diff --git a/.buildkite/ftr_oblt_serverless_configs.yml b/.buildkite/ftr_oblt_serverless_configs.yml index ee954577fc75..737add5ebccf 100644 --- a/.buildkite/ftr_oblt_serverless_configs.yml +++ b/.buildkite/ftr_oblt_serverless_configs.yml @@ -24,7 +24,10 @@ enabled: - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group4.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group5.ts - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group6.ts + - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group7.ts + - x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group8.ts - x-pack/test_serverless/functional/test_suites/observability/config.screenshots.ts + - x-pack/test_serverless/functional/test_suites/observability/config.telemetry.ts # serverless config files that run deployment-agnostic tests - x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts - x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.apm.serverless.config.ts diff --git a/.buildkite/ftr_oblt_stateful_configs.yml b/.buildkite/ftr_oblt_stateful_configs.yml index 6cad97ecc445..eed465472503 100644 --- a/.buildkite/ftr_oblt_stateful_configs.yml +++ b/.buildkite/ftr_oblt_stateful_configs.yml @@ -32,6 +32,7 @@ enabled: - x-pack/test/api_integration/apis/synthetics/config.ts - x-pack/test/api_integration/apis/uptime/config.ts - x-pack/test/api_integration/apis/entity_manager/config.ts + - x-pack/test/api_integration/apis/streams/config.ts - x-pack/test/apm_api_integration/basic/config.ts - x-pack/test/apm_api_integration/cloud/config.ts - x-pack/test/apm_api_integration/rules/config.ts diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index f55fc2f7b489..c1236a04685f 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -64,7 +64,6 @@ enabled: - test/functional/apps/dashboard/group5/config.ts - test/functional/apps/dashboard/group6/config.ts - test/functional/apps/discover/ccs_compatibility/config.ts - - test/functional/apps/discover/classic/config.ts - test/functional/apps/discover/embeddable/config.ts - test/functional/apps/discover/esql/config.ts - test/functional/apps/discover/group1/config.ts @@ -231,6 +230,7 @@ enabled: - x-pack/test/functional/apps/lens/group4/config.ts - x-pack/test/functional/apps/lens/group5/config.ts - x-pack/test/functional/apps/lens/group6/config.ts + - x-pack/test/functional/apps/lens/group7/config.ts - x-pack/test/functional/apps/lens/open_in_lens/tsvb/config.ts - x-pack/test/functional/apps/lens/open_in_lens/agg_based/config.ts - x-pack/test/functional/apps/lens/open_in_lens/dashboard/config.ts diff --git a/.buildkite/ftr_search_serverless_configs.yml b/.buildkite/ftr_search_serverless_configs.yml index e6efee586080..20f3e8165e1e 100644 --- a/.buildkite/ftr_search_serverless_configs.yml +++ b/.buildkite/ftr_search_serverless_configs.yml @@ -18,5 +18,7 @@ enabled: - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group4.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group5.ts - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group6.ts + - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group7.ts + - x-pack/test_serverless/functional/test_suites/search/common_configs/config.group8.ts # serverless config files that run deployment-agnostic tests - x-pack/test/api_integration/deployment_agnostic/configs/serverless/search.serverless.config.ts diff --git a/.buildkite/ftr_security_serverless_configs.yml b/.buildkite/ftr_security_serverless_configs.yml index 955354e2acb5..920ecce34935 100644 --- a/.buildkite/ftr_security_serverless_configs.yml +++ b/.buildkite/ftr_security_serverless_configs.yml @@ -19,6 +19,9 @@ disabled: - x-pack/test_serverless/functional/config.base.ts - x-pack/test_serverless/shared/config.base.ts + # MKI only configs files + - x-pack/test_serverless/functional/test_suites/security/config.mki_only.ts + defaultQueue: 'n2-4-spot' enabled: - x-pack/test_serverless/api_integration/test_suites/security/config.ts @@ -32,7 +35,6 @@ enabled: - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.essentials.ts - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts - - x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless_api.ts - x-pack/test_serverless/functional/test_suites/security/config.saved_objects_management.ts - x-pack/test_serverless/functional/test_suites/security/config.context_awareness.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group1.ts @@ -41,6 +43,8 @@ enabled: - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group4.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group5.ts - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group6.ts + - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group7.ts + - x-pack/test_serverless/functional/test_suites/security/common_configs/config.group8.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/actions/trial_license_complete_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/basic_license_essentials_tier/configs/serverless.config.ts - x-pack/test/security_solution_api_integration/test_suites/detections_response/detection_engine/alerts/trial_license_complete_tier/configs/serverless.config.ts diff --git a/.buildkite/package-lock.json b/.buildkite/package-lock.json index 92231d27ea50..ffec5b75fca6 100644 --- a/.buildkite/package-lock.json +++ b/.buildkite/package-lock.json @@ -22,7 +22,7 @@ "@types/mocha": "^10.0.1", "@types/node": "^15.12.2", "chai": "^4.3.10", - "mocha": "^10.3.0", + "mocha": "^10.8.2", "nock": "^12.0.2", "ts-node": "^10.9.2", "typescript": "^5.1.6" @@ -280,6 +280,15 @@ "node": ">=0.4.0" } }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -536,12 +545,12 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -590,9 +599,9 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -1042,9 +1051,9 @@ } }, "node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1053,31 +1062,31 @@ } }, "node_modules/mocha": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", - "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -1087,33 +1096,6 @@ "node": ">= 14.0.0" } }, - "node_modules/mocha/node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -1130,9 +1112,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/nock": { @@ -1567,9 +1549,9 @@ } }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "node_modules/wrap-ansi": { @@ -1622,9 +1604,9 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "engines": { "node": ">=10" @@ -1893,6 +1875,12 @@ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2090,12 +2078,12 @@ "dev": true }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "decamelize": { @@ -2124,9 +2112,9 @@ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true }, "dir-glob": { @@ -2438,62 +2426,41 @@ } }, "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "requires": { "brace-expansion": "^2.0.1" } }, "mocha": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.3.0.tgz", - "integrity": "sha512-uF2XJs+7xSLsrmIvn37i/wnc91nw7XjOQB8ccyx5aEgdnohr7n+rEiZP23WkCYHjilR6+EboEnbq/ZQDz4LSbg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "8.1.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", "serialize-javascript": "^6.0.2", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "dependencies": { "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -2506,9 +2473,9 @@ } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "nock": { @@ -2784,9 +2751,9 @@ } }, "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "wrap-ansi": { @@ -2827,9 +2794,9 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true }, "yargs-unparser": { diff --git a/.buildkite/package.json b/.buildkite/package.json index 158a55c777e6..5d5293971833 100644 --- a/.buildkite/package.json +++ b/.buildkite/package.json @@ -24,7 +24,7 @@ "@types/mocha": "^10.0.1", "@types/node": "^15.12.2", "chai": "^4.3.10", - "mocha": "^10.3.0", + "mocha": "^10.8.2", "nock": "^12.0.2", "ts-node": "^10.9.2", "typescript": "^5.1.6" diff --git a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml index bedb81cccc5a..f651a8c9e4f9 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-fips-daily.yml @@ -3,7 +3,7 @@ apiVersion: backstage.io/v1alpha1 kind: Resource metadata: name: bk-kibana-fips-daily - description: Run Kibana FIPS smoke tests + description: Run Kibana test suite with FIPS agents links: - title: Pipeline link url: https://buildkite.com/elastic/kibana-fips @@ -16,10 +16,10 @@ spec: kind: Pipeline metadata: name: kibana / fips - description: Run Kibana FIPS smoke tests + description: Run Kibana test suite with FIPS agents spec: env: - SLACK_NOTIFICATIONS_CHANNEL: '#kibana-operations-alerts' + SLACK_NOTIFICATIONS_CHANNEL: '#kibana-fips' ELASTIC_SLACK_NOTIFICATIONS_ENABLED: 'true' repository: elastic/kibana branch_configuration: main diff --git a/.buildkite/pipeline-resource-definitions/kibana-pr.yml b/.buildkite/pipeline-resource-definitions/kibana-pr.yml index 19f05ef012b0..869a3a1f3f7c 100644 --- a/.buildkite/pipeline-resource-definitions/kibana-pr.yml +++ b/.buildkite/pipeline-resource-definitions/kibana-pr.yml @@ -21,7 +21,6 @@ spec: env: ELASTIC_PR_COMMENTS_ENABLED: 'true' GITHUB_BUILD_COMMIT_STATUS_ENABLED: 'true' - GITHUB_STEP_COMMIT_STATUS_ENABLED: 'true' GITHUB_BUILD_COMMIT_STATUS_CONTEXT: kibana-ci allow_rebuilds: true branch_configuration: '' diff --git a/.buildkite/pipeline-resource-definitions/locations.yml b/.buildkite/pipeline-resource-definitions/locations.yml index c88e37490eb4..ca454f64c269 100644 --- a/.buildkite/pipeline-resource-definitions/locations.yml +++ b/.buildkite/pipeline-resource-definitions/locations.yml @@ -15,6 +15,7 @@ spec: - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-artifacts-trigger.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-chrome-forward-testing.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-codeql.yml + - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-console-definitions-sync.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-coverage-daily.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-deploy-project.yml - https://github.com/elastic/kibana/blob/main/.buildkite/pipeline-resource-definitions/kibana-es-forward-testing.yml diff --git a/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml b/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml index dce527f9e7f6..8dd486c3176c 100644 --- a/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml +++ b/.buildkite/pipeline-resource-definitions/trigger-version-dependent-jobs.yml @@ -31,6 +31,7 @@ spec: default_branch: main repository: elastic/kibana pipeline_file: .buildkite/scripts/pipelines/trigger_version_dependent_jobs/pipeline.sh + skip_intermediate_builds: false provider_settings: prefix_pull_request_fork_branch_names: false skip_pull_request_builds_for_existing_commits: true diff --git a/.buildkite/pipelines/artifacts.yml b/.buildkite/pipelines/artifacts.yml index 476507728761..49373fff910e 100644 --- a/.buildkite/pipelines/artifacts.yml +++ b/.buildkite/pipelines/artifacts.yml @@ -6,6 +6,7 @@ steps: imageProject: elastic-images-prod provider: gcp machineType: c2-standard-16 + diskSizeGb: 125 timeout_in_minutes: 120 retry: automatic: diff --git a/.buildkite/pipelines/pull_request/base.yml b/.buildkite/pipelines/pull_request/base.yml index f56159882b2a..5f7e2d265ce0 100644 --- a/.buildkite/pipelines/pull_request/base.yml +++ b/.buildkite/pipelines/pull_request/base.yml @@ -12,6 +12,7 @@ steps: agents: machineType: n2-standard-8 preemptible: true + diskSizeGb: 125 key: build if: "build.env('KIBANA_BUILD_ID') == null || build.env('KIBANA_BUILD_ID') == ''" timeout_in_minutes: 90 diff --git a/.buildkite/scripts/steps/checks/quick_checks.txt b/.buildkite/scripts/steps/checks/quick_checks.txt index 9bd922467390..7aa0f6811846 100644 --- a/.buildkite/scripts/steps/checks/quick_checks.txt +++ b/.buildkite/scripts/steps/checks/quick_checks.txt @@ -17,3 +17,4 @@ .buildkite/scripts/steps/checks/prettier_topology.sh .buildkite/scripts/steps/checks/renovate.sh .buildkite/scripts/steps/checks/native_modules.sh +.buildkite/scripts/steps/checks/test_files_missing_owner.sh diff --git a/.buildkite/scripts/steps/checks/test_files_missing_owner.sh b/.buildkite/scripts/steps/checks/test_files_missing_owner.sh new file mode 100755 index 000000000000..4dfec4e18ab6 --- /dev/null +++ b/.buildkite/scripts/steps/checks/test_files_missing_owner.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source .buildkite/scripts/common/util.sh + +echo --- Check for Test Files missing an owner +node scripts/check_ftr_code_owners diff --git a/.buildkite/scripts/steps/console_definitions_sync.sh b/.buildkite/scripts/steps/console_definitions_sync.sh index 55719292959e..7dc565e0b964 100755 --- a/.buildkite/scripts/steps/console_definitions_sync.sh +++ b/.buildkite/scripts/steps/console_definitions_sync.sh @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -euo pipefail +GIT_SCOPE="src/plugins/console/server/lib/spec_definitions" + report_main_step () { echo "--- $1" } @@ -16,14 +18,16 @@ main () { exit 1 fi + report_main_step "Bootstrapping Kibana" cd "$KIBANA_DIR" + .buildkite/scripts/bootstrap.sh report_main_step "Generating console definitions" node scripts/generate_console_definitions.js --source "$PARENT_DIR/elasticsearch-specification" --emptyDest # Check if there are any differences set +e - git diff --exit-code --quiet "$destination_file" + git diff --exit-code --quiet "$GIT_SCOPE" if [ $? -eq 0 ]; then echo "No differences found. Exiting.." exit @@ -54,7 +58,7 @@ main () { git checkout -b "$BRANCH_NAME" - git add src/plugins/console/server/lib/spec_definitions/json/generated/* + git add $GIT_SCOPE git commit -m "Update console definitions" report_main_step "Changes committed. Creating pull request." diff --git a/.eslintrc.js b/.eslintrc.js index e2d02c33288a..226017e524d8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -952,6 +952,7 @@ module.exports = { { files: [ 'x-pack/plugins/observability_solution/**/*.{ts,tsx}', + 'x-pack/plugins/{streams,streams_app}/**/*.{ts,tsx}', 'x-pack/packages/observability/**/*.{ts,tsx}', ], rules: { @@ -959,7 +960,7 @@ module.exports = { 'error', { additionalHooks: - '^(useAbortableAsync|useMemoWithAbortSignal|useFetcher|useProgressiveFetcher|useBreadcrumb|useAsync|useTimeRangeAsync|useAutoAbortedHttpClient)$', + '^(useAbortableAsync|useMemoWithAbortSignal|useFetcher|useProgressiveFetcher|useBreadcrumb|useAsync|useTimeRangeAsync|useAutoAbortedHttpClient|use.*Fetch)$', }, ], }, @@ -968,6 +969,7 @@ module.exports = { files: [ 'x-pack/plugins/aiops/**/*.tsx', 'x-pack/plugins/observability_solution/**/*.tsx', + 'x-pack/plugins/{streams,streams_app}/**/*.{ts,tsx}', 'src/plugins/ai_assistant_management/**/*.tsx', 'x-pack/packages/observability/**/*.{ts,tsx}', ], @@ -984,6 +986,7 @@ module.exports = { { files: [ 'x-pack/plugins/observability_solution/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/{streams,streams_app}/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', 'src/plugins/ai_assistant_management/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', 'x-pack/packages/observability/logs_overview/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', ], @@ -2015,6 +2018,22 @@ module.exports = { '@kbn/imports/no_group_crossing_imports': 'warn', }, }, + { + files: ['packages/kbn-dependency-usage/**/*.{ts,tsx}'], + rules: { + // disabling it since package is a CLI tool + 'no-console': 'off', + // disabling it since package is marked as module and it requires extension for files written + '@kbn/imports/uniform_imports': 'off', + }, + }, + { + files: ['packages/kbn-dependency-ownership/**/*.{ts,tsx}'], + rules: { + // disabling it since package is a CLI tool + 'no-console': 'off', + }, + }, ], }; diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 46f771371a3c..f5c2ed37db76 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -329,6 +329,8 @@ packages/kbn-data-service @elastic/kibana-visualizations @elastic/kibana-data-di packages/kbn-data-stream-adapter @elastic/security-threat-hunting packages/kbn-data-view-utils @elastic/kibana-data-discovery packages/kbn-datemath @elastic/kibana-data-discovery +packages/kbn-dependency-ownership @elastic/kibana-security +packages/kbn-dependency-usage @elastic/kibana-security packages/kbn-dev-cli-errors @elastic/kibana-operations packages/kbn-dev-cli-runner @elastic/kibana-operations packages/kbn-dev-proc-runner @elastic/kibana-operations @@ -465,6 +467,8 @@ packages/kbn-rrule @elastic/response-ops packages/kbn-rule-data-utils @elastic/security-detections-response @elastic/response-ops @elastic/obs-ux-management-team packages/kbn-safer-lodash-set @elastic/kibana-security packages/kbn-saved-objects-settings @elastic/appex-sharedux +packages/kbn-saved-search-component @elastic/obs-ux-logs-team +packages/kbn-scout @elastic/appex-qa packages/kbn-screenshotting-server @elastic/appex-sharedux packages/kbn-search-api-keys-components @elastic/search-kibana packages/kbn-search-api-keys-server @elastic/search-kibana @@ -618,7 +622,7 @@ packages/shared-ux/storybook/mock @elastic/appex-sharedux packages/shared-ux/table_persist @elastic/appex-sharedux src/core @elastic/kibana-core src/plugins/advanced_settings @elastic/appex-sharedux @elastic/kibana-management -src/plugins/ai_assistant_management/selection @elastic/obs-knowledge-team +src/plugins/ai_assistant_management/selection @elastic/obs-ai-assistant src/plugins/bfetch @elastic/appex-sharedux src/plugins/chart_expressions/common @elastic/kibana-visualizations src/plugins/chart_expressions/expression_gauge @elastic/kibana-visualizations @@ -863,6 +867,7 @@ x-pack/plugins/ai_infra/llm_tasks @elastic/appex-ai-infra x-pack/plugins/ai_infra/product_doc_base @elastic/appex-ai-infra x-pack/plugins/aiops @elastic/ml-ui x-pack/plugins/alerting @elastic/response-ops +x-pack/plugins/asset_inventory @elastic/kibana-cloud-security-posture x-pack/plugins/banners @elastic/appex-sharedux x-pack/plugins/canvas @elastic/kibana-presentation x-pack/plugins/cases @elastic/response-ops @@ -916,7 +921,7 @@ x-pack/plugins/monitoring @elastic/stack-monitoring x-pack/plugins/monitoring_collection @elastic/stack-monitoring x-pack/plugins/notifications @elastic/appex-sharedux x-pack/plugins/observability_solution/apm @elastic/obs-ux-infra_services-team -x-pack/plugins/observability_solution/apm_data_access @elastic/obs-knowledge-team @elastic/obs-ux-infra_services-team +x-pack/plugins/observability_solution/apm_data_access @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/apm/ftr_e2e @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/dataset_quality @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/entities_data_access @elastic/obs-entities @@ -927,10 +932,10 @@ x-pack/plugins/observability_solution/inventory @elastic/obs-ux-infra_services-t x-pack/plugins/observability_solution/inventory/e2e @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/investigate @elastic/obs-ux-management-team x-pack/plugins/observability_solution/investigate_app @elastic/obs-ux-management-team -x-pack/plugins/observability_solution/logs_data_access @elastic/obs-knowledge-team @elastic/obs-ux-logs-team +x-pack/plugins/observability_solution/logs_data_access @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/logs_explorer @elastic/obs-ux-logs-team x-pack/plugins/observability_solution/logs_shared @elastic/obs-ux-logs-team -x-pack/plugins/observability_solution/metrics_data_access @elastic/obs-knowledge-team @elastic/obs-ux-infra_services-team +x-pack/plugins/observability_solution/metrics_data_access @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/observability @elastic/obs-ux-management-team x-pack/plugins/observability_solution/observability_ai_assistant @elastic/obs-ai-assistant x-pack/plugins/observability_solution/observability_ai_assistant_app @elastic/obs-ai-assistant @@ -977,6 +982,7 @@ x-pack/plugins/spaces @elastic/kibana-security x-pack/plugins/stack_alerts @elastic/response-ops x-pack/plugins/stack_connectors @elastic/response-ops x-pack/plugins/streams @simianhacker @flash1293 @dgieselaar +x-pack/plugins/streams_app @simianhacker @flash1293 @dgieselaar x-pack/plugins/task_manager @elastic/response-ops x-pack/plugins/telemetry_collection_xpack @elastic/kibana-core x-pack/plugins/threat_intelligence @elastic/security-threat-hunting-investigations @@ -1047,6 +1053,25 @@ x-pack/test_serverless/api_integration/test_suites/common/platform_security @ela # Data Discovery +/x-pack/test/api_integration/services/data_view_api.ts @elastic/kibana-data-discovery +/test/functional/fixtures/es_archiver/makelogs @elastic/kibana-data-discovery +/test/functional/fixtures/es_archiver/large_fields @elastic/kibana-data-discovery # Assigned per only use: test/functional/apps/management/data_views/_test_huge_fields.ts +/x-pack/test/functional/fixtures/kbn_archiver/kibana_scripted_fields_on_logstash.json @elastic/kibana-data-discovery # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/functional/apps/discover/async_scripted_fields.ts#L35 +/x-pack/test/functional/fixtures/kbn_archiver/discover @elastic/kibana-data-discovery +/test/functional/fixtures/kbn_archiver/unmapped_fields.json @elastic/kibana-data-discovery # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/discover/group7/_indexpattern_with_unmapped_fields.ts#L28 +/test/functional/fixtures/kbn_archiver/testlargestring.json @elastic/kibana-data-discovery # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/discover/group5/_large_string.ts#L28 +/test/functional/fixtures/kbn_archiver/message_with_newline.json @elastic/kibana-data-discovery # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/discover/classic/_doc_table_newline.ts#L26 +/test/functional/fixtures/kbn_archiver/invalid_scripted_field.json @elastic/kibana-data-discovery +/test/functional/fixtures/kbn_archiver/index_pattern_without_timefield.json @elastic/kibana-data-discovery +/test/functional/fixtures/kbn_archiver/discover @elastic/kibana-data-discovery +/test/functional/fixtures/kbn_archiver/discover.json @elastic/kibana-data-discovery +/test/functional/fixtures/kbn_archiver/date_nested.json @elastic/kibana-data-discovery +/test/functional/fixtures/kbn_archiver/date_* @elastic/kibana-data-discovery +/test/functional/fixtures/es_archiver/unmapped_fields @elastic/kibana-data-discovery # Assigned per the only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/discover/group7/_indexpattern_with_unmapped_fields.ts#L26 +/test/functional/fixtures/es_archiver/message_with_newline @elastic/kibana-data-discovery # Assigned per the only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/discover/classic/_doc_table_newline.ts#L24 +/test/functional/fixtures/es_archiver/hamlet @elastic/kibana-data-discovery # Assigned per the only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/discover/group5/_large_string.ts#L30 +/test/api_integration/fixtures/kbn_archiver/index_patterns @elastic/kibana-data-discovery +/test/api_integration/fixtures/es_archiver/index_patterns @elastic/kibana-data-discovery /test/functional/fixtures/es_archiver/alias @elastic/kibana-data-discovery /test/functional/page_objects/context_page.ts @elastic/kibana-data-discovery /test/functional/services/data_views.ts @elastic/kibana-data-discovery @@ -1112,6 +1137,7 @@ x-pack/test_serverless/api_integration/test_suites/common/platform_security @ela /x-pack/test_serverless/functional/test_suites/common/examples/unified_field_list_examples @elastic/kibana-data-discovery /x-pack/test_serverless/functional/test_suites/common/management/data_views @elastic/kibana-data-discovery src/plugins/discover/public/context_awareness/profile_providers/security @elastic/kibana-data-discovery @elastic/security-threat-hunting-investigations +src/plugins/discover/public/context_awareness/profile_providers/observability @elastic/kibana-data-discovery @elastic/obs-ux-logs-team # Platform Docs /x-pack/test_serverless/functional/test_suites/security/screenshot_creation/index.ts @elastic/platform-docs @@ -1119,6 +1145,16 @@ src/plugins/discover/public/context_awareness/profile_providers/security @elasti /x-pack/test/screenshot_creation @elastic/platform-docs # Visualizations +/x-pack/test/functional/fixtures/kbn_archiver/rollup @elastic/kibana-visualizations # Assigned per the only uses are in lens and tsvb tests +/x-pack/test/functional/fixtures/kbn_archiver/hybrid_dataview.json @elastic/kibana-visualizations # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/functional/apps/visualize/hybrid_visualization.ts#L20 +/x-pack/test/functional/es_archives/pre_calculated_histogram @elastic/kibana-visualizations # Assigned per usages +/x-pack/test/functional/es_archives/hybrid/rollup @elastic/kibana-visualizations @elastic/search-kibana # Assigned per usage +/x-pack/test/functional/es_archives/hybrid/logstash @elastic/kibana-visualizations # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/functional/apps/visualize/hybrid_visualization.ts#L22 +/x-pack/test/functional/es_archives/graph @elastic/kibana-visualizations +/x-pack/test/functional/es_archives/visualize @elastic/kibana-visualizations +/test/functional/fixtures/kbn_archiver/visualize.json @elastic/kibana-visualizations +/test/functional/fixtures/kbn_archiver/managed_content.json @elastic/kibana-visualizations # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/functional/apps/managed_content/managed_content.ts#L38 +/test/api_integration/fixtures/kbn_archiver/event_annotations/event_annotations.json @elastic/kibana-visualizations /test/functional/page_objects/unified_search_page.ts @elastic/kibana-visualizations # Assigned per https://github.com/elastic/kibana/pull/200132#discussion_r1847188168 /test/functional/apps/getting_started/*.ts @elastic/kibana-visualizations # Assigned per https://github.com/elastic/kibana/pull/199767#discussion_r1840485031 /x-pack/test/upgrade/apps/graph @elastic/kibana-visualizations @@ -1202,17 +1238,19 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql # Observability UI +/x-pack/test/api_integration/apis/streams @elastic/observability-ui # Assigned per https://github.com/elastic/kibana/pull/201293 /x-pack/test_serverless/api_integration/test_suites/observability/config.ts @elastic/observability-ui @elastic/appex-qa /x-pack/test_serverless/api_integration/test_suites/observability/index.ts @elastic/observability-ui ### Observability Plugins # Observability AI Assistant -/x-pack/test_serverless/api_integration/test_suites/common/data_usage @elastic/obs-ai-assistant -/x-pack/test_serverless/functional/test_suites/common/data_usage @elastic/obs-ai-assistant @elastic/kibana-security +/x-pack/test_serverless/api_integration/test_suites/common/data_usage @elastic/obs-ai-assistant @elastic/security-solution +/x-pack/test_serverless/functional/test_suites/common/data_usage @elastic/obs-ai-assistant @elastic/security-solution /x-pack/test/observability_ai_assistant_api_integration @elastic/obs-ai-assistant /x-pack/test/observability_ai_assistant_functional @elastic/obs-ai-assistant /x-pack/test_serverless/**/test_suites/observability/ai_assistant @elastic/obs-ai-assistant +/x-pack/test/functional/es_archives/observability/ai_assistant @elastic/obs-ai-assistant # Infra Obs ## This plugin mostly contains the codebase for the infra services, but also includes some code for the Logs UI app. @@ -1252,6 +1290,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/plugins/observability_solution/infra/server/services @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/server/usage @elastic/obs-ux-infra_services-team /x-pack/plugins/observability_solution/infra/server/utils @elastic/obs-ux-infra_services-team +/x-pack/test_serverless/functional/test_suites/observability/infra @elastic/obs-ux-infra_services-team /x-pack/test/api_integration/services/infraops_source_configuration.ts @elastic/obs-ux-infra_services-team @elastic/obs-ux-logs-team # Assigned per https://github.com/elastic/kibana/pull/34916 ## Logs UI code exceptions -> @elastic/obs-ux-logs-team @@ -1288,7 +1327,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/test/functional/apps/infra/logs @elastic/obs-ux-logs-team # Observability UX management team -/x-pack/test/api_integration/services/data_view_api.ts @elastic/obs-ux-management-team +/test/api_integration/apis/suggestions @elastic/obs-ux-management-team # Assigned per https://github.com/elastic/kibana/pull/200950#discussion_r1853705079 /x-pack/test/api_integration/services/slo.ts @elastic/obs-ux-management-team /x-pack/test/functional/services/slo @elastic/obs-ux-management-team /x-pack/test/functional/apps/slo @elastic/obs-ux-management-team @@ -1321,6 +1360,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/test/accessibility/apps/group3/stack_monitoring.ts @elastic/stack-monitoring # Fleet +/x-pack/test/common/services/ingest_manager.ts @elastic/fleet # Assigned per https://github.com/elastic/kibana/pull/201648#discussion_r1859018893 /x-pack/test/functional/es_archives/fleet @elastic/fleet /x-pack/test/api_integration/services/fleet_and_agents.ts @elastic/fleet /x-pack/test/fleet_api_integration @elastic/fleet @@ -1358,6 +1398,8 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/test_serverless/api_integration/test_suites/observability/synthetics @elastic/obs-ux-management-team # obs-ux-logs-team +/x-pack/test/functional/es_archives/observability_logs_explorer @elastic/obs-ux-logs-team +/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/test_suites/observability/config.* @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/test_suites/observability/landing_page.ts @elastic/obs-ux-logs-team /x-pack/test_serverless/functional/test_suites/observability/navigation.ts @elastic/obs-ux-logs-team @@ -1398,6 +1440,11 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql ### END Observability Plugins # Presentation +/test/functional/fixtures/kbn_archiver/dashboard_error_cases.json @elastic/kibana-presentation # Assigned per https://github.com/elastic/kibana/pull/201648#discussion_r1859020986 +/x-pack/test/functional/es_archives/getting_started/shakespeare @elastic/kibana-presentation # Assigned per https://github.com/elastic/kibana/pull/201648#discussion_r1860319853 +/x-pack/test/upgrade/screenshots @elastic/kibana-presentation +/x-pack/test/functional/screenshots @elastic/kibana-presentation +/test/functional/fixtures/kbn_archiver/legacy.json @elastic/kibana-presentation # Assigned per https://github.com/elastic/kibana/pull/200934#discussion_r1856407606 /x-pack/test/functional/fixtures/kbn_archiver/maps.json @elastic/kibana-presentation /x-pack/test/functional/fixtures/kbn_archiver/canvas @elastic/kibana-presentation /x-pack/test/functional/es_archives/dashboard/async_search @elastic/kibana-presentation @@ -1480,6 +1527,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/test/api_integration/services/transform.ts @elastic/ml-ui /x-pack/test/functional/apps/aiops @elastic/ml-ui /x-pack/test/functional/apps/transform/ @elastic/ml-ui +/x-pack/test/functional/es_archives/large_arrays @elastic/ml-ui # Assigned per usages /x-pack/test/functional/services/transform/ @elastic/ml-ui /x-pack/test/functional/services/aiops @elastic/ml-ui /x-pack/test/functional_basic/apps/transform/ @elastic/ml-ui @@ -1516,6 +1564,7 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /.eslintignore @elastic/kibana-operations # QA - Appex QA +/x-pack/plugins/discover_enhanced/ui_tests/ @elastic/appex-qa # temporarily /x-pack/test/functional/fixtures/package_registry_config.yml @elastic/appex-qa # No usages found /x-pack/test/functional/fixtures/kbn_archiver/packaging.json @elastic/appex-qa # No usages found /x-pack/test/functional/es_archives/filebeat @elastic/appex-qa @@ -1662,6 +1711,16 @@ packages/kbn-monaco/src/esql @elastic/kibana-esql /x-pack/test/api_integration/deployment_agnostic/services/ @elastic/appex-qa # Core +/test/api_integration/fixtures/kbn_archiver/management/saved_objects/relationships.json @elastic/kibana-core @elastic/kibana-data-discovery +/x-pack/test/functional/es_archives/lists @elastic/kibana-core +/test/functional/fixtures/kbn_archiver/saved_search.json @elastic/kibana-core # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/interpreter_functional/test_suites/run_pipeline/esaggs.ts#L100 +/test/functional/fixtures/kbn_archiver/saved_objects_management/show_relationships.json @elastic/kibana-core # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/saved_objects_management/show_relationships.ts#L20 +/test/functional/fixtures/kbn_archiver/saved_objects_management/hidden_from_http_apis.json @elastic/kibana-core +/test/functional/fixtures/kbn_archiver/saved_objects_management/edit_saved_object.json @elastic/kibana-core # Assigned per only use: https://github.com/elastic/kibana/blob/main/test/functional/apps/saved_objects_management/inspect_saved_objects.ts#L40 +/test/functional/fixtures/es_archiver/saved_objects_management @elastic/kibana-core +/test/api_integration/fixtures/es_archiver/saved_objects @elastic/kibana-core +/test/api_integration/fixtures/kbn_archiver/saved_objects @elastic/kibana-core +/test/interpreter_functional @elastic/kibana-core # Assigned per https://github.com/elastic/kibana/blob/main/test/interpreter_functional/plugins/kbn_tp_run_pipeline/kibana.jsonc#L4 /test/api_integration/apis/general/*.js @elastic/kibana-core # Assigned per https://github.com/elastic/kibana/pull/199795/files/894a8ede3f9d0398c5af56bf5a82654a9bc0610b#r1846691639 /x-pack/test/plugin_api_integration/plugins/feature_usage_test @elastic/kibana-core /x-pack/test/functional/page_objects/navigational_search.ts @elastic/kibana-core @@ -1779,6 +1838,15 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib # Kibana Platform Security # security +/x-pack/test/functional/es_archives/security @elastic/kibana-security +/x-pack/test/functional/fixtures/kbn_archiver/spaces @elastic/kibana-security +/x-pack/test/functional/fixtures/kbn_archiver/security @elastic/kibana-security +/x-pack/test/ftr_apis/common/lib @elastic/kibana-security +/x-pack/test/ftr_apis/common/fixtures/es_archiver/base_data/space_1.json @elastic/kibana-security # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/ftr_apis/security_and_spaces/apis/test_utils.ts#L33 +/x-pack/test/ftr_apis/common/fixtures/es_archiver/base_data/default_space.json @elastic/kibana-security # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/ftr_apis/security_and_spaces/apis/test_utils.ts#L33 +/x-pack/test/api_integration/apis/cloud @elastic/kibana-security # Assigned per https://github.com/elastic/kibana/pull/198444 +/test/plugin_functional/snapshots/baseline/hardening/prototype.json @elastic/kibana-security # Assigned per https://github.com/elastic/kibana/pull/190716 +/test/functional/page_objects/login_page.ts @elastic/kibana-security /x-pack/test_serverless/functional/test_suites/observability/role_management @elastic/kibana-security /x-pack/test/functional/config_security_basic.ts @elastic/kibana-security /x-pack/test/functional/page_objects/user_profile_page.ts @elastic/kibana-security @@ -1905,6 +1973,12 @@ x-pack/plugins/cloud_integrations/cloud_full_story/server/config.ts @elastic/kib # Enterprise Search # search +/x-pack/test/functional/es_archives/data/search_sessions @elastic/search-kibana +/x-pack/test/common/services/search_secure.ts @elastic/search-kibana +/test/functional/page_objects/unified_search_page.ts @elastic/search-kibana +/test/functional/fixtures/kbn_archiver/ccs @elastic/search-kibana +/test/functional/fixtures/kbn_archiver/annotation_listing_page_search.json @elastic/search-kibana +/test/functional/fixtures/es_archiver/search/downsampled @elastic/search-kibana /x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts @elastic/search-kibana /x-pack/test/functional/services/search_sessions.ts @elastic/search-kibana /x-pack/test/functional/page_objects/search_* @elastic/search-kibana @@ -1925,6 +1999,9 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/test/functional_search/ @elastic/search-kibana # Management Experience - Deployment Management +/test/functional/fixtures/kbn_archiver/management.json @elastic/kibana-management @elastic/kibana-data-discovery # Assigned per 2 uses: test/functional/apps/management/_import_objects.ts && test/functional/apps/management/data_views/_scripted_fields_filter.ts +/x-pack/test/functional/fixtures/kbn_archiver/home/feature_controls/security/security.json @elastic/kibana-management +/x-pack/test/functional/es_archives/upgrade_assistant @elastic/kibana-management /x-pack/test/functional/services/ace_editor.js @elastic/kibana-management /x-pack/test/functional/page_objects/remote_clusters_page.ts @elastic/kibana-management /x-pack/test/stack_functional_integration/apps/ccs @elastic/kibana-management @@ -2013,6 +2090,11 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints #CC# /x-pack/plugins/cross_cluster_replication/ @elastic/kibana-management # Security Solution +/x-pack/test/functional/fixtures/kbn_archiver/security_solution/timelines/7.15.0_space @elastic/security-solution # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/security_solution_api_integration/test_suites/investigation/timeline/tests/timeline_migrations.ts#L58 +/x-pack/test/functional/es_archives/packetbeat @elastic/security-solution +/x-pack/test/common/services/ingest_manager.ts @elastic/security-solution # Assigned per blame +/x-pack/test/security_solution_ftr @elastic/security-solution +/x-pack/test/functional/es_archives/security_solution @elastic/security-solution /x-pack/test/functional/es_archives/rule_exceptions @elastic/security-solution # Assigned per https://github.com/elastic/kibana/pull/199795/files/ae80bb252bc71f787c122849fcb9b01e386fc5e9#r1840233040 /x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts @elastic/security-solution /x-pack/test/common/utils/security_solution/index.ts @elastic/security-solution @@ -2021,7 +2103,9 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/test/api_integration/services/security_solution_*.gen.ts @elastic/security-solution /x-pack/test/accessibility/apps/group3/security_solution.ts @elastic/security-solution /x-pack/test_serverless/functional/test_suites/security/config.ts @elastic/security-solution @elastic/appex-qa -/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts @elastic/security-solution +x-pack/test_serverless/functional/test_suites/security/config.mki_only.ts @elastic/security-solution @elastic/appex-qa +x-pack/test_serverless/functional/test_suites/security/index.mki_only.ts @elastic/security-solution @elastic/appex-qa @elastic/kibana-cloud-security-posture +/x-pack/test_serverless/functional/test_suites/security/config.feature_flags.ts @elastic/security-solution @elastic/kibana-cloud-security-posture /x-pack/test_serverless/api_integration/test_suites/observability/config.feature_flags.ts @elastic/security-solution /x-pack/test_serverless/functional/test_suites/common/spaces/multiple_spaces_enabled.ts @elastic/security-solution /x-pack/test/functional/es_archives/endpoint/ @elastic/security-solution @@ -2052,11 +2136,15 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints # TODO: assign sub directories to sub teams /x-pack/plugins/security_solution_ess/ @elastic/security-solution /x-pack/plugins/security_solution_serverless/ @elastic/security-solution +/x-pack/plugins/security_solution/public/app/404.tsx @elastic/security-solution +/x-pack/plugins/security_solution/public/app/app.tsx @elastic/security-solution +/x-pack/plugins/security_solution/public/app/home @elastic/security-solution # GenAI in Security Solution /x-pack/plugins/security_solution/public/assistant @elastic/security-generative-ai /x-pack/plugins/security_solution/public/attack_discovery @elastic/security-generative-ai /x-pack/test/security_solution_cypress/cypress/e2e/ai_assistant @elastic/security-generative-ai +/x-pack/plugins/security_solution_ess/public/upselling/pages/attack_discovery @elastic/security-generative-ai # Security Solution cross teams ownership /x-pack/test/security_solution_cypress/cypress/fixtures @elastic/security-detections-response @elastic/security-threat-hunting @@ -2072,6 +2160,8 @@ x-pack/test/api_integration/apis/management/index_management/inference_endpoints /x-pack/plugins/security_solution/public/common/components/callouts @elastic/security-detections-response /x-pack/plugins/security_solution/public/common/components/hover_actions @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/formatted_date/index.tsx @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/formatted_number/index.tsx @elastic/security-threat-hunting-explore @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/server/routes @elastic/security-detections-response @elastic/security-threat-hunting /x-pack/plugins/security_solution/server/utils @elastic/security-detections-response @elastic/security-threat-hunting @@ -2082,6 +2172,8 @@ x-pack/test/security_solution_api_integration/test_suites/explore @elastic/secur x-pack/test/security_solution_api_integration/test_suites/investigations @elastic/security-threat-hunting-investigations x-pack/test/security_solution_api_integration/test_suites/sources @elastic/security-detections-response /x-pack/test/common/utils/security_solution/detections_response @elastic/security-detections-response +/x-pack/test/functional/es_archives/signals @elastic/security-detections-response +/x-pack/test/functional/es_archives/rule_keyword_family @elastic/security-detections-response # Security Solution sub teams @@ -2100,6 +2192,7 @@ x-pack/test/security_solution_api_integration/test_suites/sources @elastic/secur /x-pack/plugins/security_solution/server/lib/siem_migrations @elastic/security-threat-hunting /x-pack/plugins/security_solution/common/siem_migrations @elastic/security-threat-hunting /x-pack/plugins/security_solution/public/siem_migrations @elastic/security-threat-hunting +/x-pack/plugins/security_solution/public/common/components/control_columns @elastic/security-threat-hunting ## Security Solution Threat Hunting areas - Threat Hunting Investigations @@ -2128,6 +2221,21 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/resolver @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/threat_intelligence @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/timelines @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/header_actions @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/common/types/header_actions @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/flyout/network_details @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/flyout/rule_details @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/investigations @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/detections/configurations/security_solution_detections @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/detections/pages/detection_engine/detection_engine.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/hooks/use_resolve_conflict.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/drag_and_drop @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/draggables @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/events_tab @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution_serverless/public/upselling/pages/threat_intelligence_paywall.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/mock/mock_timeline_control_columns.tsx @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/common/components/exit_full_screen @elastic/security-threat-hunting-investigations +/x-pack/plugins/security_solution/public/app/home/template_wrapper/timeline @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/server/lib/timeline @elastic/security-threat-hunting-investigations @@ -2145,6 +2253,13 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/test/security_solution_cypress/cypress/tasks/network @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/app/actions @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/assets @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/app/solution_navigation/links @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/lib/clipboard @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/visualization_actions @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/accessibility @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/first_last_seen/first_last_seen.tsx @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/alert_count_by_status @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/common/components/guided_onboarding_tour @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/common/components/charts @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/detections/components/alerts_table/grouping_settings @elastic/security-threat-hunting-explore @@ -2168,7 +2283,10 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/explore @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/overview @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/public/dashboards @elastic/security-threat-hunting-explore - +/x-pack/plugins/security_solution/public/onboarding @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/empty_page @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution/public/common/components/empty_prompt @elastic/security-threat-hunting-explore +/x-pack/plugins/security_solution_serverless/public/components/dashboards_landing_callout @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/matrix_histogram @elastic/security-threat-hunting-explore /x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/network @elastic/security-threat-hunting-explore @@ -2240,6 +2358,7 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/plugins/security_solution/public/detections/mitre @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules @elastic/security-detection-rule-management /x-pack/plugins/security_solution/public/rules @elastic/security-detection-rule-management +/x-pack/plugins/security_solution/public/common/components/toolbar/bulk_actions @elastic/security-detection-rule-management /x-pack/plugins/security_solution/server/lib/detection_engine/fleet_integrations @elastic/security-detection-rule-management /x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules @elastic/security-detection-rule-management @@ -2262,6 +2381,8 @@ x-pack/test/security_solution_cypress/cypress/tasks/expandable_flyout @elastic/ /x-pack/test/functional/es_archives/entity/risks @elastic/security-detection-engine /x-pack/test/functional/es_archives/entity/host_risk @elastic/security-detection-engine /x-pack/test/api_integration/apis/lists @elastic/security-detection-engine +/x-pack/plugins/security_solution/public/value_list @elastic/security-detection-engine +/x-pack/plugins/security_solution/public/detections/components/value_lists_management_flyout @elastic/security-detection-engine /x-pack/plugins/security_solution/public/sourcerer @elastic/security-threat-hunting-investigations /x-pack/plugins/security_solution/public/detection_engine/rule_creation @elastic/security-detection-engine @@ -2317,15 +2438,13 @@ x-pack/packages/kbn-elastic-assistant-common/impl/schemas/defend_insights @elast x-pack/plugins/elastic_assistant/server/__mocks__/defend_insights_schema.mock.ts @elastic/security-defend-workflows x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/defend_insights @elastic/security-defend-workflows x-pack/plugins/elastic_assistant/server/routes/defend_insights @elastic/security-defend-workflows +/x-pack/plugins/security_solution/public/common/components/response_actions @elastic/security-defend-workflows +/x-pack/plugins/security_solution_serverless/public/upselling/pages/osquery_automated_response_actions.tsx @elastic/security-defend-workflows ## Security Solution sub teams - security-telemetry (Data Engineering) x-pack/plugins/security_solution/server/usage/ @elastic/security-data-analytics x-pack/plugins/security_solution/server/lib/telemetry/ @elastic/security-data-analytics -## Security Solution sub teams - adaptive-workload-protection -x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/kibana-cloud-security-posture -x-pack/plugins/security_solution/public/kubernetes @elastic/kibana-cloud-security-posture - ## Security Solution sub teams - Entity Analytics x-pack/plugins/security_solution/common/entity_analytics @elastic/security-entity-analytics x-pack/plugins/security_solution/common/search_strategy/security_solution/risk_score @elastic/security-entity-analytics @@ -2341,37 +2460,50 @@ x-pack/plugins/security_solution/common/api/entity_analytics @elastic/security-e x-pack/test/security_solution_api_integration/test_suites/genai @elastic/security-generative-ai # Security Defend Workflows - OSQuery Ownership -x-pack/plugins/osquery @elastic/security-defend-workflows +/x-pack/test/osquery_cypress @elastic/security-defend-workflows +/x-pack/plugins/osquery @elastic/security-defend-workflows /x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/detection_engine/rule_response_actions @elastic/security-defend-workflows /x-pack/plugins/security_solution/server/lib/detection_engine/rule_response_actions @elastic/security-defend-workflows /x-pack/plugins/security_solution/public/detections/components/osquery @elastic/security-defend-workflows -# Cloud Defend -/x-pack/plugins/security_solution/public/cloud_defend @elastic/kibana-cloud-security-posture - -# Cloud Security Posture -/x-pack/test/functional/es_archives/kubernetes_security @elastic/kibana-cloud-security-posture -/x-pack/test/functional/es_archives/session_view @elastic/kibana-cloud-security-posture -/x-pack/test/session_view @elastic/kibana-cloud-security-posture # Assigned per https://github.com/elastic/kibana/blob/main/api_docs/session_view.mdx#L18 -/x-pack/packages/kbn-cloud-security-posture @elastic/kibana-cloud-security-posture -/x-pack/test/kubernetes_security @elastic/kibana-cloud-security-posture -/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.* @elastic/kibana-cloud-security-posture -/x-pack/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture -/x-pack/test/api_integration/apis/cloud_security_posture/ @elastic/kibana-cloud-security-posture -/x-pack/test/cloud_security_posture_functional/ @elastic/kibana-cloud-security-posture -/x-pack/test/cloud_security_posture_api/ @elastic/kibana-cloud-security-posture -/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/ @elastic/kibana-cloud-security-posture -/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.basic.ts @elastic/kibana-cloud-security-posture -/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.essentials.ts @elastic/kibana-cloud-security-posture -/x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/ @elastic/kibana-cloud-security-posture -/x-pack/plugins/fleet/public/components/cloud_security_posture @elastic/fleet @elastic/kibana-cloud-security-posture -/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/cloud_security_posture @elastic/fleet @elastic/kibana-cloud-security-posture -/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.* @elastic/fleet @elastic/kibana-cloud-security-posture -/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/components/cloud_posture_third_party_support_callout.* @elastic/fleet @elastic/kibana-cloud-security-posture -/x-pack/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture -/x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/misconfiguration_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture -/x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/vulnerabilities_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture +# Cloud Security Posture team + +## Packages +x-pack/packages/kbn-cloud-security-posture @elastic/kibana-cloud-security-posture +x-pack/packages/security-solution/distribution_bar @elastic/kibana-cloud-security-posture +## Plugins +x-pack/plugins/cloud_defend @elastic/kibana-cloud-security-posture +x-pack/plugins/cloud_security_posture @elastic/kibana-cloud-security-posture +x-pack/plugins/kubernetes_security @elastic/kibana-cloud-security-posture +x-pack/plugins/session_view @elastic/kibana-cloud-security-posture +## Security Solution sub teams +x-pack/plugins/security_solution/public/common/components/sessions_viewer @elastic/kibana-cloud-security-posture +x-pack/plugins/security_solution/public/cloud_defend @elastic/kibana-cloud-security-posture +x-pack/plugins/security_solution/public/cloud_security_posture @elastic/kibana-cloud-security-posture +x-pack/plugins/security_solution/public/kubernetes @elastic/kibana-cloud-security-posture +## Fleet plugin (co-owned with Fleet team) +x-pack/plugins/fleet/public/components/cloud_security_posture @elastic/fleet @elastic/kibana-cloud-security-posture +x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/components/cloud_security_posture @elastic/fleet @elastic/kibana-cloud-security-posture +x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.* @elastic/fleet @elastic/kibana-cloud-security-posture +x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/components/cloud_posture_third_party_support_callout.* @elastic/fleet @elastic/kibana-cloud-security-posture +## Kubernetes Security tests +x-pack/test/functional/es_archives/kubernetes_security @elastic/kibana-cloud-security-posture +x-pack/test/kubernetes_security @elastic/kibana-cloud-security-posture +## SessionView tests +x-pack/test/functional/es_archives/session_view @elastic/kibana-cloud-security-posture +x-pack/test/session_view @elastic/kibana-cloud-security-posture # Assigned per https://github.com/elastic/kibana/blob/main/api_docs/session_view.mdx#L18 +## CSP tests +x-pack/test/api_integration/apis/cloud_security_posture/ @elastic/kibana-cloud-security-posture +x-pack/test/cloud_security_posture_functional/ @elastic/kibana-cloud-security-posture +x-pack/test/cloud_security_posture_api/ @elastic/kibana-cloud-security-posture +## CSP Serverless tests +x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.* @elastic/kibana-cloud-security-posture +x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/ @elastic/kibana-cloud-security-posture +x-pack/test_serverless/api_integration/test_suites/security/cloud_security_posture/ @elastic/kibana-cloud-security-posture +## CSP e2e tests +x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/misconfiguration_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture +x-pack/test/security_solution_cypress/cypress/e2e/cloud_security_posture/vulnerabilities_contextual_flyout.cy.ts @elastic/kibana-cloud-security-posture # Security Solution onboarding tour /x-pack/plugins/security_solution/public/common/components/guided_onboarding @elastic/security-threat-hunting-explore @@ -2401,6 +2533,7 @@ x-pack/plugins/security_solution/server/lib/security_integrations @elastic/secur /x-pack/plugins/security_solution_serverless/**/*.scss @elastic/security-design # Logstash +/x-pack/test/functional/es_archives/logstash/example_pipelines @elastic/logstash /x-pack/test/functional/services/pipeline_* @elastic/logstash /x-pack/test/functional/page_objects/logstash_page.ts @elastic/logstash /x-pack/test/functional/apps/logstash @elastic/logstash @@ -2423,6 +2556,7 @@ x-pack/test/profiling_api_integration @elastic/obs-ux-infra_services-team x-pack/plugins/observability_solution/observability_shared/public/components/profiling @elastic/obs-ux-infra_services-team # Shared UX +/x-pack/test_serverless/api_integration/test_suites/common/favorites @elastic/appex-sharedux # Assigned per https://github.com/elastic/kibana/pull/200985 /test/api_integration/apis/short_url/**/*.ts @elastic/appex-sharedux # Assigned per https://github.com/elastic/kibana/pull/200209/files#r1846654156 /test/functional/page_objects/share_page.ts @elastic/appex-sharedux # Assigned per https://github.com/elastic/kibana/pull/200209/files#r1846648444 /test/accessibility/apps/kibana_overview_* @elastic/appex-sharedux # Assigned per https://github.com/elastic/kibana/pull/200209/files/cab99bce5ac2082fa77222beebe3b61ff836b94b#r1846659920 diff --git a/.gitignore b/.gitignore index 9bda927a92b6..be8d495f95f1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ target *.iml *.log types.eslint.config.js +types.eslint.config.cjs __tmp__ # Ignore example plugin builds @@ -142,6 +143,8 @@ x-pack/test/security_api_integration/plugins/audit_log/audit.log .ftr role_users.json +# ignore Scout temp directory +.scout .devcontainer/.env @@ -159,3 +162,4 @@ x-pack/test/security_solution_playwright/playwright/.cache/ x-pack/test/security_solution_playwright/.auth/ x-pack/test/security_solution_playwright/.env .codeql +.dependency-graph-log.json diff --git a/.telemetryrc.json b/.telemetryrc.json index 09c3051f81a0..2387ef73c88e 100644 --- a/.telemetryrc.json +++ b/.telemetryrc.json @@ -10,5 +10,10 @@ "output": "src/plugins/telemetry/schema/kbn_packages.json", "root": "packages/", "exclude": [] + }, + { + "output": "src/plugins/telemetry/schema/oss_platform.json", + "root": "src/platform/", + "exclude": [] } ] diff --git a/api_docs/actions.devdocs.json b/api_docs/actions.devdocs.json index d93ecea54b84..551623f07d05 100644 --- a/api_docs/actions.devdocs.json +++ b/api_docs/actions.devdocs.json @@ -3270,20 +3270,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "actions", - "id": "def-server.ActionTypeExecutorOptions.isEphemeral", - "type": "CompoundType", - "tags": [], - "label": "isEphemeral", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/actions/server/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "actions", "id": "def-server.ActionTypeExecutorOptions.taskInfo", @@ -3838,16 +3824,6 @@ "ExecuteOptions", "[]) => Promise<", "ExecutionResponse", - ">; ephemeralEnqueuedExecution: (options: ", - "ExecuteOptions", - ") => Promise<", - { - "pluginId": "taskManager", - "scope": "server", - "docId": "kibTaskManagerPluginApi", - "section": "def-server.RunNowResult", - "text": "RunNowResult" - }, ">; listTypes: ({ featureId, includeSystemActionTypes, }?: ", "ListTypesParams", ") => Promise<", diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index c46307e89955..25325239da8c 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 322 | 0 | 316 | 37 | +| 321 | 0 | 315 | 37 | ## Client diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 3c758b28e162..3ba1bc950dca 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/ai_assistant_management_selection.mdx b/api_docs/ai_assistant_management_selection.mdx index 1f9bbdc82eaf..e6a25e9c32d3 100644 --- a/api_docs/ai_assistant_management_selection.mdx +++ b/api_docs/ai_assistant_management_selection.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/aiAssistantManagementSelection title: "aiAssistantManagementSelection" image: https://source.unsplash.com/400x175/?github description: API docs for the aiAssistantManagementSelection plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiAssistantManagementSelection'] --- import aiAssistantManagementSelectionObj from './ai_assistant_management_selection.devdocs.json'; -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index 1b86116b3a61..5a442711b0a1 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2024-11-22 +date: 2024-12-03 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 0b009877a9f0..7e168f7bf112 100644 --- a/api_docs/alerting.devdocs.json +++ b/api_docs/alerting.devdocs.json @@ -3701,6 +3701,17 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "alerting", + "id": "def-server.RuleExecutorOptions.isServerless", + "type": "boolean", + "tags": [], + "label": "isServerless", + "description": [], + "path": "x-pack/plugins/alerting/server/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -4704,21 +4715,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "alerting", - "id": "def-server.DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT", - "type": "number", - "tags": [], - "label": "DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT", - "description": [], - "signature": [ - "10" - ], - "path": "x-pack/plugins/alerting/server/config.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "alerting", "id": "def-server.ECS_COMPONENT_TEMPLATE_NAME", diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 824a897b7edb..3172ccf49b33 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.devdocs.json b/api_docs/apm.devdocs.json index a288da356746..d6b2c432c467 100644 --- a/api_docs/apm.devdocs.json +++ b/api_docs/apm.devdocs.json @@ -695,7 +695,7 @@ "section": "def-common.TopNFunctions", "text": "TopNFunctions" }, - "; hostNames: string[]; } | undefined, ", + "; hostNames: string[]; containerIds: string[]; } | undefined, ", "APMRouteCreateOptions", ">; \"GET /internal/apm/services/{serviceName}/profiling/hosts/flamegraph\": ", { @@ -829,7 +829,7 @@ "section": "def-common.BaseFlameGraph", "text": "BaseFlameGraph" }, - "; hostNames: string[]; } | undefined, ", + "; hostNames: string[]; containerIds: string[]; } | undefined, ", "APMRouteCreateOptions", ">; \"GET /internal/apm/services/{serviceName}/profiling/functions\": ", { diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 3fd196f6a3ea..d9d9c6275755 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.devdocs.json b/api_docs/apm_data_access.devdocs.json index 6d0f3b4532dc..be97ce96ca40 100644 --- a/api_docs/apm_data_access.devdocs.json +++ b/api_docs/apm_data_access.devdocs.json @@ -441,6 +441,78 @@ ], "functions": [], "interfaces": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck", + "type": "Interface", + "tags": [], + "label": "ApmDataAccessPrivilegesCheck", + "description": [], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck.request", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-server", + "scope": "server", + "docId": "kibKbnSecurityPluginTypesServerPluginApi", + "section": "def-server.SecurityPluginStart", + "text": "SecurityPluginStart" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPrivilegesCheck.getApmIndices", + "type": "Function", + "tags": [], + "label": "getApmIndices", + "description": [], + "signature": [ + "() => Promise>" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "apmDataAccess", "id": "def-server.ApmDataAccessServicesParams", @@ -2293,12 +2365,42 @@ "label": "getApmIndices", "description": [], "signature": [ - "() => Promise>" + "(soClient: ", + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsClientContract", + "text": "SavedObjectsClientContract" + }, + ") => Promise>" ], "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPluginSetup.getApmIndices.$1", + "type": "Object", + "tags": [], + "label": "soClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-api-server", + "scope": "server", + "docId": "kibKbnCoreSavedObjectsApiServerPluginApi", + "section": "def-server.SavedObjectsClientContract", + "text": "SavedObjectsClientContract" + } + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], "returnComment": [] }, { @@ -2402,7 +2504,56 @@ "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", "deprecated": false, "trackAdoption": false, - "children": [], + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPluginStart.hasPrivileges", + "type": "Function", + "tags": [], + "label": "hasPrivileges", + "description": [], + "signature": [ + "(params: Pick<", + { + "pluginId": "apmDataAccess", + "scope": "server", + "docId": "kibApmDataAccessPluginApi", + "section": "def-server.ApmDataAccessPrivilegesCheck", + "text": "ApmDataAccessPrivilegesCheck" + }, + ", \"request\">) => Promise" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "apmDataAccess", + "id": "def-server.ApmDataAccessPluginStart.hasPrivileges.$1", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "Pick<", + { + "pluginId": "apmDataAccess", + "scope": "server", + "docId": "kibApmDataAccessPluginApi", + "section": "def-server.ApmDataAccessPrivilegesCheck", + "text": "ApmDataAccessPrivilegesCheck" + }, + ", \"request\">" + ], + "path": "x-pack/plugins/observability_solution/apm_data_access/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], "lifecycle": "start", "initialIsOpen": true } diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 70d67751d9f5..decef801d061 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,20 +8,20 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) for questions regarding this plugin. **Code health stats** | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 86 | 0 | 86 | 3 | +| 93 | 0 | 93 | 3 | ## Server diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index c4f3b9492fcd..37f6ffd3c560 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 5354ef0b591b..1574b0899679 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index a012f754c98f..90d1aa548e6a 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.devdocs.json b/api_docs/cases.devdocs.json index f1e85ca9536d..b621e45205db 100644 --- a/api_docs/cases.devdocs.json +++ b/api_docs/cases.devdocs.json @@ -503,7 +503,7 @@ "section": "def-common.CasesFindResponseUI", "text": "CasesFindResponseUI" }, - ">; getCasesStatus: (query: { from?: string | undefined; to?: string | undefined; owner?: string | string[] | undefined; }, signal?: AbortSignal | undefined) => Promise<{ countOpenCases: number; countInProgressCases: number; countClosedCases: number; }>; getCasesMetrics: (query: { features: ", + ">; getCasesMetrics: (query: { features: ", { "pluginId": "cases", "scope": "common", @@ -511,7 +511,7 @@ "section": "def-common.CaseMetricsFeature", "text": "CaseMetricsFeature" }, - "[]; } & { from?: string | undefined; to?: string | undefined; owner?: string | string[] | undefined; }, signal?: AbortSignal | undefined) => Promise<{ mttr?: number | null | undefined; }>; bulkGet: (params: { ids: string[]; }, signal?: AbortSignal | undefined) => Promise<{ cases: ({ description: string; tags: string[]; title: string; connector: { id: string; } & (({ type: ", + "[]; } & { from?: string | undefined; to?: string | undefined; owner?: string | string[] | undefined; }, signal?: AbortSignal | undefined) => Promise<{ mttr?: number | null | undefined; status?: { open: number; inProgress: number; closed: number; } | undefined; }>; bulkGet: (params: { ids: string[]; }, signal?: AbortSignal | undefined) => Promise<{ cases: ({ description: string; tags: string[]; title: string; connector: { id: string; } & (({ type: ", { "pluginId": "cases", "scope": "common", @@ -2987,28 +2987,13 @@ "label": "CasesMetricsResponse", "description": [], "signature": [ - "{ mttr?: number | null | undefined; }" + "{ mttr?: number | null | undefined; status?: { open: number; inProgress: number; closed: number; } | undefined; }" ], "path": "x-pack/plugins/cases/common/types/api/metrics/v1.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "cases", - "id": "def-common.CasesStatus", - "type": "Type", - "tags": [], - "label": "CasesStatus", - "description": [], - "signature": [ - "{ countOpenCases: number; countInProgressCases: number; countClosedCases: number; }" - ], - "path": "x-pack/plugins/cases/common/ui/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "cases", "id": "def-common.CasesUI", diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 279f5f92bc77..601841b63ddc 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 126 | 0 | 106 | 28 | +| 125 | 0 | 105 | 28 | ## Client diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index c45e0a8dead2..5d341d4fb045 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 32379e22a8fb..fae98a56939c 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 000e9143be76..eb5a95b7d2cc 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 54adbbaddee5..7646521c485d 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 82a7ab678f33..dcf110b8af02 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2024-11-22 +date: 2024-12-03 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 ca5595652c62..ac3593719be3 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index baec4a847cbe..a6efce141f66 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index ed65a57c45b8..3c954c4b1738 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 168097f88872..b25d90614eec 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2024-11-22 +date: 2024-12-03 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 896f30264a98..01900e4b0d9c 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2024-11-22 +date: 2024-12-03 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 39ff8a3aed26..c268fdfdf219 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 06c3e8522b3b..318ea50da0b4 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_quality.mdx b/api_docs/data_quality.mdx index 041afddaca06..f00b1f0ffbed 100644 --- a/api_docs/data_quality.mdx +++ b/api_docs/data_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataQuality title: "dataQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the dataQuality plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataQuality'] --- import dataQualityObj from './data_quality.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index ba24c3db6c87..e6a4c20b9451 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 52bf12c0a388..ace239d28972 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_usage.devdocs.json b/api_docs/data_usage.devdocs.json index 09fcffd5c58e..fa0dd73eb8c2 100644 --- a/api_docs/data_usage.devdocs.json +++ b/api_docs/data_usage.devdocs.json @@ -88,7 +88,7 @@ "signature": [ "\"/api/data_usage/\"" ], - "path": "x-pack/plugins/data_usage/common/index.ts", + "path": "x-pack/plugins/data_usage/common/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -100,7 +100,7 @@ "tags": [], "label": "DATA_USAGE_DATA_STREAMS_API_ROUTE", "description": [], - "path": "x-pack/plugins/data_usage/common/index.ts", + "path": "x-pack/plugins/data_usage/common/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -112,7 +112,7 @@ "tags": [], "label": "DATA_USAGE_METRICS_API_ROUTE", "description": [], - "path": "x-pack/plugins/data_usage/common/index.ts", + "path": "x-pack/plugins/data_usage/common/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -127,7 +127,7 @@ "signature": [ "50" ], - "path": "x-pack/plugins/data_usage/common/index.ts", + "path": "x-pack/plugins/data_usage/common/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false @@ -142,19 +142,7 @@ "signature": [ "\"data_usage\"" ], - "path": "x-pack/plugins/data_usage/common/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "dataUsage", - "id": "def-common.PLUGIN_NAME", - "type": "string", - "tags": [], - "label": "PLUGIN_NAME", - "description": [], - "path": "x-pack/plugins/data_usage/common/index.ts", + "path": "x-pack/plugins/data_usage/common/constants.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/data_usage.mdx b/api_docs/data_usage.mdx index 3e2caf4ea20f..ecf73aa12a4c 100644 --- a/api_docs/data_usage.mdx +++ b/api_docs/data_usage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataUsage title: "dataUsage" image: https://source.unsplash.com/400x175/?github description: API docs for the dataUsage plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataUsage'] --- import dataUsageObj from './data_usage.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 10 | 0 | 10 | 0 | +| 9 | 0 | 9 | 0 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index eda90bd90b1a..d6af1159f4d8 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index a40a06de84f7..d7f742560200 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2024-11-22 +date: 2024-12-03 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 d611d8e1d6c4..0a652e419568 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.devdocs.json b/api_docs/data_views.devdocs.json index 17af467c336c..2db8e5ec9476 100644 --- a/api_docs/data_views.devdocs.json +++ b/api_docs/data_views.devdocs.json @@ -14202,10 +14202,6 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/eql_query_bar/validators.ts" - }, { "plugin": "timelines", "path": "x-pack/plugins/timelines/server/search_strategy/index_fields/index.ts" diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index e3b18891387d..16737110a668 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2024-11-22 +date: 2024-12-03 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 10b17f6cb009..e6599d0884eb 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/dataset_quality.devdocs.json b/api_docs/dataset_quality.devdocs.json index 0f42873f1c07..d160859f49a9 100644 --- a/api_docs/dataset_quality.devdocs.json +++ b/api_docs/dataset_quality.devdocs.json @@ -311,6 +311,24 @@ "DatasetQualityRouteHandlerResources", ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; defaultPipeline?: string | undefined; }, ", "DatasetQualityRouteCreateOptions", + ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { isIntegration: false; areAssetsAvailable: boolean; } | { isIntegration: true; areAssetsAvailable: true; integration: { name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; }; }, ", + "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -561,7 +579,7 @@ "section": "def-common.ServerRouteCreateOptions", "text": "ServerRouteCreateOptions" }, - "> ? TRouteParamsRT extends ", + " | undefined> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -678,6 +696,24 @@ "DatasetQualityRouteHandlerResources", ", { isFieldLimitIssue: boolean; fieldCount: number; totalFieldLimit: number; } & { ignoreMalformed?: boolean | undefined; nestedFieldLimit?: number | undefined; fieldMapping?: { type?: string | undefined; ignore_above?: number | undefined; } | undefined; defaultPipeline?: string | undefined; }, ", "DatasetQualityRouteCreateOptions", + ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/dataset_quality/data_streams/{dataStream}/integration/check\", ", + "TypeC", + "<{ path: ", + "TypeC", + "<{ dataStream: ", + "StringC", + "; }>; }>, ", + "DatasetQualityRouteHandlerResources", + ", { isIntegration: false; areAssetsAvailable: boolean; } | { isIntegration: true; areAssetsAvailable: true; integration: { name: string; } & { title?: string | undefined; version?: string | undefined; icons?: ({ src: string; } & { path?: string | undefined; size?: string | undefined; title?: string | undefined; type?: string | undefined; })[] | undefined; datasets?: { [x: string]: string; } | undefined; }; }, ", + "DatasetQualityRouteCreateOptions", ">; \"GET /internal/dataset_quality/data_streams/{dataStream}/settings\": ", { "pluginId": "@kbn/server-route-repository-utils", @@ -912,15 +948,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - " ? TReturnType extends ", + " ? TReturnType extends ", { "pluginId": "@kbn/core-http-server", "scope": "server", diff --git a/api_docs/dataset_quality.mdx b/api_docs/dataset_quality.mdx index 8b5a77fa9f8b..c829741bc56c 100644 --- a/api_docs/dataset_quality.mdx +++ b/api_docs/dataset_quality.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/datasetQuality title: "datasetQuality" image: https://source.unsplash.com/400x175/?github description: API docs for the datasetQuality plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'datasetQuality'] --- import datasetQualityObj from './dataset_quality.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index 93404d07f959..0d4d75b73171 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -50,7 +50,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-saved-objects-common, @kbn/core-saved-objects-server, @kbn/core, @kbn/alerting-types, alerting, actions, savedSearch, canvas, enterpriseSearch, securitySolution, taskManager, @kbn/core-saved-objects-server-internal, @kbn/core-saved-objects-api-server | - | | | @kbn/core-saved-objects-api-browser, @kbn/core-saved-objects-browser-internal, @kbn/core-saved-objects-api-server, @kbn/core, savedObjectsTagging, home, canvas, savedObjectsTaggingOss, lists, securitySolution, upgradeAssistant, savedObjectsManagement, @kbn/core-saved-objects-import-export-server-internal, @kbn/core-saved-objects-browser-mocks, @kbn/core-ui-settings-server-internal | - | | | @kbn/core-saved-objects-migration-server-internal, dataViews, actions, data, alerting, dashboard, lens, cases, savedSearch, canvas, savedObjectsTagging, graph, lists, maps, visualizations, securitySolution, @kbn/core-test-helpers-so-type-serializer | - | -| | @kbn/esql-utils, @kbn/securitysolution-utils, securitySolution | - | | | security, securitySolution, cloudLinks, cases | - | | | security, cases, searchPlayground, securitySolution | - | | | lists, securitySolution, @kbn/securitysolution-io-ts-list-types | - | @@ -121,18 +120,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | dataViews, dataViewManagement | - | | | maps | - | | | maps | - | -| | dashboard, maps | - | +| | lens, dashboard, maps | - | | | dataViewManagement | - | | | dataViewManagement | - | | | data, discover, imageEmbeddable, embeddable | - | | | spaces, savedObjectsManagement | - | | | unifiedSearch | - | | | unifiedSearch | - | -| | lens, dashboard, canvas | - | -| | lens | - | -| | lens | - | -| | lens, dashboard, investigateApp | - | | | @kbn/core, lens | - | +| | dashboard, canvas | - | | | canvas | - | | | canvas | - | | | canvas | - | @@ -146,6 +142,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | canvas | - | | | enterpriseSearch | - | | | @kbn/core-elasticsearch-server-internal, @kbn/core-plugins-server-internal, enterpriseSearch, observabilityOnboarding, console | - | +| | dashboard, investigateApp | - | | | dashboard | - | | | embeddable, dashboard | - | | | embeddableEnhanced | - | @@ -169,18 +166,18 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | @kbn/core-plugins-server-internal | - | | | encryptedSavedObjects | - | | | @kbn/esql-validation-autocomplete | - | +| | @kbn/esql-utils | - | | | @kbn/monaco | - | | | reporting | - | | | reporting | - | | | @kbn/reporting-export-types-pdf | - | -| | security, aiops, licenseManagement, ml, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher, profiling, apm, slo | 8.8.0 | +| | security, aiops, licenseManagement, ml, crossClusterReplication, logstash, painlessLab, searchprofiler, watcher, slo | 8.8.0 | | | spaces, security, actions, alerting, aiops, remoteClusters, ml, graph, indexLifecycleManagement, osquery, securitySolution, painlessLab, rollup, searchprofiler, snapshotRestore, transform, upgradeAssistant | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | | | fleet, apm, security, securitySolution | 8.8.0 | | | spaces, @kbn/security-authorization-core, security, alerting, cases, @kbn/security-role-management-model | 8.8.0 | | | embeddable, presentationUtil, lens, dashboard, discover, graph, links | 8.8.0 | | | security, @kbn/security-role-management-model | 8.8.0 | -| | apm | 8.8.0 | | | security | 8.8.0 This is relied on by the reporting feature, and should be removed once reporting @@ -208,6 +205,8 @@ Safe to remove. | | data | | | data | | | embeddableEnhanced | +| | embeddable | +| | embeddable | | | expressionGauge | | | expressionGauge | | | expressions | @@ -223,6 +222,7 @@ Safe to remove. | | expressions | | | expressions | | | expressions | +| | home | | | home | | | kibanaReact | | | kibanaReact | diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 0afb9d9eeaef..d38e73008c01 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -472,14 +472,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] -## @kbn/securitysolution-utils - -| Deprecated API | Reference location(s) | Remove By | -| ---------------|-----------|-----------| -| | [compute_if_esql_query_aggregating.ts](https://github.com/elastic/kibana/tree/main/packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts#:~:text=ast) | - | - - - ## @kbn/unified-field-list | Deprecated API | Reference location(s) | Remove By | @@ -538,9 +530,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/plugin.ts#:~:text=environment) | 8.8.0 | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | -| | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | | | [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts#:~:text=authc), [get_agent_keys_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts#:~:text=authc), [is_superuser.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts#:~:text=authc), [index.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_random_sampler/index.ts#:~:text=authc), [get_agent_keys_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/agent_keys/get_agent_keys_privileges.ts#:~:text=authc), [is_superuser.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/routes/fleet/is_superuser.ts#:~:text=authc) | - | | | [apm_service_groups.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/server/saved_objects/apm_service_groups.ts#:~:text=migrations) | - | @@ -1012,18 +1002,15 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| | | [loader.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/data_views_service/loader.ts#:~:text=title), [lens_top_nav.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx#:~:text=title) | - | -| | [embeddable_component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx#:~:text=EmbeddablePanel), [embeddable_component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx#:~:text=EmbeddablePanel) | - | -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/plugin.ts#:~:text=registerSavedObjectToPanelMethod) | - | -| | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/plugin.ts#:~:text=registerEmbeddableFactory) | - | -| | [embeddable_component.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx#:~:text=getEmbeddableFactory) | - | | | [save_action.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/visualizations/xy/annotations/actions/save_action.tsx#:~:text=SavedObjectSaveModal), [save_action.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/visualizations/xy/annotations/actions/save_action.tsx#:~:text=SavedObjectSaveModal) | 8.8.0 | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SavedObjectsClientContract), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SavedObjectsClientContract), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SavedObjectsClientContract) | - | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SimpleSavedObject), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=SimpleSavedObject) | - | | | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/types.ts#:~:text=ResolvedSimpleSavedObject) | - | | | [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock), [find_object_by_title.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_objects_utils/find_object_by_title.test.ts#:~:text=simpleSavedObjectMock) | - | -| | [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference), [selectors.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/state_management/selectors.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference)+ 52 more | - | +| | [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [saved_object_store.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/persistence/saved_object_store.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference), [state_helpers.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts#:~:text=SavedObjectReference)+ 54 more | - | | | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/server/saved_objects.ts#:~:text=migrations) | - | | | [saved_objects.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/server/saved_objects.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | +| | [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/react_embeddable/types.ts#:~:text=HasLibraryTransforms), [types.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/react_embeddable/types.ts#:~:text=HasLibraryTransforms), [initialize_dashboard_services.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts#:~:text=HasLibraryTransforms), [initialize_dashboard_services.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts#:~:text=HasLibraryTransforms) | - | @@ -1176,7 +1163,6 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Deprecated API | Reference location(s) | Remove By | | ---------------|-----------|-----------| -| | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | | [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get), [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get), [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get), [get_has_setup_privileges.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts#:~:text=get) | - | @@ -1328,7 +1314,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [wrap_search_source_client.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.ts#:~:text=create) | - | | | [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch), [wrap_search_source_client.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/wrap_search_source_client.test.ts#:~:text=fetch) | - | | | [api.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/hooks/eql/api.ts#:~:text=options) | - | -| | [create_sourcerer_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts#:~:text=title), [create_sourcerer_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts#:~:text=title), [create_sourcerer_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts#:~:text=title), [validators.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/eql_query_bar/validators.ts#:~:text=title) | - | +| | [create_sourcerer_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts#:~:text=title), [create_sourcerer_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts#:~:text=title), [create_sourcerer_data_view.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/sourcerer/containers/create_sourcerer_data_view.ts#:~:text=title) | - | | | [fleet_services.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts#:~:text=policy_id), [fleet_services.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts#:~:text=policy_id), [endpoint_metadata_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.test.ts#:~:text=policy_id), [endpoint_package_policies.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/endpoint_package_policies.test.ts#:~:text=policy_id), [index.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts#:~:text=policy_id) | - | | | [fleet_services.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts#:~:text=policy_id), [fleet_services.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/scripts/endpoint/common/fleet_services.ts#:~:text=policy_id), [endpoint_metadata_service.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/services/metadata/endpoint_metadata_service.test.ts#:~:text=policy_id), [endpoint_package_policies.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/routes/metadata/support/endpoint_package_policies.test.ts#:~:text=policy_id), [index.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/index.test.ts#:~:text=policy_id) | - | | | [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), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.test.ts#:~:text=mode), [create_default_policy.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/fleet_integration/handlers/create_default_policy.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)+ 7 more | 8.8.0 | @@ -1348,7 +1334,6 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | | [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [host_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/host_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject), [user_risk_score_dashboards.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/risk_score/prebuilt_saved_objects/saved_object/user_risk_score_dashboards.ts#:~:text=SavedObject) | - | | | [timelines.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts#:~:text=migrations), [notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts#:~:text=migrations), [pinned_events.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts#:~:text=migrations), [legacy_saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts#:~:text=migrations), [saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/endpoint/lib/artifacts/saved_object_mappings.ts#:~:text=migrations) | - | | | [timelines.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/timelines.ts#:~:text=convertToMultiNamespaceTypeVersion), [notes.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/notes.ts#:~:text=convertToMultiNamespaceTypeVersion), [pinned_events.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/timeline/saved_object_mappings/pinned_events.ts#:~:text=convertToMultiNamespaceTypeVersion), [legacy_saved_object_mappings.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/rule_actions/legacy_saved_object_mappings.ts#:~:text=convertToMultiNamespaceTypeVersion) | - | -| | [esql_validator.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts#:~:text=ast), [esql_validator.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts#:~:text=ast) | - | | | [links.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/management/links.ts#:~:text=authc), [hooks.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/lib/kibana/hooks.ts#:~:text=authc) | - | | | [use_bulk_get_user_profiles.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/user_profiles/use_bulk_get_user_profiles.tsx#:~:text=userProfiles), [use_get_current_user_profile.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/public/common/components/user_profiles/use_get_current_user_profile.tsx#:~:text=userProfiles) | - | | | [request_context_factory.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/request_context_factory.ts#:~:text=audit), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin.ts#:~:text=audit), [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/security_solution/server/plugin.ts#:~:text=audit) | - | diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index f6fb16069c43..c42ccc11a88b 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -97,9 +97,7 @@ migrates to using the Kibana Privilege model: https://github.com/elastic/kibana/ | Plugin | Deprecated API | Reference location(s) | Remove By | | --------|-------|-----------|-----------| -| apm | | [plugin.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/plugin.ts#:~:text=environment) | 8.8.0 | | apm | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | -| apm | | [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx#:~:text=license%24), [license_context.tsx](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx#:~:text=license%24) | 8.8.0 | | apm | | [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode), [license_check.test.ts](https://github.com/elastic/kibana/tree/main/x-pack/plugins/observability_solution/apm/common/license_check.test.ts#:~:text=mode)+ 2 more | 8.8.0 | diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 014e3b957729..0b3e9a7f75b6 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 2eb8c1f28f08..51ca92481316 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -800,6 +800,1449 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices", + "type": "Interface", + "tags": [], + "label": "DiscoverServices", + "description": [], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.aiops", + "type": "Object", + "tags": [], + "label": "aiops", + "description": [], + "signature": [ + { + "pluginId": "aiops", + "scope": "public", + "docId": "kibAiopsPluginApi", + "section": "def-public.AiopsPluginStart", + "text": "AiopsPluginStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.application", + "type": "Object", + "tags": [], + "label": "application", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-application-browser", + "scope": "public", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-public.ApplicationStart", + "text": "ApplicationStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.addBasePath", + "type": "Function", + "tags": [], + "label": "addBasePath", + "description": [], + "signature": [ + "(path: string) => string" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.addBasePath.$1", + "type": "string", + "tags": [], + "label": "path", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.analytics", + "type": "Object", + "tags": [], + "label": "analytics", + "description": [], + "signature": [ + "{ optIn: (optInConfig: ", + "OptInConfig", + ") => void; reportEvent: (eventType: string, eventData: EventTypeData) => void; readonly telemetryCounter$: ", + "Observable", + "<", + "TelemetryCounter", + ">; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.i18n", + "type": "Object", + "tags": [], + "label": "i18n", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-i18n-browser", + "scope": "public", + "docId": "kibKbnCoreI18nBrowserPluginApi", + "section": "def-public.I18nStart", + "text": "I18nStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.capabilities", + "type": "Object", + "tags": [], + "label": "capabilities", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-capabilities-common", + "scope": "common", + "docId": "kibKbnCoreCapabilitiesCommonPluginApi", + "section": "def-common.Capabilities", + "text": "Capabilities" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.chrome", + "type": "Object", + "tags": [], + "label": "chrome", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-chrome-browser", + "scope": "public", + "docId": "kibKbnCoreChromeBrowserPluginApi", + "section": "def-public.ChromeStart", + "text": "ChromeStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.core", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreStart", + "text": "CoreStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.data", + "type": "Object", + "tags": [], + "label": "data", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataPluginApi", + "section": "def-public.DataPublicPluginStart", + "text": "DataPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.discoverShared", + "type": "Object", + "tags": [], + "label": "discoverShared", + "description": [], + "signature": [ + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverSharedPublicStart", + "text": "DiscoverSharedPublicStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.docLinks", + "type": "Object", + "tags": [], + "label": "docLinks", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-doc-links-browser", + "scope": "public", + "docId": "kibKbnCoreDocLinksBrowserPluginApi", + "section": "def-public.DocLinksStart", + "text": "DocLinksStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.embeddable", + "type": "Object", + "tags": [], + "label": "embeddable", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableStart", + "text": "EmbeddableStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.history", + "type": "Object", + "tags": [], + "label": "history", + "description": [], + "signature": [ + "History", + "<", + "HistoryLocationState", + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.getScopedHistory", + "type": "Function", + "tags": [], + "label": "getScopedHistory", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/core-application-browser", + "scope": "public", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-public.ScopedHistory", + "text": "ScopedHistory" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.setHeaderActionMenu", + "type": "Function", + "tags": [], + "label": "setHeaderActionMenu", + "description": [], + "signature": [ + "(menuMount: ", + { + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.MountPoint", + "text": "MountPoint" + }, + " | undefined) => void" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.setHeaderActionMenu.$1", + "type": "Function", + "tags": [], + "label": "menuMount", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.MountPoint", + "text": "MountPoint" + }, + " | undefined" + ], + "path": "packages/core/application/core-application-browser/src/app_mount.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.theme", + "type": "Object", + "tags": [], + "label": "theme", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-theme-browser", + "scope": "public", + "docId": "kibKbnCoreThemeBrowserPluginApi", + "section": "def-public.ThemeServiceSetup", + "text": "ThemeServiceSetup" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.filterManager", + "type": "Object", + "tags": [], + "label": "filterManager", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataQueryPluginApi", + "section": "def-public.FilterManager", + "text": "FilterManager" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.fieldFormats", + "type": "CompoundType", + "tags": [], + "label": "fieldFormats", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "fieldFormats", + "scope": "common", + "docId": "kibFieldFormatsPluginApi", + "section": "def-common.FieldFormatsRegistry", + "text": "FieldFormatsRegistry" + }, + ", \"init\" | \"register\"> & { deserialize: ", + { + "pluginId": "fieldFormats", + "scope": "common", + "docId": "kibFieldFormatsPluginApi", + "section": "def-common.FormatFactory", + "text": "FormatFactory" + }, + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataViews", + "type": "Object", + "tags": [], + "label": "dataViews", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "public", + "docId": "kibDataViewsPluginApi", + "section": "def-public.DataViewsServicePublic", + "text": "DataViewsServicePublic" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.inspector", + "type": "Object", + "tags": [], + "label": "inspector", + "description": [], + "signature": [ + { + "pluginId": "inspector", + "scope": "public", + "docId": "kibInspectorPluginApi", + "section": "def-public.Start", + "text": "Start" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.metadata", + "type": "Object", + "tags": [], + "label": "metadata", + "description": [], + "signature": [ + "{ branch: string; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.navigation", + "type": "Object", + "tags": [], + "label": "navigation", + "description": [], + "signature": [ + { + "pluginId": "navigation", + "scope": "public", + "docId": "kibNavigationPluginApi", + "section": "def-public.NavigationPublicStart", + "text": "NavigationPublicStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.share", + "type": "CompoundType", + "tags": [], + "label": "share", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "public", + "docId": "kibSharePluginApi", + "section": "def-public.SharePublicStart", + "text": "SharePublicStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.urlForwarding", + "type": "Object", + "tags": [], + "label": "urlForwarding", + "description": [], + "signature": [ + "{ navigateToLegacyKibanaUrl: (hash: string) => { navigated: boolean; }; getForwards: () => ", + { + "pluginId": "urlForwarding", + "scope": "public", + "docId": "kibUrlForwardingPluginApi", + "section": "def-public.ForwardDefinition", + "text": "ForwardDefinition" + }, + "[]; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.urlTracker", + "type": "Object", + "tags": [], + "label": "urlTracker", + "description": [], + "signature": [ + "UrlTracker" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.timefilter", + "type": "Object", + "tags": [], + "label": "timefilter", + "description": [], + "signature": [ + "{ isTimeRangeSelectorEnabled: () => boolean; isAutoRefreshSelectorEnabled: () => boolean; isTimeTouched: () => boolean; isRefreshIntervalTouched: () => boolean; getEnabledUpdated$: () => ", + "Observable", + "; getTimeUpdate$: () => ", + "Observable", + "; getRefreshIntervalUpdate$: () => ", + "Observable", + "; getAutoRefreshFetch$: () => ", + "Observable", + "<", + { + "pluginId": "data", + "scope": "public", + "docId": "kibDataQueryPluginApi", + "section": "def-public.AutoRefreshDoneFn", + "text": "AutoRefreshDoneFn" + }, + ">; getFetch$: () => ", + "Observable", + "; getTime: () => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; getAbsoluteTime: () => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; setTime: (time: ", + "InputTimeRange", + ") => void; getRefreshInterval: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.RefreshInterval", + "text": "RefreshInterval" + }, + "; getMinRefreshInterval: () => number; setRefreshInterval: (refreshInterval: Partial<", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.RefreshInterval", + "text": "RefreshInterval" + }, + ">) => void; createFilter: (indexPattern: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.RangeFilter", + "text": "RangeFilter" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.ScriptedRangeFilter", + "text": "ScriptedRangeFilter" + }, + " | ", + "MatchAllRangeFilter", + " | undefined; createRelativeFilter: (indexPattern: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.RangeFilter", + "text": "RangeFilter" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.ScriptedRangeFilter", + "text": "ScriptedRangeFilter" + }, + " | ", + "MatchAllRangeFilter", + " | undefined; getBounds: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRangeBounds", + "text": "TimeRangeBounds" + }, + "; calculateBounds: (timeRange: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + ") => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRangeBounds", + "text": "TimeRangeBounds" + }, + "; getActiveBounds: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.TimeRangeBounds", + "text": "TimeRangeBounds" + }, + " | undefined; enableTimeRangeSelector: () => void; disableTimeRangeSelector: () => void; enableAutoRefreshSelector: () => void; disableAutoRefreshSelector: () => void; getTimeDefaults: () => ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + "; getRefreshIntervalDefaults: () => ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataQueryPluginApi", + "section": "def-common.RefreshInterval", + "text": "RefreshInterval" + }, + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.toastNotifications", + "type": "Object", + "tags": [], + "label": "toastNotifications", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-notifications-browser", + "scope": "public", + "docId": "kibKbnCoreNotificationsBrowserPluginApi", + "section": "def-public.IToasts", + "text": "IToasts" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.notifications", + "type": "Object", + "tags": [], + "label": "notifications", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-notifications-browser", + "scope": "public", + "docId": "kibKbnCoreNotificationsBrowserPluginApi", + "section": "def-public.NotificationsStart", + "text": "NotificationsStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-browser", + "scope": "public", + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-public.IUiSettingsClient", + "text": "IUiSettingsClient" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.settings", + "type": "Object", + "tags": [], + "label": "settings", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-ui-settings-browser", + "scope": "public", + "docId": "kibKbnCoreUiSettingsBrowserPluginApi", + "section": "def-public.SettingsStart", + "text": "SettingsStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.trackUiMetric", + "type": "Function", + "tags": [], + "label": "trackUiMetric", + "description": [], + "signature": [ + "((metricType: string, eventName: string | string[]) => void) | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.trackUiMetric.$1", + "type": "string", + "tags": [], + "label": "metricType", + "description": [], + "signature": [ + "string" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.trackUiMetric.$2", + "type": "CompoundType", + "tags": [], + "label": "eventName", + "description": [], + "signature": [ + "string | string[]" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataViewFieldEditor", + "type": "Object", + "tags": [], + "label": "dataViewFieldEditor", + "description": [], + "signature": [ + { + "pluginId": "dataViewFieldEditor", + "scope": "public", + "docId": "kibDataViewFieldEditorPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataViewEditor", + "type": "Object", + "tags": [], + "label": "dataViewEditor", + "description": [], + "signature": [ + { + "pluginId": "dataViewEditor", + "scope": "public", + "docId": "kibDataViewEditorPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.dataVisualizer", + "type": "Object", + "tags": [], + "label": "dataVisualizer", + "description": [], + "signature": [ + "{ getFileDataVisualizerComponent: () => Promise<() => ", + "SpecWithLinks", + ">>; getIndexDataVisualizerComponent: () => Promise<() => React.FC<", + "Props", + ">>; getDataDriftComponent: () => Promise<() => React.FC<", + "DataDriftDetectionAppStateProps", + ">>; getMaxBytesFormatted: () => string; FieldStatsUnavailableMessage: React.ForwardRefExoticComponent<{ id?: string | undefined; title?: string | undefined; } & React.RefAttributes<{}>>; FieldStatisticsTable: React.ForwardRefExoticComponent<", + "FieldStatisticTableEmbeddableProps", + " & React.RefAttributes<{}>>; } | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.http", + "type": "Object", + "tags": [], + "label": "http", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpSetup", + "text": "HttpSetup" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.storage", + "type": "Object", + "tags": [], + "label": "storage", + "description": [], + "signature": [ + { + "pluginId": "kibanaUtils", + "scope": "public", + "docId": "kibKibanaUtilsPluginApi", + "section": "def-public.Storage", + "text": "Storage" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.spaces", + "type": "Object", + "tags": [], + "label": "spaces", + "description": [], + "signature": [ + { + "pluginId": "spaces", + "scope": "public", + "docId": "kibSpacesPluginApi", + "section": "def-public.SpacesApi", + "text": "SpacesApi" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.triggersActionsUi", + "type": "Object", + "tags": [], + "label": "triggersActionsUi", + "description": [], + "signature": [ + { + "pluginId": "triggersActionsUi", + "scope": "public", + "docId": "kibTriggersActionsUiPluginApi", + "section": "def-public.TriggersAndActionsUIPublicPluginStart", + "text": "TriggersAndActionsUIPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.locator", + "type": "Object", + "tags": [], + "label": "locator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + { + "pluginId": "discover", + "scope": "common", + "docId": "kibDiscoverPluginApi", + "section": "def-common.DiscoverAppLocatorParams", + "text": "DiscoverAppLocatorParams" + }, + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.contextLocator", + "type": "Object", + "tags": [], + "label": "contextLocator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "DiscoverContextAppLocatorParams", + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.singleDocLocator", + "type": "Object", + "tags": [], + "label": "singleDocLocator", + "description": [], + "signature": [ + { + "pluginId": "share", + "scope": "common", + "docId": "kibSharePluginApi", + "section": "def-common.LocatorPublic", + "text": "LocatorPublic" + }, + "<", + "DiscoverSingleDocLocatorParams", + ">" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.expressions", + "type": "Object", + "tags": [], + "label": "expressions", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "public", + "docId": "kibExpressionsPluginApi", + "section": "def-public.ExpressionsStart", + "text": "ExpressionsStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.charts", + "type": "CompoundType", + "tags": [], + "label": "charts", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "public", + "docId": "kibChartsPluginApi", + "section": "def-public.ChartsPluginSetup", + "text": "ChartsPluginSetup" + }, + " & { activeCursor: ", + "ActiveCursor", + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.savedObjectsManagement", + "type": "Object", + "tags": [], + "label": "savedObjectsManagement", + "description": [], + "signature": [ + { + "pluginId": "savedObjectsManagement", + "scope": "public", + "docId": "kibSavedObjectsManagementPluginApi", + "section": "def-public.SavedObjectsManagementPluginStart", + "text": "SavedObjectsManagementPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.savedObjectsTagging", + "type": "Object", + "tags": [], + "label": "savedObjectsTagging", + "description": [], + "signature": [ + { + "pluginId": "savedObjectsTaggingOss", + "scope": "public", + "docId": "kibSavedObjectsTaggingOssPluginApi", + "section": "def-public.SavedObjectsTaggingApi", + "text": "SavedObjectsTaggingApi" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.savedSearch", + "type": "Object", + "tags": [], + "label": "savedSearch", + "description": [], + "signature": [ + { + "pluginId": "savedSearch", + "scope": "public", + "docId": "kibSavedSearchPluginApi", + "section": "def-public.SavedSearchPublicPluginStart", + "text": "SavedSearchPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.unifiedSearch", + "type": "Object", + "tags": [], + "label": "unifiedSearch", + "description": [], + "signature": [ + { + "pluginId": "unifiedSearch", + "scope": "public", + "docId": "kibUnifiedSearchPluginApi", + "section": "def-public.UnifiedSearchPublicPluginStart", + "text": "UnifiedSearchPublicPluginStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.lens", + "type": "Object", + "tags": [], + "label": "lens", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensPublicStart", + "text": "LensPublicStart" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.uiActions", + "type": "Object", + "tags": [], + "label": "uiActions", + "description": [], + "signature": [ + "{ readonly registerTrigger: (trigger: ", + { + "pluginId": "@kbn/ui-actions-browser", + "scope": "common", + "docId": "kibKbnUiActionsBrowserPluginApi", + "section": "def-common.Trigger", + "text": "Trigger" + }, + ") => void; readonly hasTrigger: (triggerId: string) => boolean; readonly getTrigger: (triggerId: string) => ", + "TriggerContract", + "; readonly registerAction: (definition: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" + }, + ") => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "; readonly unregisterAction: (actionId: string) => void; readonly hasAction: (actionId: string) => boolean; readonly attachAction: (triggerId: string, actionId: string) => void; readonly detachAction: (triggerId: string, actionId: string) => void; readonly addTriggerAction: (triggerId: string, action: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.ActionDefinition", + "text": "ActionDefinition" + }, + ") => void; readonly getAction: (id: string) => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "; readonly getTriggerActions: (triggerId: string) => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[]; readonly getTriggerCompatibleActions: (triggerId: string, context: object) => Promise<", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[]>; readonly getFrequentlyChangingActionsForTrigger: (triggerId: string, context: object) => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.FrequentCompatibilityChangeAction", + "text": "FrequentCompatibilityChangeAction" + }, + "[]; readonly executeTriggerActions: (triggerId: string, context: object) => Promise; readonly clear: () => void; readonly fork: () => ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.UiActionsService", + "text": "UiActionsService" + }, + "; }" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.contentClient", + "type": "Object", + "tags": [], + "label": "contentClient", + "description": [], + "signature": [ + { + "pluginId": "contentManagement", + "scope": "public", + "docId": "kibContentManagementPluginApi", + "section": "def-public.ContentClient", + "text": "ContentClient" + } + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.noDataPage", + "type": "Object", + "tags": [], + "label": "noDataPage", + "description": [], + "signature": [ + { + "pluginId": "noDataPage", + "scope": "public", + "docId": "kibNoDataPagePluginApi", + "section": "def-public.NoDataPagePublicSetup", + "text": "NoDataPagePublicSetup" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.observabilityAIAssistant", + "type": "Object", + "tags": [], + "label": "observabilityAIAssistant", + "description": [], + "signature": [ + { + "pluginId": "observabilityAIAssistant", + "scope": "public", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-public.ObservabilityAIAssistantPublicStart", + "text": "ObservabilityAIAssistantPublicStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.profilesManager", + "type": "Object", + "tags": [], + "label": "profilesManager", + "description": [], + "signature": [ + "ProfilesManager" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.ebtManager", + "type": "Object", + "tags": [], + "label": "ebtManager", + "description": [], + "signature": [ + "DiscoverEBTManager" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.fieldsMetadata", + "type": "Object", + "tags": [], + "label": "fieldsMetadata", + "description": [], + "signature": [ + { + "pluginId": "fieldsMetadata", + "scope": "public", + "docId": "kibFieldsMetadataPluginApi", + "section": "def-public.FieldsMetadataPublicStart", + "text": "FieldsMetadataPublicStart" + }, + " | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.DiscoverServices.logsDataAccess", + "type": "Object", + "tags": [], + "label": "logsDataAccess", + "description": [], + "signature": [ + "{ services: { logSourcesService: ", + "LogSourcesService", + "; }; } | undefined" + ], + "path": "src/plugins/discover/public/build_services.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "discover", "id": "def-public.DiscoverStateContainer", @@ -1289,6 +2732,48 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "discover", + "id": "def-public.NonPersistedDisplayOptions", + "type": "Interface", + "tags": [], + "label": "NonPersistedDisplayOptions", + "description": [], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discover", + "id": "def-public.NonPersistedDisplayOptions.enableDocumentViewer", + "type": "CompoundType", + "tags": [], + "label": "enableDocumentViewer", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.NonPersistedDisplayOptions.enableFilters", + "type": "CompoundType", + "tags": [], + "label": "enableFilters", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "discover", "id": "def-public.PublishesSavedSearch", @@ -1871,7 +3356,13 @@ "description": [], "signature": [ "{ isLoading?: boolean | undefined; overrideServices: Partial<", - "DiscoverServices", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.DiscoverServices", + "text": "DiscoverServices" + }, ">; scopedHistory: ", { "pluginId": "@kbn/core-application-browser", @@ -1982,6 +3473,239 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "discover", + "id": "def-public.SearchEmbeddableApi", + "type": "Type", + "tags": [], + "label": "SearchEmbeddableApi", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.DefaultEmbeddableApi", + "text": "DefaultEmbeddableApi" + }, + "<", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.SearchEmbeddableSerializedState", + "text": "SearchEmbeddableSerializedState" + }, + ", ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.SearchEmbeddableRuntimeState", + "text": "SearchEmbeddableRuntimeState" + }, + "> & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesSavedObjectId", + "text": "PublishesSavedObjectId" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesDataLoading", + "text": "PublishesDataLoading" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesBlockingError", + "text": "PublishesBlockingError" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesPanelTitle", + "text": "PublishesPanelTitle" + }, + " & { setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; } & ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.PublishesSavedSearch", + "text": "PublishesSavedSearch" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesDataViews", + "text": "PublishesDataViews" + }, + " & { setDataViews: (dataViews: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]) => void; } & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesTimeRange", + "text": "PublishesTimeRange" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesFilters", + "text": "PublishesFilters" + }, + " & { isCompatibleWithUnifiedSearch?: (() => boolean) | undefined; query$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined>; } & { setTimeRange: (timeRange: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => void; } & { setFilters: (filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined) => void; setQuery: (query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | undefined) => void; } & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.HasInPlaceLibraryTransforms", + "text": "HasInPlaceLibraryTransforms" + }, + " & ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.HasTimeRange", + "text": "HasTimeRange" + }, + " & Partial<", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.HasEditCapabilities", + "text": "HasEditCapabilities" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesSavedObjectId", + "text": "PublishesSavedObjectId" + }, + ">" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "discover", + "id": "def-public.SearchEmbeddableRuntimeState", + "type": "Type", + "tags": [], + "label": "SearchEmbeddableRuntimeState", + "description": [], + "signature": [ + "Omit<", + "SearchEmbeddableState", + ", \"rows\" | \"searchSource\" | \"columnsMeta\" | \"totalHitCount\"> & Pick<", + "SerializableSavedSearch", + ", \"serializedSearchSource\"> & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.SerializedTitles", + "text": "SerializedTitles" + }, + " & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.SerializedTimeRange", + "text": "SerializedTimeRange" + }, + " & { savedObjectTitle?: string | undefined; savedObjectId?: string | undefined; savedObjectDescription?: string | undefined; nonPersistedDisplayOptions?: ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.NonPersistedDisplayOptions", + "text": "NonPersistedDisplayOptions" + }, + " | undefined; }" + ], + "path": "src/plugins/discover/public/embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "discover", "id": "def-public.SearchEmbeddableSerializedState", @@ -2019,7 +3743,15 @@ "section": "def-common.SavedObjectReference", "text": "SavedObjectReference" }, - "[] | undefined; }) | undefined; savedObjectId?: string | undefined; }" + "[] | undefined; }) | undefined; savedObjectId?: string | undefined; nonPersistedDisplayOptions?: ", + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.NonPersistedDisplayOptions", + "text": "NonPersistedDisplayOptions" + }, + " | undefined; }" ], "path": "src/plugins/discover/public/embeddable/types.ts", "deprecated": false, diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index e51f0efbca90..dc4c2a117f6c 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 148 | 0 | 100 | 24 | +| 214 | 0 | 166 | 30 | ## Client diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index 8f33990a5cb6..dd1634e549f7 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/discover_shared.devdocs.json b/api_docs/discover_shared.devdocs.json index bc05a07a26fe..39dc71aa37b1 100644 --- a/api_docs/discover_shared.devdocs.json +++ b/api_docs/discover_shared.devdocs.json @@ -4,6 +4,94 @@ "classes": [], "functions": [], "interfaces": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceSetup", + "type": "Interface", + "tags": [], + "label": "DiscoverFeaturesServiceSetup", + "description": [ + "\nService types" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceSetup.registry", + "type": "Object", + "tags": [], + "label": "registry", + "description": [], + "signature": [ + { + "pluginId": "discoverShared", + "scope": "common", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-common.FeaturesRegistry", + "text": "FeaturesRegistry" + }, + "<", + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeature", + "text": "DiscoverFeature" + }, + ">" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceStart", + "type": "Interface", + "tags": [], + "label": "DiscoverFeaturesServiceStart", + "description": [], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.DiscoverFeaturesServiceStart.registry", + "type": "Object", + "tags": [], + "label": "registry", + "description": [], + "signature": [ + { + "pluginId": "discoverShared", + "scope": "common", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-common.FeaturesRegistry", + "text": "FeaturesRegistry" + }, + "<", + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeature", + "text": "DiscoverFeature" + }, + ">" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "discoverShared", "id": "def-public.ObservabilityLogsAIAssistantFeature", @@ -113,6 +201,104 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionAppWrapperFeature", + "type": "Interface", + "tags": [], + "label": "SecuritySolutionAppWrapperFeature", + "description": [], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionAppWrapperFeature.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "\"security-solution-app-wrapper\"" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionAppWrapperFeature.getWrapper", + "type": "Function", + "tags": [], + "label": "getWrapper", + "description": [], + "signature": [ + "() => Promise<() => React.FunctionComponent<{ children?: React.ReactNode; }>>" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionCellRendererFeature", + "type": "Interface", + "tags": [], + "label": "SecuritySolutionCellRendererFeature", + "description": [ + "*************** Security Solution" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionCellRendererFeature.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "\"security-solution-cell-renderer\"" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "discoverShared", + "id": "def-public.SecuritySolutionCellRendererFeature.getRenderer", + "type": "Function", + "tags": [], + "label": "getRenderer", + "description": [], + "signature": [ + "() => Promise<(fieldName: string) => React.FunctionComponent<", + { + "pluginId": "@kbn/unified-data-table", + "scope": "public", + "docId": "kibKbnUnifiedDataTablePluginApi", + "section": "def-public.DataGridCellValueElementProps", + "text": "DataGridCellValueElementProps" + }, + "> | undefined>" + ], + "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false } ], "enums": [], @@ -133,7 +319,9 @@ "text": "ObservabilityLogsAIAssistantFeature" }, " | ", - "ObservabilityCreateSLOFeature" + "ObservabilityCreateSLOFeature", + " | ", + "SecuritySolutionFeature" ], "path": "src/plugins/discover_shared/public/services/discover_features/types.ts", "deprecated": false, @@ -161,7 +349,13 @@ "label": "features", "description": [], "signature": [ - "DiscoverFeaturesServiceSetup" + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeaturesServiceSetup", + "text": "DiscoverFeaturesServiceSetup" + } ], "path": "src/plugins/discover_shared/public/types.ts", "deprecated": false, @@ -190,7 +384,13 @@ "label": "features", "description": [], "signature": [ - "DiscoverFeaturesServiceStart" + { + "pluginId": "discoverShared", + "scope": "public", + "docId": "kibDiscoverSharedPluginApi", + "section": "def-public.DiscoverFeaturesServiceStart", + "text": "DiscoverFeaturesServiceStart" + } ], "path": "src/plugins/discover_shared/public/types.ts", "deprecated": false, diff --git a/api_docs/discover_shared.mdx b/api_docs/discover_shared.mdx index 5625ea4ce73a..0f6288b8ea94 100644 --- a/api_docs/discover_shared.mdx +++ b/api_docs/discover_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverShared title: "discoverShared" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverShared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverShared'] --- import discoverSharedObj from './discover_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 15 | 3 | +| 26 | 0 | 23 | 2 | ## Client diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index a89da9995ee8..98377a0807c9 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index 67ebc7fedb13..7a0831a5debf 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.devdocs.json b/api_docs/embeddable.devdocs.json index f462c063c1df..29710266277e 100644 --- a/api_docs/embeddable.devdocs.json +++ b/api_docs/embeddable.devdocs.json @@ -8190,14 +8190,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" - }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" - }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_container/component/grid/dashboard_grid_item.tsx" @@ -9203,7 +9195,7 @@ "section": "def-public.PresentationPanelProps", "text": "PresentationPanelProps" }, - ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideLoader\" | \"hideHeader\" | \"hideInspector\"> | undefined; hidePanelChrome?: boolean | undefined; onAnyStateChange?: ((state: ", + ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideLoader\" | \"hideHeader\" | \"hideInspector\" | \"getActions\"> | undefined; hidePanelChrome?: boolean | undefined; onAnyStateChange?: ((state: ", { "pluginId": "@kbn/presentation-containers", "scope": "public", @@ -9317,7 +9309,7 @@ "section": "def-public.PresentationPanelProps", "text": "PresentationPanelProps" }, - ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideLoader\" | \"hideHeader\" | \"hideInspector\"> | undefined" + ", \"showShadow\" | \"showBorder\" | \"showBadges\" | \"showNotifications\" | \"hideLoader\" | \"hideHeader\" | \"hideInspector\" | \"getActions\"> | undefined" ], "path": "src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx", "deprecated": false, @@ -14475,12 +14467,7 @@ "path": "src/plugins/embeddable/public/plugin.tsx", "deprecated": true, "trackAdoption": false, - "references": [ - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/plugin.ts" - } - ], + "references": [], "returnComment": [], "children": [ { @@ -14699,12 +14686,7 @@ "path": "src/plugins/embeddable/public/plugin.tsx", "deprecated": true, "trackAdoption": false, - "references": [ - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/plugin.ts" - } - ], + "references": [], "children": [ { "parentPluginId": "embeddable", @@ -15058,10 +15040,6 @@ "deprecated": true, "trackAdoption": false, "references": [ - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx" - }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/services/dashboard_content_management_service/lib/migrate_dashboard_input.ts" diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index cb4b3c4bad40..7774b8b0a3c5 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2024-11-22 +date: 2024-12-03 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 e7c8c82ff029..2439bde8e99d 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2024-11-22 +date: 2024-12-03 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 acb4cefaddec..32a3d89f65a2 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2024-11-22 +date: 2024-12-03 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 e7a15f22d30a..230c232342c7 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/entities_data_access.mdx b/api_docs/entities_data_access.mdx index d3dc9b4f8bf3..fb7b4c912b45 100644 --- a/api_docs/entities_data_access.mdx +++ b/api_docs/entities_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entitiesDataAccess title: "entitiesDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the entitiesDataAccess plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entitiesDataAccess'] --- import entitiesDataAccessObj from './entities_data_access.devdocs.json'; diff --git a/api_docs/entity_manager.devdocs.json b/api_docs/entity_manager.devdocs.json index a3f5fff48eb9..fb4d3e8050c6 100644 --- a/api_docs/entity_manager.devdocs.json +++ b/api_docs/entity_manager.devdocs.json @@ -2,6 +2,1035 @@ "id": "entityManager", "client": { "classes": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient", + "type": "Class", + "tags": [], + "label": "EntityClient", + "description": [], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.repositoryClient", + "type": "Function", + "tags": [], + "label": "repositoryClient", + "description": [], + "signature": [ + "(endpoint: TEndpoint, ...args: MaybeOptionalArgs<", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ClientRequestParamsOf", + "text": "ClientRequestParamsOf" + }, + "<{ \"POST /internal/entities/v2/_search/preview\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; display_name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + "<{ entities: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.EntityV2", + "text": "EntityV2" + }, + "[]; }>, undefined>; \"POST /internal/entities/v2/_search\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"PATCH /internal/entities/definition/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PATCH /internal/entities/definition/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; body: Zod.ZodObject; filter: Zod.ZodOptional>; version: Zod.ZodOptional>; name: Zod.ZodOptional; description: Zod.ZodOptional>; metrics: Zod.ZodOptional; field: Zod.ZodString; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"doc_count\">; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"percentile\">; field: Zod.ZodString; percentile: Zod.ZodNumber; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }>]>, \"many\">; equation: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }>, \"many\">>>; indexPatterns: Zod.ZodOptional>; metadata: Zod.ZodOptional; aggregation: Zod.ZodDefault; limit: Zod.ZodDefault; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; }, { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; }>, Zod.ZodObject<{ type: Zod.ZodLiteral<\"top_value\">; sort: Zod.ZodRecord, Zod.ZodLiteral<\"desc\">]>>; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }>]>>>; }, \"strip\", Zod.ZodTypeAny, { source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; destination?: string | undefined; }, { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, Zod.ZodEffects]>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, \"many\">>>; identityFields: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; optional: false; }, { field: string; optional: false; }>, Zod.ZodEffects]>, \"many\">>; displayNameTemplate: Zod.ZodOptional; staticFields: Zod.ZodOptional>>; latest: Zod.ZodOptional>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }, { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }>>; installedComponents: Zod.ZodOptional, Zod.ZodLiteral<\"ingest_pipeline\">, Zod.ZodLiteral<\"template\">]>; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }>, \"many\">>>; }, { latest: Zod.ZodOptional; lookbackPeriod: Zod.ZodOptional>>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }>>>; }, \"strip\", Zod.ZodTypeAny, { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; }, { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; }>>; version: Zod.ZodEffects; }>, \"strip\", Zod.ZodTypeAny, { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; identityFields?: ({ field: string; optional: false; } | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }, { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: false; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; identityFields?: ({ field: string; optional: false; } | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }, { path: { id: string; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: false; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"POST /internal/entities/definition/{id}/_reset\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/definition/{id}/_reset\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"GET /internal/entities/definition/{id?}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/entities/definition/{id?}\", Zod.ZodObject<{ query: Zod.ZodObject<{ page: Zod.ZodOptional; perPage: Zod.ZodOptional; includeState: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { includeState: boolean; page?: number | undefined; perPage?: number | undefined; }, { page?: number | undefined; perPage?: number | undefined; includeState?: boolean | \"true\" | \"false\" | undefined; }>; path: Zod.ZodObject<{ id: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; }, { id?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { includeState: boolean; page?: number | undefined; perPage?: number | undefined; }; path: { id?: string | undefined; }; }, { query: { page?: number | undefined; perPage?: number | undefined; includeState?: boolean | \"true\" | \"false\" | undefined; }; path: { id?: string | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"DELETE /internal/entities/definition/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"DELETE /internal/entities/definition/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; query: Zod.ZodObject<{ deleteData: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { deleteData: boolean; }, { deleteData?: boolean | \"true\" | \"false\" | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { deleteData: boolean; }; path: { id: string; }; }, { query: { deleteData?: boolean | \"true\" | \"false\" | undefined; }; path: { id: string; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"POST /internal/entities/definition\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/definition\", Zod.ZodObject<{ query: Zod.ZodObject<{ installOnly: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { installOnly: boolean; }, { installOnly?: boolean | \"true\" | \"false\" | undefined; }>; body: Zod.ZodObject<{ id: Zod.ZodString; version: Zod.ZodEffects; name: Zod.ZodString; description: Zod.ZodOptional; type: Zod.ZodString; filter: Zod.ZodOptional; indexPatterns: Zod.ZodArray; identityFields: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { field: string; optional: false; }, { field: string; optional: false; }>, Zod.ZodEffects]>, \"many\">; displayNameTemplate: Zod.ZodString; metadata: Zod.ZodOptional; aggregation: Zod.ZodDefault; limit: Zod.ZodDefault; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; }, { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; }>, Zod.ZodObject<{ type: Zod.ZodLiteral<\"top_value\">; sort: Zod.ZodRecord, Zod.ZodLiteral<\"desc\">]>>; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }>]>>>; }, \"strip\", Zod.ZodTypeAny, { source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; destination?: string | undefined; }, { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, Zod.ZodEffects]>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, \"many\">>; metrics: Zod.ZodOptional; field: Zod.ZodString; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"doc_count\">; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"percentile\">; field: Zod.ZodString; percentile: Zod.ZodNumber; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }>]>, \"many\">; equation: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }>, \"many\">>; staticFields: Zod.ZodOptional>; managed: Zod.ZodDefault>; latest: Zod.ZodObject<{ timestampField: Zod.ZodString; lookbackPeriod: Zod.ZodDefault>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }, { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }>; installStatus: Zod.ZodOptional, Zod.ZodLiteral<\"upgrading\">, Zod.ZodLiteral<\"installed\">, Zod.ZodLiteral<\"failed\">]>>; installStartedAt: Zod.ZodOptional; installedComponents: Zod.ZodOptional, Zod.ZodLiteral<\"ingest_pipeline\">, Zod.ZodLiteral<\"template\">]>; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { id: string; type: string; version: string; name: string; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: false; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; latest: { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }, { id: string; type: string; version: string; name: string; indexPatterns: string[]; identityFields: (string | { field: string; optional: false; })[]; displayNameTemplate: string; latest: { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; managed?: boolean | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { installOnly: boolean; }; body: { id: string; type: string; version: string; name: string; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: false; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; latest: { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }, { query: { installOnly?: boolean | \"true\" | \"false\" | undefined; }; body: { id: string; type: string; version: string; name: string; indexPatterns: string[]; identityFields: (string | { field: string; optional: false; })[]; displayNameTemplate: string; latest: { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; managed?: boolean | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"DELETE /internal/entities/managed/enablement\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"DELETE /internal/entities/managed/enablement\", Zod.ZodObject<{ query: Zod.ZodObject<{ deleteData: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { deleteData: boolean; }, { deleteData?: boolean | \"true\" | \"false\" | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { deleteData: boolean; }; }, { query: { deleteData?: boolean | \"true\" | \"false\" | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"PUT /internal/entities/managed/enablement\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PUT /internal/entities/managed/enablement\", Zod.ZodObject<{ query: Zod.ZodObject<{ installOnly: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { installOnly: boolean; }, { installOnly?: boolean | \"true\" | \"false\" | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { installOnly: boolean; }; }, { query: { installOnly?: boolean | \"true\" | \"false\" | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"GET /internal/entities/managed/enablement\": { endpoint: \"GET /internal/entities/managed/enablement\"; handler: ServerRouteHandler<", + "EntityManagerRouteHandlerResources", + ", undefined, ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ">; security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; }; }, TEndpoint> & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => Promise<", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ReturnOf", + "text": "ReturnOf" + }, + "<{ \"POST /internal/entities/v2/_search/preview\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; display_name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + "<{ entities: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.EntityV2", + "text": "EntityV2" + }, + "[]; }>, undefined>; \"POST /internal/entities/v2/_search\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"PATCH /internal/entities/definition/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PATCH /internal/entities/definition/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; body: Zod.ZodObject; filter: Zod.ZodOptional>; version: Zod.ZodOptional>; name: Zod.ZodOptional; description: Zod.ZodOptional>; metrics: Zod.ZodOptional; field: Zod.ZodString; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"doc_count\">; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"percentile\">; field: Zod.ZodString; percentile: Zod.ZodNumber; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }>]>, \"many\">; equation: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }>, \"many\">>>; indexPatterns: Zod.ZodOptional>; metadata: Zod.ZodOptional; aggregation: Zod.ZodDefault; limit: Zod.ZodDefault; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; }, { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; }>, Zod.ZodObject<{ type: Zod.ZodLiteral<\"top_value\">; sort: Zod.ZodRecord, Zod.ZodLiteral<\"desc\">]>>; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }>]>>>; }, \"strip\", Zod.ZodTypeAny, { source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; destination?: string | undefined; }, { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, Zod.ZodEffects]>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, \"many\">>>; identityFields: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; optional: false; }, { field: string; optional: false; }>, Zod.ZodEffects]>, \"many\">>; displayNameTemplate: Zod.ZodOptional; staticFields: Zod.ZodOptional>>; latest: Zod.ZodOptional>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }, { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }>>; installedComponents: Zod.ZodOptional, Zod.ZodLiteral<\"ingest_pipeline\">, Zod.ZodLiteral<\"template\">]>; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }>, \"many\">>>; }, { latest: Zod.ZodOptional; lookbackPeriod: Zod.ZodOptional>>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }>>>; }, \"strip\", Zod.ZodTypeAny, { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; }, { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; }>>; version: Zod.ZodEffects; }>, \"strip\", Zod.ZodTypeAny, { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; identityFields?: ({ field: string; optional: false; } | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }, { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: false; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; identityFields?: ({ field: string; optional: false; } | { field: string; optional: boolean; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }, { path: { id: string; }; body: { version: string; type?: string | undefined; filter?: string | undefined; name?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; indexPatterns?: string[] | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; identityFields?: (string | { field: string; optional: false; })[] | undefined; displayNameTemplate?: string | undefined; staticFields?: Record | undefined; latest?: { settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; timestampField?: string | undefined; } | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"POST /internal/entities/definition/{id}/_reset\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/definition/{id}/_reset\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"GET /internal/entities/definition/{id?}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /internal/entities/definition/{id?}\", Zod.ZodObject<{ query: Zod.ZodObject<{ page: Zod.ZodOptional; perPage: Zod.ZodOptional; includeState: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { includeState: boolean; page?: number | undefined; perPage?: number | undefined; }, { page?: number | undefined; perPage?: number | undefined; includeState?: boolean | \"true\" | \"false\" | undefined; }>; path: Zod.ZodObject<{ id: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { id?: string | undefined; }, { id?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { includeState: boolean; page?: number | undefined; perPage?: number | undefined; }; path: { id?: string | undefined; }; }, { query: { page?: number | undefined; perPage?: number | undefined; includeState?: boolean | \"true\" | \"false\" | undefined; }; path: { id?: string | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"DELETE /internal/entities/definition/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"DELETE /internal/entities/definition/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; query: Zod.ZodObject<{ deleteData: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { deleteData: boolean; }, { deleteData?: boolean | \"true\" | \"false\" | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { deleteData: boolean; }; path: { id: string; }; }, { query: { deleteData?: boolean | \"true\" | \"false\" | undefined; }; path: { id: string; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"POST /internal/entities/definition\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/definition\", Zod.ZodObject<{ query: Zod.ZodObject<{ installOnly: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { installOnly: boolean; }, { installOnly?: boolean | \"true\" | \"false\" | undefined; }>; body: Zod.ZodObject<{ id: Zod.ZodString; version: Zod.ZodEffects; name: Zod.ZodString; description: Zod.ZodOptional; type: Zod.ZodString; filter: Zod.ZodOptional; indexPatterns: Zod.ZodArray; identityFields: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { field: string; optional: false; }, { field: string; optional: false; }>, Zod.ZodEffects]>, \"many\">; displayNameTemplate: Zod.ZodString; metadata: Zod.ZodOptional; aggregation: Zod.ZodDefault; limit: Zod.ZodDefault; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; }, { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; }>, Zod.ZodObject<{ type: Zod.ZodLiteral<\"top_value\">; sort: Zod.ZodRecord, Zod.ZodLiteral<\"desc\">]>>; lookbackPeriod: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }, { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }>]>>>; }, \"strip\", Zod.ZodTypeAny, { source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; destination?: string | undefined; }, { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, Zod.ZodEffects]>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; }, string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; }>, \"many\">>; metrics: Zod.ZodOptional; field: Zod.ZodString; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }, { name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"doc_count\">; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }, { name: string; aggregation: \"doc_count\"; filter?: string | undefined; }>, Zod.ZodObject<{ name: Zod.ZodString; aggregation: Zod.ZodLiteral<\"percentile\">; field: Zod.ZodString; percentile: Zod.ZodNumber; filter: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }, { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; }>]>, \"many\">; equation: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }, { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }>, \"many\">>; staticFields: Zod.ZodOptional>; managed: Zod.ZodDefault>; latest: Zod.ZodObject<{ timestampField: Zod.ZodString; lookbackPeriod: Zod.ZodDefault>; settings: Zod.ZodOptional; syncDelay: Zod.ZodOptional; frequency: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }, { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; }>>; }, \"strip\", Zod.ZodTypeAny, { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }, { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }>; installStatus: Zod.ZodOptional, Zod.ZodLiteral<\"upgrading\">, Zod.ZodLiteral<\"installed\">, Zod.ZodLiteral<\"failed\">]>>; installStartedAt: Zod.ZodOptional; installedComponents: Zod.ZodOptional, Zod.ZodLiteral<\"ingest_pipeline\">, Zod.ZodLiteral<\"template\">]>; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }, { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { id: string; type: string; version: string; name: string; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: false; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; latest: { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }, { id: string; type: string; version: string; name: string; indexPatterns: string[]; identityFields: (string | { field: string; optional: false; })[]; displayNameTemplate: string; latest: { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; managed?: boolean | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { installOnly: boolean; }; body: { id: string; type: string; version: string; name: string; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: false; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; latest: { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }, { query: { installOnly?: boolean | \"true\" | \"false\" | undefined; }; body: { id: string; type: string; version: string; name: string; indexPatterns: string[]; identityFields: (string | { field: string; optional: false; })[]; displayNameTemplate: string; latest: { timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; lookbackPeriod?: string | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; managed?: boolean | undefined; metadata?: (string | { source: string; destination?: string | undefined; aggregation?: { type: \"terms\"; limit?: number | undefined; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; } | undefined; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"DELETE /internal/entities/managed/enablement\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"DELETE /internal/entities/managed/enablement\", Zod.ZodObject<{ query: Zod.ZodObject<{ deleteData: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { deleteData: boolean; }, { deleteData?: boolean | \"true\" | \"false\" | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { deleteData: boolean; }; }, { query: { deleteData?: boolean | \"true\" | \"false\" | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"PUT /internal/entities/managed/enablement\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PUT /internal/entities/managed/enablement\", Zod.ZodObject<{ query: Zod.ZodObject<{ installOnly: Zod.ZodDefault, Zod.ZodBoolean]>, boolean, boolean | \"true\" | \"false\">>>; }, \"strip\", Zod.ZodTypeAny, { installOnly: boolean; }, { installOnly?: boolean | \"true\" | \"false\" | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { query: { installOnly: boolean; }; }, { query: { installOnly?: boolean | \"true\" | \"false\" | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"GET /internal/entities/managed/enablement\": { endpoint: \"GET /internal/entities/managed/enablement\"; handler: ServerRouteHandler<", + "EntityManagerRouteHandlerResources", + ", undefined, ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ">; security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; }; }, TEndpoint>>" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.repositoryClient.$1", + "type": "Uncategorized", + "tags": [], + "label": "endpoint", + "description": [], + "signature": [ + "TEndpoint" + ], + "path": "packages/kbn-server-route-repository-utils/src/typings.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.repositoryClient.$2", + "type": "Uncategorized", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "RequiredKeys", + "<", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ClientRequestParamsOf", + "text": "ClientRequestParamsOf" + }, + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + "> extends never ? [] | [", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ClientRequestParamsOf", + "text": "ClientRequestParamsOf" + }, + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + "] : [", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ClientRequestParamsOf", + "text": "ClientRequestParamsOf" + }, + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + "]" + ], + "path": "packages/kbn-server-route-repository-utils/src/typings.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.Unnamed.$1", + "type": "CompoundType", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreStart", + "text": "CoreStart" + }, + " | ", + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreSetup", + "text": "CoreSetup" + }, + "" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.isManagedEntityDiscoveryEnabled", + "type": "Function", + "tags": [], + "label": "isManagedEntityDiscoveryEnabled", + "description": [], + "signature": [ + "() => Promise<{ enabled: boolean; reason: string; }>" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.enableManagedEntityDiscovery", + "type": "Function", + "tags": [], + "label": "enableManagedEntityDiscovery", + "description": [], + "signature": [ + "(query?: { installOnly?: boolean | \"true\" | \"false\" | undefined; } | undefined) => Promise<{ success: boolean; reason: string; message: string; }>" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.enableManagedEntityDiscovery.$1", + "type": "Object", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "{ installOnly?: boolean | \"true\" | \"false\" | undefined; } | undefined" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.disableManagedEntityDiscovery", + "type": "Function", + "tags": [], + "label": "disableManagedEntityDiscovery", + "description": [], + "signature": [ + "(query?: { deleteData?: boolean | \"true\" | \"false\" | undefined; } | undefined) => Promise<{ success: boolean; reason: string; message: string; }>" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.disableManagedEntityDiscovery.$1", + "type": "Object", + "tags": [], + "label": "query", + "description": [], + "signature": [ + "{ deleteData?: boolean | \"true\" | \"false\" | undefined; } | undefined" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.getEntityDefinition", + "type": "Function", + "tags": [], + "label": "getEntityDefinition", + "description": [], + "signature": [ + "(id: string) => Promise<{ definitions: { id: string; type: string; version: string; name: string; managed: boolean; indexPatterns: string[]; identityFields: ({ field: string; optional: false; } | { field: string; optional: boolean; })[]; displayNameTemplate: string; latest: { lookbackPeriod: string; timestampField: string; settings?: { frequency?: string | undefined; syncField?: string | undefined; syncDelay?: string | undefined; } | undefined; }; filter?: string | undefined; description?: string | undefined; metrics?: { name: string; metrics: ({ name: string; field: string; aggregation: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.BasicAggregations", + "text": "BasicAggregations" + }, + "; filter?: string | undefined; } | { name: string; aggregation: \"doc_count\"; filter?: string | undefined; } | { name: string; field: string; percentile: number; aggregation: \"percentile\"; filter?: string | undefined; })[]; equation: string; }[] | undefined; metadata?: ({ destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod?: string | undefined; } | { type: \"top_value\"; sort: Record; lookbackPeriod?: string | undefined; }; } | { destination: string; source: string; aggregation: { type: \"terms\"; limit: number; lookbackPeriod: undefined; }; })[] | undefined; staticFields?: Record | undefined; installStatus?: \"failed\" | \"installing\" | \"upgrading\" | \"installed\" | undefined; installStartedAt?: string | undefined; installedComponents?: { id: string; type: \"transform\" | \"template\" | \"ingest_pipeline\"; }[] | undefined; }[] | ", + "EntityDefinitionWithState", + "[]; }>" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.getEntityDefinition.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.asKqlFilter", + "type": "Function", + "tags": [], + "label": "asKqlFilter", + "description": [], + "signature": [ + "(entityInstance: { entity: Pick<{ id: string; type: string; schema_version: string; identity_fields: string | string[]; display_name: string; definition_version: string; definition_id: string; last_seen_timestamp: string; metrics?: Record | undefined; }, \"identity_fields\">; } & Required) => string" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.asKqlFilter.$1", + "type": "CompoundType", + "tags": [], + "label": "entityInstance", + "description": [], + "signature": [ + "{ entity: Pick<{ id: string; type: string; schema_version: string; identity_fields: string | string[]; display_name: string; definition_version: string; definition_id: string; last_seen_timestamp: string; metrics?: Record | undefined; }, \"identity_fields\">; } & Required" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.getIdentityFieldsValue", + "type": "Function", + "tags": [], + "label": "getIdentityFieldsValue", + "description": [], + "signature": [ + "(entityInstance: { entity: Pick<{ id: string; type: string; schema_version: string; identity_fields: string | string[]; display_name: string; definition_version: string; definition_id: string; last_seen_timestamp: string; metrics?: Record | undefined; }, \"identity_fields\">; } & Required) => Record" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "entityManager", + "id": "def-public.EntityClient.getIdentityFieldsValue.$1", + "type": "CompoundType", + "tags": [], + "label": "entityInstance", + "description": [], + "signature": [ + "{ entity: Pick<{ id: string; type: string; schema_version: string; identity_fields: string | string[]; display_name: string; definition_version: string; definition_id: string; last_seen_timestamp: string; metrics?: Record | undefined; }, \"identity_fields\">; } & Required" + ], + "path": "x-pack/plugins/entity_manager/public/lib/entity_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "entityManager", "id": "def-public.EntityManagerUnauthorizedError", @@ -174,7 +1203,13 @@ "label": "entityClient", "description": [], "signature": [ - "EntityClient" + { + "pluginId": "entityManager", + "scope": "public", + "docId": "kibEntityManagerPluginApi", + "section": "def-public.EntityClient", + "text": "EntityClient" + } ], "path": "x-pack/plugins/entity_manager/public/types.ts", "deprecated": false, @@ -203,7 +1238,13 @@ "label": "entityClient", "description": [], "signature": [ - "EntityClient" + { + "pluginId": "entityManager", + "scope": "public", + "docId": "kibEntityManagerPluginApi", + "section": "def-public.EntityClient", + "text": "EntityClient" + } ], "path": "x-pack/plugins/entity_manager/public/types.ts", "deprecated": false, @@ -243,7 +1284,51 @@ "label": "EntityManagerRouteRepository", "description": [], "signature": [ - "{ \"PATCH /internal/entities/definition/{id}\": ", + "{ \"POST /internal/entities/v2/_search/preview\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/v2/_search/preview\", Zod.ZodObject<{ body: Zod.ZodObject<{ sources: Zod.ZodArray; index_patterns: Zod.ZodArray; identity_fields: Zod.ZodArray; metadata_fields: Zod.ZodArray; filters: Zod.ZodArray; display_name: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }, { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }>, \"many\">; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { start: string; end: string; sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; limit: number; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { sources: { type: string; filters: string[]; metadata_fields: string[]; index_patterns: string[]; identity_fields: string[]; timestamp_field?: string | undefined; display_name?: string | undefined; }[]; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; limit?: number | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + "<{ entities: ", + { + "pluginId": "@kbn/entities-schema", + "scope": "common", + "docId": "kibKbnEntitiesSchemaPluginApi", + "section": "def-common.EntityV2", + "text": "EntityV2" + }, + "[]; }>, undefined>; \"POST /internal/entities/v2/_search\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/entities/v2/_search\", Zod.ZodObject<{ body: Zod.ZodObject<{ type: Zod.ZodString; metadata_fields: Zod.ZodDefault>>; filters: Zod.ZodDefault>>; start: Zod.ZodEffects>, string, string | undefined>; end: Zod.ZodEffects>, string, string | undefined>; sort: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { field: string; direction: \"ASC\" | \"DESC\"; }, { field: string; direction: \"ASC\" | \"DESC\"; }>>; limit: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }, { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { type: string; start: string; end: string; filters: string[]; limit: number; metadata_fields: string[]; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; }; }, { body: { type: string; start?: string | undefined; end?: string | undefined; sort?: { field: string; direction: \"ASC\" | \"DESC\"; } | undefined; filters?: string[] | undefined; limit?: number | undefined; metadata_fields?: string[] | undefined; }; }>, ", + "EntityManagerRouteHandlerResources", + ", ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.IKibanaResponse", + "text": "IKibanaResponse" + }, + ", undefined>; \"PATCH /internal/entities/definition/{id}\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -333,15 +1418,7 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"POST /internal/entities/definition/{id}/_reset\": ", + ", undefined>; \"POST /internal/entities/definition/{id}/_reset\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -359,15 +1436,7 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"GET /internal/entities/definition/{id?}\": ", + ", undefined>; \"GET /internal/entities/definition/{id?}\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -385,15 +1454,7 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"DELETE /internal/entities/definition/{id}\": ", + ", undefined>; \"DELETE /internal/entities/definition/{id}\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -411,15 +1472,7 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"POST /internal/entities/definition\": ", + ", undefined>; \"POST /internal/entities/definition\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -509,15 +1562,7 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"DELETE /internal/entities/managed/enablement\": ", + ", undefined>; \"DELETE /internal/entities/managed/enablement\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -535,15 +1580,7 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"PUT /internal/entities/managed/enablement\": ", + ", undefined>; \"PUT /internal/entities/managed/enablement\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -561,25 +1598,9 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"GET /internal/entities/managed/enablement\": ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRoute", - "text": "ServerRoute" - }, - "<\"GET /internal/entities/managed/enablement\", undefined, ", + ", undefined>; \"GET /internal/entities/managed/enablement\": { endpoint: \"GET /internal/entities/managed/enablement\"; handler: ServerRouteHandler<", "EntityManagerRouteHandlerResources", - ", ", + ", undefined, ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -587,15 +1608,15 @@ "section": "def-server.IKibanaResponse", "text": "IKibanaResponse" }, - ", ", + ">; security?: ", { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" }, - ">; }" + " | undefined; }; }" ], "path": "x-pack/plugins/entity_manager/server/routes/index.ts", "deprecated": false, diff --git a/api_docs/entity_manager.mdx b/api_docs/entity_manager.mdx index d6856ee270d2..3711c94ed9ba 100644 --- a/api_docs/entity_manager.mdx +++ b/api_docs/entity_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/entityManager title: "entityManager" image: https://source.unsplash.com/400x175/?github description: API docs for the entityManager plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'entityManager'] --- import entityManagerObj from './entity_manager.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entiti | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 20 | 0 | 20 | 3 | +| 37 | 0 | 37 | 3 | ## Client diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 71ea62f1d088..1d5cd9990b9d 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/esql.mdx b/api_docs/esql.mdx index 73a8cec2d5d2..d026d789d73a 100644 --- a/api_docs/esql.mdx +++ b/api_docs/esql.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esql title: "esql" image: https://source.unsplash.com/400x175/?github description: API docs for the esql plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esql'] --- import esqlObj from './esql.devdocs.json'; diff --git a/api_docs/esql_data_grid.mdx b/api_docs/esql_data_grid.mdx index e976b72ccbc3..4cd5976f886c 100644 --- a/api_docs/esql_data_grid.mdx +++ b/api_docs/esql_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esqlDataGrid title: "esqlDataGrid" image: https://source.unsplash.com/400x175/?github description: API docs for the esqlDataGrid plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esqlDataGrid'] --- import esqlDataGridObj from './esql_data_grid.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 6a5e39f98e57..60c63d315f8f 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index b68acc6aae10..006a0ad52e32 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index 86306851253b..90bed851be23 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index 54dee6f42f36..d226a1207d3f 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index 57e3252c5b9f..5412c012dccf 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2024-11-22 +date: 2024-12-03 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 b6b78728afb0..0be715deea20 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2024-11-22 +date: 2024-12-03 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 834736852c12..c7882909785d 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2024-11-22 +date: 2024-12-03 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 289e994db73c..c9332d0b0ff6 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2024-11-22 +date: 2024-12-03 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 a58694530b8c..e83cea3de90c 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2024-11-22 +date: 2024-12-03 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 a1a500a4e34b..872ef40b76e3 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2024-11-22 +date: 2024-12-03 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 8c65e20d9a7b..b3c82de9aaed 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2024-11-22 +date: 2024-12-03 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 5e6c0d8d9a0b..8c1e1462e9ee 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2024-11-22 +date: 2024-12-03 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 89ae0a046fd6..fe3383781dd3 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2024-11-22 +date: 2024-12-03 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 6ff7ee1ef487..585fdceb1ae5 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2024-11-22 +date: 2024-12-03 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 961c00ac133e..3c46e5108b05 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2024-11-22 +date: 2024-12-03 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 3b49f274c7d3..1ab84e554d86 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2024-11-22 +date: 2024-12-03 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 8f51158e4b64..c63d33f62a1c 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.devdocs.json b/api_docs/expressions.devdocs.json index 08f101eb3abe..5ca47f1114d5 100644 --- a/api_docs/expressions.devdocs.json +++ b/api_docs/expressions.devdocs.json @@ -9545,7 +9545,7 @@ "label": "onData$", "description": [], "signature": [ - "((data: TData, adapters?: TInspectorAdapters | undefined, partial?: boolean | undefined) => void) | undefined" + "((data: TData, adapters?: TInspectorAdapters | undefined, partial?: boolean | undefined) => void) | undefined" ], "path": "src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts", "deprecated": false, diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 190d68318871..f7433b89be8a 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 74e11e54e571..b4cab32461bd 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2024-11-22 +date: 2024-12-03 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 2016174d824b..d3a77744d938 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/fields_metadata.mdx b/api_docs/fields_metadata.mdx index ae6c21e33e75..7700b42a9da6 100644 --- a/api_docs/fields_metadata.mdx +++ b/api_docs/fields_metadata.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldsMetadata title: "fieldsMetadata" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldsMetadata plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldsMetadata'] --- import fieldsMetadataObj from './fields_metadata.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index 81fa1a1bec2b..2169567dd27d 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2024-11-22 +date: 2024-12-03 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 535a33443751..c7568eef46d7 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index 30b87f6f2144..ebcc2d578f6c 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.devdocs.json b/api_docs/fleet.devdocs.json index 4d371badd779..9abcedefd304 100644 --- a/api_docs/fleet.devdocs.json +++ b/api_docs/fleet.devdocs.json @@ -1840,6 +1840,20 @@ "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-public.NewPackagePolicy.supports_agentless", + "type": "CompoundType", + "tags": [], + "label": "supports_agentless", + "description": [], + "signature": [ + "boolean | null | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -3084,7 +3098,7 @@ "section": "def-common.PackagePolicyConfigRecord", "text": "PackagePolicyConfigRecord" }, - " | undefined; elasticsearch?: { [key: string]: any; privileges?: { cluster?: string[] | undefined; } | undefined; } | undefined; overrides?: { inputs?: { [key: string]: any; } | undefined; } | null | undefined; }" + " | undefined; elasticsearch?: { [key: string]: any; privileges?: { cluster?: string[] | undefined; } | undefined; } | undefined; overrides?: { inputs?: { [key: string]: any; } | undefined; } | null | undefined; supports_agentless?: boolean | null | undefined; }" ], "path": "x-pack/plugins/fleet/public/types/ui_extensions.ts", "deprecated": false, @@ -9229,6 +9243,61 @@ ], "returnComment": [] }, + { + "parentPluginId": "fleet", + "id": "def-server.PackageClient.getLatestPackageInfo", + "type": "Function", + "tags": [], + "label": "getLatestPackageInfo", + "description": [], + "signature": [ + "(packageName: string, prerelease?: boolean | undefined) => Promise<", + { + "pluginId": "fleet", + "scope": "common", + "docId": "kibFleetPluginApi", + "section": "def-common.PackageInfo", + "text": "PackageInfo" + }, + ">" + ], + "path": "x-pack/plugins/fleet/server/services/epm/package_service.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "fleet", + "id": "def-server.PackageClient.getLatestPackageInfo.$1", + "type": "string", + "tags": [], + "label": "packageName", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/fleet/server/services/epm/package_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "fleet", + "id": "def-server.PackageClient.getLatestPackageInfo.$2", + "type": "CompoundType", + "tags": [], + "label": "prerelease", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/fleet/server/services/epm/package_service.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, { "parentPluginId": "fleet", "id": "def-server.PackageClient.getPackages", @@ -20134,6 +20203,57 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "fleet", + "id": "def-server.FleetStartContract.createOutputClient", + "type": "Function", + "tags": [], + "label": "createOutputClient", + "description": [ + "\nCreate a Fleet Output Client instance" + ], + "signature": [ + "(request: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + ") => Promise<", + "OutputClientInterface", + ">" + ], + "path": "x-pack/plugins/fleet/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "fleet", + "id": "def-server.FleetStartContract.createOutputClient.$1", + "type": "Object", + "tags": [], + "label": "request", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "x-pack/plugins/fleet/server/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "lifecycle": "start", @@ -24608,6 +24728,20 @@ "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "fleet", + "id": "def-common.NewPackagePolicy.supports_agentless", + "type": "CompoundType", + "tags": [], + "label": "supports_agentless", + "description": [], + "signature": [ + "boolean | null | undefined" + ], + "path": "x-pack/plugins/fleet/common/types/models/package_policy.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 4b15fbe5e960..1c4db3adeae7 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 1428 | 5 | 1303 | 81 | +| 1435 | 5 | 1309 | 82 | ## Client diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 93b2911bb9da..229d3a9e4bbb 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 6bdbe7638cc5..7824e377774e 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.devdocs.json b/api_docs/home.devdocs.json index 1b22af8001d6..797a06a30715 100644 --- a/api_docs/home.devdocs.json +++ b/api_docs/home.devdocs.json @@ -1415,12 +1415,7 @@ "deprecated": true, "removeBy": "8.8.0", "trackAdoption": false, - "references": [ - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/public/plugin.ts" - } - ] + "references": [] } ], "lifecycle": "setup", diff --git a/api_docs/home.mdx b/api_docs/home.mdx index aaecc50110ff..7dc920164d8d 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index cfdd524b8c4b..67b9a220830b 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 4989a78d7a72..56da4fb40641 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2024-11-22 +date: 2024-12-03 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 354ee844c309..2e82880526e5 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/inference.devdocs.json b/api_docs/inference.devdocs.json index 340b5e87d7f0..4cf16dcfec9b 100644 --- a/api_docs/inference.devdocs.json +++ b/api_docs/inference.devdocs.json @@ -738,11 +738,13 @@ "type": "Function", "tags": [], "label": "correctCommonEsqlMistakes", - "description": [], + "description": [ + "\nCorrect some common ES|QL syntax and grammar mistakes that LLM can potentially do.\n\nCorrecting the query is done in two steps:\n1. we try to correct the *syntax*, without AST (given it requires a valid syntax)\n2. we try to correct the *grammar*, using AST this time." + ], "signature": [ - "(query: string) => { isCorrection: boolean; input: string; output: string; }" + "(query: string) => { input: string; output: string; isCorrection: boolean; }" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -756,7 +758,7 @@ "signature": [ "string" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -929,7 +931,7 @@ "signature": [ "(query: string) => { name: string | undefined; command: string; }[]" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts", "deprecated": false, "trackAdoption": false, "children": [ @@ -943,7 +945,7 @@ "signature": [ "string" ], - "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts", + "path": "x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts", "deprecated": false, "trackAdoption": false, "isRequired": true diff --git a/api_docs/inference.mdx b/api_docs/inference.mdx index 93db807612e5..ec0fa9af5251 100644 --- a/api_docs/inference.mdx +++ b/api_docs/inference.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inference title: "inference" image: https://source.unsplash.com/400x175/?github description: API docs for the inference plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inference'] --- import inferenceObj from './inference.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 40 | 0 | 29 | 6 | +| 40 | 0 | 28 | 6 | ## Client diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 54a886e8d430..76d0e667edac 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/ingest_pipelines.mdx b/api_docs/ingest_pipelines.mdx index a6864f177fb9..7c385f03d849 100644 --- a/api_docs/ingest_pipelines.mdx +++ b/api_docs/ingest_pipelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ingestPipelines title: "ingestPipelines" image: https://source.unsplash.com/400x175/?github description: API docs for the ingestPipelines plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ingestPipelines'] --- import ingestPipelinesObj from './ingest_pipelines.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 695ec48139c3..453e6fba686d 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/integration_assistant.devdocs.json b/api_docs/integration_assistant.devdocs.json index 37870e95e8e9..3c6f41d4c4c0 100644 --- a/api_docs/integration_assistant.devdocs.json +++ b/api_docs/integration_assistant.devdocs.json @@ -318,7 +318,7 @@ "label": "AnalyzeLogsResponse", "description": [], "signature": [ - "{ results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", + "{ results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -357,7 +357,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }" + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }" ], "path": "x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.gen.ts", "deprecated": false, @@ -384,7 +384,7 @@ "label": "CategorizationRequestBody", "description": [], "signature": [ - "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -581,7 +581,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }" + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -625,7 +625,7 @@ "label": "EcsMappingRequestBody", "description": [], "signature": [ - "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", + "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -714,7 +714,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }" + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -848,7 +848,7 @@ "label": "RelatedRequestBody", "description": [], "signature": [ - "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "{ connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -912,7 +912,7 @@ "\nFormat of the provided log samples." ], "signature": [ - "{ name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }" + "{ name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -929,7 +929,7 @@ "\nThe name of the log samples format." ], "signature": [ - "\"ndjson\" | \"json\" | \"csv\" | \"structured\" | \"unstructured\" | \"unsupported\"" + "\"ndjson\" | \"json\" | \"csv\" | \"structured\" | \"unstructured\" | \"unsupported\" | \"cef\"" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -971,7 +971,7 @@ }, ", Zod.ZodTypeDef, ", "ESProcessorItemInput", - ">, \"many\">>; results: Zod.ZodObject<{ samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; parsedSamples: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }>; }, \"strip\", Zod.ZodTypeAny, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", + ">, \"many\">>; results: Zod.ZodObject<{ samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; parsedSamples: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }, { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }>; }, \"strip\", Zod.ZodTypeAny, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -979,7 +979,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", + "[] | undefined; }, { results: { samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; parsedSamples: string[]; }; additionalProcessors?: ", "ESProcessorItemInput", "[] | undefined; }>" ], @@ -1036,7 +1036,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1052,11 +1052,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1072,11 +1072,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1092,11 +1092,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }, { integration: { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }>" + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/build_integration/build_integration.gen.ts", "deprecated": false, @@ -1151,7 +1151,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1167,7 +1167,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", @@ -1456,7 +1456,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1472,11 +1472,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>" + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -1506,7 +1506,7 @@ "label": "EcsMappingRequestBody", "description": [], "signature": [ - "Zod.ZodObject<{ packageName: Zod.ZodString; dataStreamName: Zod.ZodString; rawSamples: Zod.ZodArray; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; mapping: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; additionalProcessors: Zod.ZodOptional; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; mapping: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>>; additionalProcessors: Zod.ZodOptional, \"many\">>; connectorId: Zod.ZodString; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", + ">, \"many\">>; connectorId: Zod.ZodString; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1524,7 +1524,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", + "[] | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; mapping?: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\"> | undefined; additionalProcessors?: ", "ESProcessorItemInput", "[] | undefined; }>" ], @@ -1716,7 +1716,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }>; docs: Zod.ZodArray, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>, \"many\">; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; celInput: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">>; redactVars: Zod.ZodArray; }, \"strip\", Zod.ZodTypeAny, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }, { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; }>>; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1732,11 +1732,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }, { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }>, \"many\">; logo: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1752,11 +1752,11 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", + "[] | undefined; }; docs: Zod.objectOutputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }, { name: string; title: string; description: string; dataStreams: { name: string; title: string; description: string; inputTypes: (\"kafka\" | \"aws-cloudwatch\" | \"aws-s3\" | \"azure-blob-storage\" | \"azure-eventhub\" | \"cel\" | \"cloudfoundry\" | \"filestream\" | \"gcp-pubsub\" | \"gcs\" | \"http_endpoint\" | \"journald\" | \"tcp\" | \"udp\")[]; rawSamples: string[]; pipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>" + "[] | undefined; }; docs: Zod.objectInputType<{}, Zod.ZodUnknown, \"strip\">[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; celInput?: { program: string; stateSettings: {} & { [k: string]: unknown; }; redactVars: string[]; } | undefined; }[]; logo?: string | undefined; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -1881,7 +1881,7 @@ "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", - "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }>; connectorId: Zod.ZodString; samplesFormat: Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>; langSmithOptions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", { "pluginId": "integrationAssistant", "scope": "common", @@ -1897,7 +1897,7 @@ "section": "def-common.ESProcessorItem", "text": "ESProcessorItem" }, - "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", + "[] | undefined; }; langSmithOptions?: { apiKey: string; projectName: string; } | undefined; }, { connectorId: string; packageName: string; rawSamples: string[]; samplesFormat: { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }; dataStreamName: string; currentPipeline: { processors: ", "ESProcessorItemInput", "[]; version?: number | undefined; name?: string | undefined; description?: string | undefined; on_failure?: ", "ESProcessorItemInput", @@ -2011,7 +2011,7 @@ "label": "SamplesFormat", "description": [], "signature": [ - "Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>" + "Zod.ZodObject<{ name: Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>; multiline: Zod.ZodOptional; header: Zod.ZodOptional; columns: Zod.ZodOptional>; json_path: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }, { name: \"unsupported\" | \"json\" | \"ndjson\" | \"csv\" | \"structured\" | \"unstructured\" | \"cef\"; columns?: string[] | undefined; header?: boolean | undefined; multiline?: boolean | undefined; json_path?: string[] | undefined; }>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, @@ -2026,7 +2026,7 @@ "label": "SamplesFormatName", "description": [], "signature": [ - "Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\"]>" + "Zod.ZodEnum<[\"ndjson\", \"json\", \"csv\", \"structured\", \"unstructured\", \"unsupported\", \"cef\"]>" ], "path": "x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts", "deprecated": false, diff --git a/api_docs/integration_assistant.mdx b/api_docs/integration_assistant.mdx index 7d6cae5abf1b..8d8a9090a827 100644 --- a/api_docs/integration_assistant.mdx +++ b/api_docs/integration_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/integrationAssistant title: "integrationAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the integrationAssistant plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'integrationAssistant'] --- import integrationAssistantObj from './integration_assistant.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 05468989ddaa..8a5c806b2c6a 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/inventory.devdocs.json b/api_docs/inventory.devdocs.json index 00f3e7b5b9b8..39c0d7b7c7b6 100644 --- a/api_docs/inventory.devdocs.json +++ b/api_docs/inventory.devdocs.json @@ -82,9 +82,13 @@ "PartialC", "<{ query: ", "PartialC", - "<{ esQuery: ", + "<{ includeEntityTypes: ", "Type", - "<{ [key: string]: unknown; }, string, unknown>; }>; }>]>, ", + "; excludeEntityTypes: ", + "Type", + "; kuery: ", + "StringC", + "; }>; }>]>, ", "InventoryRouteHandlerResources", ", { groupBy: \"entity.type\"; groups: ", "EntityGroup", @@ -136,9 +140,9 @@ "LiteralC", "<\"desc\">]>; }>, ", "PartialC", - "<{ esQuery: ", - "Type", - "<{ [key: string]: unknown; }, string, unknown>; entityTypes: ", + "<{ kuery: ", + "StringC", + "; entityTypes: ", "Type", "; }>]>; }>, ", "InventoryRouteHandlerResources", diff --git a/api_docs/inventory.mdx b/api_docs/inventory.mdx index aa17f2393961..aadd2ea61f55 100644 --- a/api_docs/inventory.mdx +++ b/api_docs/inventory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inventory title: "inventory" image: https://source.unsplash.com/400x175/?github description: API docs for the inventory plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inventory'] --- import inventoryObj from './inventory.devdocs.json'; diff --git a/api_docs/investigate.mdx b/api_docs/investigate.mdx index 3520f542e229..655656d8e900 100644 --- a/api_docs/investigate.mdx +++ b/api_docs/investigate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigate title: "investigate" image: https://source.unsplash.com/400x175/?github description: API docs for the investigate plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigate'] --- import investigateObj from './investigate.devdocs.json'; diff --git a/api_docs/investigate_app.mdx b/api_docs/investigate_app.mdx index b4d0a8050845..8d11653091be 100644 --- a/api_docs/investigate_app.mdx +++ b/api_docs/investigate_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/investigateApp title: "investigateApp" image: https://source.unsplash.com/400x175/?github description: API docs for the investigateApp plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'investigateApp'] --- import investigateAppObj from './investigate_app.devdocs.json'; diff --git a/api_docs/kbn_actions_types.mdx b/api_docs/kbn_actions_types.mdx index 3f9fee6b535c..bc6e94cfac6e 100644 --- a/api_docs/kbn_actions_types.mdx +++ b/api_docs/kbn_actions_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-actions-types title: "@kbn/actions-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/actions-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/actions-types'] --- import kbnActionsTypesObj from './kbn_actions_types.devdocs.json'; diff --git a/api_docs/kbn_ai_assistant.mdx b/api_docs/kbn_ai_assistant.mdx index 254f5dd2b38e..c683aeba6873 100644 --- a/api_docs/kbn_ai_assistant.mdx +++ b/api_docs/kbn_ai_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ai-assistant title: "@kbn/ai-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ai-assistant plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ai-assistant'] --- import kbnAiAssistantObj from './kbn_ai_assistant.devdocs.json'; diff --git a/api_docs/kbn_ai_assistant_common.mdx b/api_docs/kbn_ai_assistant_common.mdx index 3b95d229a596..f19f97a4449f 100644 --- a/api_docs/kbn_ai_assistant_common.mdx +++ b/api_docs/kbn_ai_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ai-assistant-common title: "@kbn/ai-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ai-assistant-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ai-assistant-common'] --- import kbnAiAssistantCommonObj from './kbn_ai_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.devdocs.json b/api_docs/kbn_aiops_components.devdocs.json index 90b929e81e67..fc526124b270 100644 --- a/api_docs/kbn_aiops_components.devdocs.json +++ b/api_docs/kbn_aiops_components.devdocs.json @@ -703,6 +703,22 @@ "path": "x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/aiops-components", + "id": "def-common.DocumentCountChartProps.nonInteractive", + "type": "CompoundType", + "tags": [], + "label": "nonInteractive", + "description": [ + "Whether the brush should be non-interactive" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 2fc68aaca35c..f97b1a673f4e 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) for questi | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 36 | 0 | 0 | 0 | +| 37 | 0 | 0 | 0 | ## Common diff --git a/api_docs/kbn_aiops_log_pattern_analysis.mdx b/api_docs/kbn_aiops_log_pattern_analysis.mdx index a6815681ce67..fbac611741b8 100644 --- a/api_docs/kbn_aiops_log_pattern_analysis.mdx +++ b/api_docs/kbn_aiops_log_pattern_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-pattern-analysis title: "@kbn/aiops-log-pattern-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-pattern-analysis plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-pattern-analysis'] --- import kbnAiopsLogPatternAnalysisObj from './kbn_aiops_log_pattern_analysis.devdocs.json'; diff --git a/api_docs/kbn_aiops_log_rate_analysis.mdx b/api_docs/kbn_aiops_log_rate_analysis.mdx index d3adfe40323e..3dd810cf505b 100644 --- a/api_docs/kbn_aiops_log_rate_analysis.mdx +++ b/api_docs/kbn_aiops_log_rate_analysis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-log-rate-analysis title: "@kbn/aiops-log-rate-analysis" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-log-rate-analysis plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-log-rate-analysis'] --- import kbnAiopsLogRateAnalysisObj from './kbn_aiops_log_rate_analysis.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index ec363b57d161..55bf830ff784 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_comparators.mdx b/api_docs/kbn_alerting_comparators.mdx index df6278d74112..4accc32a4deb 100644 --- a/api_docs/kbn_alerting_comparators.mdx +++ b/api_docs/kbn_alerting_comparators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-comparators title: "@kbn/alerting-comparators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-comparators plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-comparators'] --- import kbnAlertingComparatorsObj from './kbn_alerting_comparators.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index 9e142b96ba8c..44f688a7bb5d 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerting_types.mdx b/api_docs/kbn_alerting_types.mdx index 3899a44b8a45..e086a2773059 100644 --- a/api_docs/kbn_alerting_types.mdx +++ b/api_docs/kbn_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-types title: "@kbn/alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-types'] --- import kbnAlertingTypesObj from './kbn_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index 2c43f24595af..5e51f13103f9 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_grouping.mdx b/api_docs/kbn_alerts_grouping.mdx index c88ae5ad6183..2e75a8a1181f 100644 --- a/api_docs/kbn_alerts_grouping.mdx +++ b/api_docs/kbn_alerts_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-grouping title: "@kbn/alerts-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-grouping plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-grouping'] --- import kbnAlertsGroupingObj from './kbn_alerts_grouping.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.devdocs.json b/api_docs/kbn_alerts_ui_shared.devdocs.json index 402f4ad328ac..b186a273e1dd 100644 --- a/api_docs/kbn_alerts_ui_shared.devdocs.json +++ b/api_docs/kbn_alerts_ui_shared.devdocs.json @@ -5203,6 +5203,20 @@ "path": "packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/alerts-ui-shared", + "id": "def-public.UseLoadConnectorTypesProps.featureId", + "type": "string", + "tags": [], + "label": "featureId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-alerts-ui-shared/src/common/hooks/use_load_connector_types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index 5f15133af906..9e573d9868d5 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-o | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 320 | 0 | 304 | 8 | +| 321 | 0 | 305 | 8 | ## Client diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 54eb2a99f9ff..4920c2b74d82 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_collection_utils.mdx b/api_docs/kbn_analytics_collection_utils.mdx index b938716b8505..e31437c87d60 100644 --- a/api_docs/kbn_analytics_collection_utils.mdx +++ b/api_docs/kbn_analytics_collection_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-collection-utils title: "@kbn/analytics-collection-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-collection-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-collection-utils'] --- import kbnAnalyticsCollectionUtilsObj from './kbn_analytics_collection_utils.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 45c6d171b9d5..6f3489930119 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_data_view.mdx b/api_docs/kbn_apm_data_view.mdx index 945ef3fe2aa4..11f911917bf0 100644 --- a/api_docs/kbn_apm_data_view.mdx +++ b/api_docs/kbn_apm_data_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-data-view title: "@kbn/apm-data-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-data-view plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-data-view'] --- import kbnApmDataViewObj from './kbn_apm_data_view.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index 5ef2fdf98029..77ca49ee9a36 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.devdocs.json b/api_docs/kbn_apm_synthtrace_client.devdocs.json index 4f458c6eb82a..0c4dcd3b9beb 100644 --- a/api_docs/kbn_apm_synthtrace_client.devdocs.json +++ b/api_docs/kbn_apm_synthtrace_client.devdocs.json @@ -3133,7 +3133,7 @@ "label": "LogDocument", "description": [], "signature": [ - "{ '@timestamp'?: number | undefined; } & Partial<{ 'input.type': string; 'log.file.path'?: string | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'data_stream.namespace': string; 'data_stream.type': string; 'data_stream.dataset': string; message?: string | undefined; 'error.message'?: string | undefined; 'event.original'?: string | undefined; 'event.dataset': string; 'log.level'?: string | undefined; 'host.name'?: string | undefined; 'container.id'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'kubernetes.pod.uid'?: string | undefined; 'aws.s3.bucket.name'?: string | undefined; 'aws.kinesis.name'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'container.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.exception.stacktrace'?: string | undefined; 'error.log.stacktrace'?: string | undefined; 'log.custom': Record; 'host.geo.location': number[]; 'host.ip': string; 'network.bytes': number; 'tls.established': boolean; 'event.duration': number; 'event.start': Date; 'event.end': Date; labels?: Record | undefined; test_field: string | string[]; date: Date; severity: string; msg: string; svc: string; hostname: string; thisisaverylongfieldnamethatevendoesnotcontainanyspaceswhyitcouldpotentiallybreakouruiinseveralplaces: string; }>" + "{ '@timestamp'?: number | undefined; } & Partial<{ _index?: string | undefined; 'input.type': string; 'log.file.path'?: string | undefined; 'service.name'?: string | undefined; 'service.environment'?: string | undefined; 'data_stream.namespace': string; 'data_stream.type': string; 'data_stream.dataset': string; message?: string | undefined; 'error.message'?: string | undefined; 'event.original'?: string | undefined; 'event.dataset': string; 'log.level'?: string | undefined; 'host.name'?: string | undefined; 'container.id'?: string | undefined; 'trace.id'?: string | undefined; 'transaction.id'?: string | undefined; 'agent.id'?: string | undefined; 'agent.name'?: string | undefined; 'orchestrator.cluster.name'?: string | undefined; 'orchestrator.cluster.id'?: string | undefined; 'orchestrator.resource.id'?: string | undefined; 'kubernetes.pod.uid'?: string | undefined; 'aws.s3.bucket.name'?: string | undefined; 'aws.kinesis.name'?: string | undefined; 'orchestrator.namespace'?: string | undefined; 'container.name'?: string | undefined; 'cloud.provider'?: string | undefined; 'cloud.region'?: string | undefined; 'cloud.availability_zone'?: string | undefined; 'cloud.project.id'?: string | undefined; 'cloud.instance.id'?: string | undefined; 'error.stack_trace'?: string | undefined; 'error.exception.stacktrace'?: string | undefined; 'error.log.stacktrace'?: string | undefined; 'log.custom': Record; 'host.geo.location': number[]; 'host.ip': string; 'network.bytes': number; 'tls.established': boolean; 'event.duration': number; 'event.start': Date; 'event.end': Date; labels?: Record | undefined; test_field: string | string[]; date: Date; severity: string; msg: string; svc: string; hostname: string; 'http.status_code'?: number | undefined; 'http.request.method'?: string | undefined; 'url.path'?: string | undefined; 'process.name'?: string | undefined; 'kubernetes.namespace'?: string | undefined; 'kubernetes.pod.name'?: string | undefined; 'kubernetes.container.name'?: string | undefined; 'orchestrator.resource.name'?: string | undefined; thisisaverylongfieldnamethatevendoesnotcontainanyspaceswhyitcouldpotentiallybreakouruiinseveralplaces: string; }>" ], "path": "packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts", "deprecated": false, @@ -3634,10 +3634,10 @@ }, { "parentPluginId": "@kbn/apm-synthtrace-client", - "id": "def-common.entities.k8s.k8sJobSetEntity", + "id": "def-common.entities.k8s.k8sJobEntity", "type": "Function", "tags": [], - "label": "k8sJobSetEntity", + "label": "k8sJobEntity", "description": [], "signature": [ "({ schema, name, uid, clusterName, entityId, ...others }: { [key: string]: any; schema: ", @@ -3652,7 +3652,7 @@ "children": [ { "parentPluginId": "@kbn/apm-synthtrace-client", - "id": "def-common.entities.k8s.k8sJobSetEntity.$1", + "id": "def-common.entities.k8s.k8sJobEntity.$1", "type": "Object", "tags": [], "label": "__0", @@ -3662,7 +3662,7 @@ "Schema", "; name: string; uid?: string | undefined; clusterName?: string | undefined; entityId: string; }" ], - "path": "packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/job_set_entity.ts", + "path": "packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/job_entity.ts", "deprecated": false, "trackAdoption": false } @@ -3812,6 +3812,42 @@ } ] }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.entities.k8s.k8sServiceEntity", + "type": "Function", + "tags": [], + "label": "k8sServiceEntity", + "description": [], + "signature": [ + "({ schema, name, uid, clusterName, entityId, ...others }: { [key: string]: any; schema: ", + "Schema", + "; name: string; uid?: string | undefined; clusterName?: string | undefined; entityId: string; }) => ", + "K8sEntity" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/entities/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.entities.k8s.k8sServiceEntity.$1", + "type": "Object", + "tags": [], + "label": "__0", + "description": [], + "signature": [ + "{ [key: string]: any; schema: ", + "Schema", + "; name: string; uid?: string | undefined; clusterName?: string | undefined; entityId: string; }" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/entities/kubernetes/service.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, { "parentPluginId": "@kbn/apm-synthtrace-client", "id": "def-common.entities.k8s.k8sContainerEntity", @@ -4167,6 +4203,34 @@ } ] }, + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.log.createForIndex", + "type": "Function", + "tags": [], + "label": "createForIndex", + "description": [], + "signature": [ + "(index: string) => Log" + ], + "path": "packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/apm-synthtrace-client", + "id": "def-common.log.createForIndex.$1", + "type": "string", + "tags": [], + "label": "index", + "description": [], + "path": "packages/kbn-apm-synthtrace-client/src/lib/logs/index.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, { "parentPluginId": "@kbn/apm-synthtrace-client", "id": "def-common.log.createMinimal", diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 313228821e9c..41bd4c9ae248 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/te | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 268 | 0 | 268 | 38 | +| 272 | 0 | 272 | 38 | ## Common diff --git a/api_docs/kbn_apm_types.mdx b/api_docs/kbn_apm_types.mdx index c63d8466e3e5..55b6b16418ba 100644 --- a/api_docs/kbn_apm_types.mdx +++ b/api_docs/kbn_apm_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-types title: "@kbn/apm-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-types'] --- import kbnApmTypesObj from './kbn_apm_types.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index a05d2191c088..4075db91aeeb 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_avc_banner.mdx b/api_docs/kbn_avc_banner.mdx index d5be6cc3f802..b601c38a6b6f 100644 --- a/api_docs/kbn_avc_banner.mdx +++ b/api_docs/kbn_avc_banner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-avc-banner title: "@kbn/avc-banner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/avc-banner plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/avc-banner'] --- import kbnAvcBannerObj from './kbn_avc_banner.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index d6441c0935d1..015b7e6fc465 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_bfetch_error.mdx b/api_docs/kbn_bfetch_error.mdx index 6bac3c36f2e3..b1f7af0142da 100644 --- a/api_docs/kbn_bfetch_error.mdx +++ b/api_docs/kbn_bfetch_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-bfetch-error title: "@kbn/bfetch-error" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/bfetch-error plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/bfetch-error'] --- import kbnBfetchErrorObj from './kbn_bfetch_error.devdocs.json'; diff --git a/api_docs/kbn_calculate_auto.mdx b/api_docs/kbn_calculate_auto.mdx index 378767a0a261..9aee2ea98ae3 100644 --- a/api_docs/kbn_calculate_auto.mdx +++ b/api_docs/kbn_calculate_auto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-auto title: "@kbn/calculate-auto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-auto plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-auto'] --- import kbnCalculateAutoObj from './kbn_calculate_auto.devdocs.json'; diff --git a/api_docs/kbn_calculate_width_from_char_count.mdx b/api_docs/kbn_calculate_width_from_char_count.mdx index 5e5de0c61abd..773c0ec8ab72 100644 --- a/api_docs/kbn_calculate_width_from_char_count.mdx +++ b/api_docs/kbn_calculate_width_from_char_count.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-calculate-width-from-char-count title: "@kbn/calculate-width-from-char-count" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/calculate-width-from-char-count plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/calculate-width-from-char-count'] --- import kbnCalculateWidthFromCharCountObj from './kbn_calculate_width_from_char_count.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 537ffa21830b..8b250e1427d2 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cbor.mdx b/api_docs/kbn_cbor.mdx index 6c60239b17d1..f4d4502cdc37 100644 --- a/api_docs/kbn_cbor.mdx +++ b/api_docs/kbn_cbor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cbor title: "@kbn/cbor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cbor plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cbor'] --- import kbnCborObj from './kbn_cbor.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 25c7ed965d45..0e297dede197 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index bdc7fc442028..a5e272dd9b74 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 5ced1454b662..8d943b0d72a6 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2024-11-22 +date: 2024-12-03 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 009d09a0a930..41b41e8befbf 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2024-11-22 +date: 2024-12-03 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 403fcf05888c..31077f7f5140 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2024-11-22 +date: 2024-12-03 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 6d1b326868d9..043bf8e005c2 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2024-11-22 +date: 2024-12-03 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 7f3afbd00868..aa15347482fc 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_cloud_security_posture.devdocs.json b/api_docs/kbn_cloud_security_posture.devdocs.json index 37cc79e0d28b..62f5fce1db93 100644 --- a/api_docs/kbn_cloud_security_posture.devdocs.json +++ b/api_docs/kbn_cloud_security_posture.devdocs.json @@ -270,7 +270,7 @@ "label": "getVulnerabilityStats", "description": [], "signature": [ - "(counts: VulnerabilityCounts) => VulnerabilitiesDistributionBarProps[]" + "(counts: VulnerabilityCounts, filterFunction?: ((filter: string) => void) | undefined, currentFilter?: string | undefined) => VulnerabilitiesDistributionBarProps[]" ], "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts", "deprecated": false, @@ -290,6 +290,36 @@ "deprecated": false, "trackAdoption": false, "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.getVulnerabilityStats.$2", + "type": "Function", + "tags": [], + "label": "filterFunction", + "description": [], + "signature": [ + "((filter: string) => void) | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.getVulnerabilityStats.$3", + "type": "string", + "tags": [], + "label": "currentFilter", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], @@ -444,9 +474,9 @@ "label": "query", "description": [], "signature": [ - "{ bool: { filter: ", + "{ bool: { filter: (", "QueryDslQueryContainer", - "[]; }; } | undefined" + " | undefined)[] | undefined; }; } | undefined" ], "path": "x-pack/packages/kbn-cloud-security-posture/public/src/types.ts", "deprecated": false, @@ -1042,6 +1072,21 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.HOST_NAME", + "type": "string", + "tags": [], + "label": "HOST_NAME", + "description": [], + "signature": [ + "\"host.name\"" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture", "id": "def-public.LatestFindingsRequest", @@ -1120,6 +1165,21 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture", + "id": "def-public.USER_NAME", + "type": "string", + "tags": [], + "label": "USER_NAME", + "description": [], + "signature": [ + "\"user.name\"" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [ diff --git a/api_docs/kbn_cloud_security_posture.mdx b/api_docs/kbn_cloud_security_posture.mdx index 040ddbb32d13..9a9ebb3ed96a 100644 --- a/api_docs/kbn_cloud_security_posture.mdx +++ b/api_docs/kbn_cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture title: "@kbn/cloud-security-posture" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture'] --- import kbnCloudSecurityPostureObj from './kbn_cloud_security_posture.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 89 | 1 | 89 | 0 | +| 93 | 1 | 93 | 0 | ## Client diff --git a/api_docs/kbn_cloud_security_posture_common.devdocs.json b/api_docs/kbn_cloud_security_posture_common.devdocs.json index 6c0ae2a2db8a..5e993b4e3c1f 100644 --- a/api_docs/kbn_cloud_security_posture_common.devdocs.json +++ b/api_docs/kbn_cloud_security_posture_common.devdocs.json @@ -129,13 +129,13 @@ "functions": [ { "parentPluginId": "@kbn/cloud-security-posture-common", - "id": "def-common.buildEntityFlyoutPreviewQuery", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery", "type": "Function", "tags": [], - "label": "buildEntityFlyoutPreviewQuery", + "label": "buildGenericEntityFlyoutPreviewQuery", "description": [], "signature": [ - "(field: string, queryValue?: string | undefined) => { bool: { filter: { bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; }[]; }; }" + "(field: string, queryValue?: string | undefined, status?: string | undefined, queryField?: string | undefined) => { bool: { filter: ({ bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; } | undefined)[]; }; }" ], "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", "deprecated": false, @@ -143,7 +143,7 @@ "children": [ { "parentPluginId": "@kbn/cloud-security-posture-common", - "id": "def-common.buildEntityFlyoutPreviewQuery.$1", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$1", "type": "string", "tags": [], "label": "field", @@ -158,7 +158,7 @@ }, { "parentPluginId": "@kbn/cloud-security-posture-common", - "id": "def-common.buildEntityFlyoutPreviewQuery.$2", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$2", "type": "string", "tags": [], "label": "queryValue", @@ -170,6 +170,99 @@ "deprecated": false, "trackAdoption": false, "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$3", + "type": "string", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildGenericEntityFlyoutPreviewQuery.$4", + "type": "string", + "tags": [], + "label": "queryField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery", + "type": "Function", + "tags": [], + "label": "buildMisconfigurationEntityFlyoutPreviewQuery", + "description": [], + "signature": [ + "(field: string, queryValue?: string | undefined, status?: string | undefined) => { bool: { filter: ({ bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; } | undefined)[]; }; }" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery.$1", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery.$2", + "type": "string", + "tags": [], + "label": "queryValue", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildMisconfigurationEntityFlyoutPreviewQuery.$3", + "type": "string", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false } ], "returnComment": [], @@ -210,6 +303,69 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery", + "type": "Function", + "tags": [], + "label": "buildVulnerabilityEntityFlyoutPreviewQuery", + "description": [], + "signature": [ + "(field: string, queryValue?: string | undefined, status?: string | undefined) => { bool: { filter: ({ bool: { should: { term: { [x: string]: string; }; }[]; minimum_should_match: number; }; } | undefined)[]; }; }" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery.$1", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery.$2", + "type": "string", + "tags": [], + "label": "queryValue", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.buildVulnerabilityEntityFlyoutPreviewQuery.$3", + "type": "string", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture-common", "id": "def-common.extractErrorMessage", @@ -1556,6 +1712,42 @@ } ], "objects": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.MISCONFIGURATION_STATUS", + "type": "Object", + "tags": [], + "label": "MISCONFIGURATION_STATUS", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.MISCONFIGURATION_STATUS.PASSED", + "type": "string", + "tags": [], + "label": "PASSED", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/common/constants.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/cloud-security-posture-common", + "id": "def-common.MISCONFIGURATION_STATUS.FAILED", + "type": "string", + "tags": [], + "label": "FAILED", + "description": [], + "path": "x-pack/packages/kbn-cloud-security-posture/common/constants.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/cloud-security-posture-common", "id": "def-common.VULNERABILITIES_SEVERITY", diff --git a/api_docs/kbn_cloud_security_posture_common.mdx b/api_docs/kbn_cloud_security_posture_common.mdx index 8a25054cc686..0c9d0ce05e98 100644 --- a/api_docs/kbn_cloud_security_posture_common.mdx +++ b/api_docs/kbn_cloud_security_posture_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-common title: "@kbn/cloud-security-posture-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-common'] --- import kbnCloudSecurityPostureCommonObj from './kbn_cloud_security_posture_common.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 109 | 0 | 107 | 1 | +| 122 | 0 | 120 | 1 | ## Common diff --git a/api_docs/kbn_cloud_security_posture_graph.mdx b/api_docs/kbn_cloud_security_posture_graph.mdx index 877ed9e162ef..5bdb2f292236 100644 --- a/api_docs/kbn_cloud_security_posture_graph.mdx +++ b/api_docs/kbn_cloud_security_posture_graph.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cloud-security-posture-graph title: "@kbn/cloud-security-posture-graph" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cloud-security-posture-graph plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cloud-security-posture-graph'] --- import kbnCloudSecurityPostureGraphObj from './kbn_cloud_security_posture_graph.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 3e40426381ea..5f2d76f06ed3 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mock.mdx b/api_docs/kbn_code_editor_mock.mdx index 09d5418473f9..4dfe3de38b27 100644 --- a/api_docs/kbn_code_editor_mock.mdx +++ b/api_docs/kbn_code_editor_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mock title: "@kbn/code-editor-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mock plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mock'] --- import kbnCodeEditorMockObj from './kbn_code_editor_mock.devdocs.json'; diff --git a/api_docs/kbn_code_owners.mdx b/api_docs/kbn_code_owners.mdx index 286833fc3fa6..77f579431d48 100644 --- a/api_docs/kbn_code_owners.mdx +++ b/api_docs/kbn_code_owners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-owners title: "@kbn/code-owners" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-owners plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-owners'] --- import kbnCodeOwnersObj from './kbn_code_owners.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index dc24d179f72c..040e0b7ca3ef 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2024-11-22 +date: 2024-12-03 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 e5408cb5acde..34eb1c16afdf 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2024-11-22 +date: 2024-12-03 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 e3dadc72f923..afdf13e4fd5b 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 40b415251d9c..b7f38ac879ff 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index 0e9d4232ecee..7cc97347d095 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_public.mdx b/api_docs/kbn_content_management_content_insights_public.mdx index c44b78488217..1c4b45969fae 100644 --- a/api_docs/kbn_content_management_content_insights_public.mdx +++ b/api_docs/kbn_content_management_content_insights_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-public title: "@kbn/content-management-content-insights-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-public plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-public'] --- import kbnContentManagementContentInsightsPublicObj from './kbn_content_management_content_insights_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_insights_server.mdx b/api_docs/kbn_content_management_content_insights_server.mdx index 0fb1a295d156..314fa216d2a1 100644 --- a/api_docs/kbn_content_management_content_insights_server.mdx +++ b/api_docs/kbn_content_management_content_insights_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-insights-server title: "@kbn/content-management-content-insights-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-insights-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-insights-server'] --- import kbnContentManagementContentInsightsServerObj from './kbn_content_management_content_insights_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_common.mdx b/api_docs/kbn_content_management_favorites_common.mdx index 9b902ca15848..0d3aa9f0fb62 100644 --- a/api_docs/kbn_content_management_favorites_common.mdx +++ b/api_docs/kbn_content_management_favorites_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-common title: "@kbn/content-management-favorites-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-common'] --- import kbnContentManagementFavoritesCommonObj from './kbn_content_management_favorites_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_public.mdx b/api_docs/kbn_content_management_favorites_public.mdx index 7eb75aa66504..7e40607b21fa 100644 --- a/api_docs/kbn_content_management_favorites_public.mdx +++ b/api_docs/kbn_content_management_favorites_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-public title: "@kbn/content-management-favorites-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-public plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-public'] --- import kbnContentManagementFavoritesPublicObj from './kbn_content_management_favorites_public.devdocs.json'; diff --git a/api_docs/kbn_content_management_favorites_server.mdx b/api_docs/kbn_content_management_favorites_server.mdx index 5c172cd20836..052d931d97f9 100644 --- a/api_docs/kbn_content_management_favorites_server.mdx +++ b/api_docs/kbn_content_management_favorites_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-favorites-server title: "@kbn/content-management-favorites-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-favorites-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-favorites-server'] --- import kbnContentManagementFavoritesServerObj from './kbn_content_management_favorites_server.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index 2ed330e10839..95a87f1b9637 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index eef9d63222bb..ade0488c0667 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_common.mdx b/api_docs/kbn_content_management_table_list_view_common.mdx index e29d9a67be0e..824bf9224c81 100644 --- a/api_docs/kbn_content_management_table_list_view_common.mdx +++ b/api_docs/kbn_content_management_table_list_view_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-common title: "@kbn/content-management-table-list-view-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-common'] --- import kbnContentManagementTableListViewCommonObj from './kbn_content_management_table_list_view_common.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index 0c275a5216b3..25ecb50b3687 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_user_profiles.mdx b/api_docs/kbn_content_management_user_profiles.mdx index 5c7d6109f24b..f1aaaeba258f 100644 --- a/api_docs/kbn_content_management_user_profiles.mdx +++ b/api_docs/kbn_content_management_user_profiles.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-user-profiles title: "@kbn/content-management-user-profiles" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-user-profiles plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-user-profiles'] --- import kbnContentManagementUserProfilesObj from './kbn_content_management_user_profiles.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index 6300345f4913..658e6502f3e5 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.devdocs.json b/api_docs/kbn_core_analytics_browser.devdocs.json index 2f2c5fc3f3d9..d9e9918f342d 100644 --- a/api_docs/kbn_core_analytics_browser.devdocs.json +++ b/api_docs/kbn_core_analytics_browser.devdocs.json @@ -942,6 +942,10 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "observabilityLogsExplorer", "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" @@ -1398,6 +1402,14 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 8066df24b148..bb1cb25cb221 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 c4ab538354e0..1b61f04d13f1 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 787f96a0c690..bdc4764b131b 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.devdocs.json b/api_docs/kbn_core_analytics_server.devdocs.json index fe50bcb0679d..f551b259301d 100644 --- a/api_docs/kbn_core_analytics_server.devdocs.json +++ b/api_docs/kbn_core_analytics_server.devdocs.json @@ -950,6 +950,10 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts" + }, { "plugin": "observabilityLogsExplorer", "path": "x-pack/plugins/observability_solution/observability_logs_explorer/public/state_machines/observability_logs_explorer/src/telemetry_events.ts" @@ -1406,6 +1410,14 @@ "plugin": "inventory", "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, + { + "plugin": "inventory", + "path": "x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/public/common/lib/telemetry/telemetry_service.test.ts" diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 64f8a813599e..6e3572328aa3 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2024-11-22 +date: 2024-12-03 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 8fd61324c638..55c716c5195c 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 4e81c9fe4104..1dc3b7ced43b 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 8bdf56b2ba97..385b70eab182 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 6391b315d4e0..c93e1d6b36b2 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 a96be3b8182b..d2eee2647ac0 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 8b333782ee6b..15b69d35fb42 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2024-11-22 +date: 2024-12-03 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 4b2145272c5a..f4a263b70200 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 f18dc0bf8820..d11bf0ef2554 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index 20d7fb801dfb..9e6309e566ad 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 38a155881695..e70df86ee3ed 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 7e595442d34a..f4e6af94f037 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2024-11-22 +date: 2024-12-03 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 1b016542fa81..59b22026793a 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 9445c455a8ef..227ed73b3c16 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 dca19153744f..ff91510acfaf 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 f4c0f99be42c..6658412504cf 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2024-11-22 +date: 2024-12-03 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 581e17975192..6f6f9b67f471 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2024-11-22 +date: 2024-12-03 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 6a1da1b91387..a0c45fad5a71 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.devdocs.json b/api_docs/kbn_core_chrome_browser.devdocs.json index 31736959b737..acc96d2631c6 100644 --- a/api_docs/kbn_core_chrome_browser.devdocs.json +++ b/api_docs/kbn_core_chrome_browser.devdocs.json @@ -3765,7 +3765,7 @@ "label": "AppDeepLinkId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"serverlessWebCrawlers\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"streams\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"serverlessWebCrawlers\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"streams:overview\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:siem_migrations-rules\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "packages/core/chrome/core-chrome-browser/src/project_navigation.ts", "deprecated": false, diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index 60c336387a83..ae8118d69b16 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 64bfefe8200f..4d87b9bf64a0 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 797ced21bcbb..19132ba78af5 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 12a629a41e83..3e877454b83c 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 906b5decbe13..bd98ce434b95 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 4eb19bfa0705..6c9eff9988d3 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index b09d7943d5e5..68beb9c6ae3d 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 65eb63f52cbd..372cdd0b4ec5 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index 8778fa1bc6bf..7942915dc597 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index ef7dfa5b8775..c259b64cbf3f 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index 735de0b33963..90fe4f7840cc 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 18ffa846a324..60fbb3615447 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 625b11d576d1..e3a4f3069d9d 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 7b9ab629c8fb..175356815a82 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2024-11-22 +date: 2024-12-03 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 1ab77326a814..b2daa0f91760 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2024-11-22 +date: 2024-12-03 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 c912fe5b5d62..bd55fd32f899 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 751a323909db..cfb99447d5ff 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 6a57d0519db6..fa541c8101c4 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 34b77855ba91..6abfb4f6ef16 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 0fdc6f9719ea..b8f98e965cf0 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2024-11-22 +date: 2024-12-03 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 085522317673..2a9917b2c125 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index c4714af61deb..dd669241d943 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index d766c3daecf7..c9f33864366f 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 27fcdd39a6be..2a2f8f06c4a2 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2024-11-22 +date: 2024-12-03 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 023dac9acf34..8893dc1cb951 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 004e1275a4fc..79c5a3739384 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 199363dcfdb9..e99acf6a3e67 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 a62a424f303a..96cd751aff25 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 fc14dc5b6143..cb4aca1b4099 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 167d120d06f7..513da8162935 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 0057708b10e6..7967bb82da0d 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 585737e1770e..0f608a0690c9 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2024-11-22 +date: 2024-12-03 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 60205be760d1..7328a307f125 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2024-11-22 +date: 2024-12-03 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 1b069ef1c955..1fa7cfaf1d56 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 309c1a3e11dc..8209391797eb 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 2c1089adcc9e..26e88146b34c 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 9c0a53358e05..a875baf15e78 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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_feature_flags_browser.mdx b/api_docs/kbn_core_feature_flags_browser.mdx index 7368b89dd829..42fa72a88396 100644 --- a/api_docs/kbn_core_feature_flags_browser.mdx +++ b/api_docs/kbn_core_feature_flags_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser title: "@kbn/core-feature-flags-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser'] --- import kbnCoreFeatureFlagsBrowserObj from './kbn_core_feature_flags_browser.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_internal.mdx b/api_docs/kbn_core_feature_flags_browser_internal.mdx index 7c97ea63d7a3..d217d041e47f 100644 --- a/api_docs/kbn_core_feature_flags_browser_internal.mdx +++ b/api_docs/kbn_core_feature_flags_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-internal title: "@kbn/core-feature-flags-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-internal'] --- import kbnCoreFeatureFlagsBrowserInternalObj from './kbn_core_feature_flags_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_browser_mocks.mdx b/api_docs/kbn_core_feature_flags_browser_mocks.mdx index a5ff3696e75b..f0e6419529ce 100644 --- a/api_docs/kbn_core_feature_flags_browser_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-browser-mocks title: "@kbn/core-feature-flags-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-browser-mocks'] --- import kbnCoreFeatureFlagsBrowserMocksObj from './kbn_core_feature_flags_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server.mdx b/api_docs/kbn_core_feature_flags_server.mdx index 9df543abcaaf..7407052fffac 100644 --- a/api_docs/kbn_core_feature_flags_server.mdx +++ b/api_docs/kbn_core_feature_flags_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server title: "@kbn/core-feature-flags-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server'] --- import kbnCoreFeatureFlagsServerObj from './kbn_core_feature_flags_server.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_internal.mdx b/api_docs/kbn_core_feature_flags_server_internal.mdx index 03a42bc8e1e1..8de24625d29c 100644 --- a/api_docs/kbn_core_feature_flags_server_internal.mdx +++ b/api_docs/kbn_core_feature_flags_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-internal title: "@kbn/core-feature-flags-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-internal'] --- import kbnCoreFeatureFlagsServerInternalObj from './kbn_core_feature_flags_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_feature_flags_server_mocks.mdx b/api_docs/kbn_core_feature_flags_server_mocks.mdx index 11b0f6da49b2..8e1c60b0e122 100644 --- a/api_docs/kbn_core_feature_flags_server_mocks.mdx +++ b/api_docs/kbn_core_feature_flags_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-feature-flags-server-mocks title: "@kbn/core-feature-flags-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-feature-flags-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-feature-flags-server-mocks'] --- import kbnCoreFeatureFlagsServerMocksObj from './kbn_core_feature_flags_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 845dc7df523a..4f05da87b338 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 89710d3c5179..76025554376d 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 2c8ce91d1a9e..2ed650549272 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 2008264f1fd5..76e5bf1c2614 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2024-11-22 +date: 2024-12-03 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 37646c5adb93..e5f33881d9b3 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 53b0a7d48172..f4855ca0d616 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index e050f814b530..1997e4cc5eec 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index cf072f090712..efbdec67cab4 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index bbf8c3602a57..c852a9402ddf 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.devdocs.json b/api_docs/kbn_core_http_router_server_internal.devdocs.json index 219635cec955..37b9e5a564b6 100644 --- a/api_docs/kbn_core_http_router_server_internal.devdocs.json +++ b/api_docs/kbn_core_http_router_server_internal.devdocs.json @@ -179,7 +179,7 @@ }, "<", "Method", - ">, \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ">, \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -266,7 +266,7 @@ }, "<", "Method", - ">, \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ">, \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -353,7 +353,7 @@ }, "<", "Method", - ">, \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ">, \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -440,7 +440,7 @@ }, "<", "Method", - ">, \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ">, \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -527,7 +527,7 @@ }, "<", "Method", - ">, \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ">, \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 78a39b33d84f..cbeafe319ddc 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_core_http_router_server_mocks.devdocs.json index df244e8c6f8c..f32d02105856 100644 --- a/api_docs/kbn_core_http_router_server_mocks.devdocs.json +++ b/api_docs/kbn_core_http_router_server_mocks.devdocs.json @@ -72,7 +72,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 2d72bb71c1b3..2b867d2b8ad3 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index cf76b2a6b8cf..e00fe9fba4ed 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -5125,6 +5125,10 @@ "plugin": "@kbn/core-http-router-server-internal", "path": "packages/core/http/core-http-router-server-internal/src/router.test.ts" }, + { + "plugin": "@kbn/core-http-router-server-internal", + "path": "packages/core/http/core-http-router-server-internal/src/router.test.ts" + }, { "plugin": "@kbn/core-http-server-internal", "path": "packages/core/http/core-http-server-internal/src/http_server.test.ts" @@ -5449,6 +5453,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/find.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/find.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get.test.ts" @@ -5473,6 +5481,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/get.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts" @@ -5509,6 +5525,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/health.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/health.test.ts" @@ -5565,6 +5589,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts" + }, { "plugin": "remoteClusters", "path": "x-pack/plugins/remote_clusters/server/routes/api/get_route.test.ts" @@ -6751,6 +6779,10 @@ "plugin": "indexManagement", "path": "x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts" }, + { + "plugin": "indexManagement", + "path": "x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts" + }, { "plugin": "indexManagement", "path": "x-pack/plugins/index_management/server/routes/api/indices/register_clear_cache_route.ts" @@ -7443,6 +7475,10 @@ "plugin": "serverlessSearch", "path": "x-pack/plugins/serverless_search/server/routes/connectors_routes.ts" }, + { + "plugin": "serverlessSearch", + "path": "x-pack/plugins/serverless_search/server/routes/connectors_routes.ts" + }, { "plugin": "snapshotRestore", "path": "x-pack/plugins/snapshot_restore/server/routes/api/repositories.ts" @@ -7867,6 +7903,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/create.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/create.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/disable.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/disable.test.ts" @@ -7899,6 +7943,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/enable.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/enable.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts" @@ -7931,6 +7983,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts" @@ -7947,6 +8003,14 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts" + }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts" @@ -7979,6 +8043,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts" + }, { "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/suggestions/fileds_rule.test.ts" @@ -9121,6 +9189,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/update.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/update.test.ts" + }, { "plugin": "remoteClusters", "path": "x-pack/plugins/remote_clusters/server/routes/api/update_route.test.ts" @@ -10005,6 +10077,10 @@ "plugin": "alerting", "path": "x-pack/plugins/alerting/server/routes/legacy/delete.test.ts" }, + { + "plugin": "alerting", + "path": "x-pack/plugins/alerting/server/routes/legacy/delete.test.ts" + }, { "plugin": "remoteClusters", "path": "x-pack/plugins/remote_clusters/server/routes/api/delete_route.test.ts" @@ -11569,12 +11645,12 @@ { "parentPluginId": "@kbn/core-http-server", "id": "def-server.KibanaRequestRoute.options", - "type": "Uncategorized", + "type": "CompoundType", "tags": [], "label": "options", "description": [], "signature": [ - "Method extends \"get\" | \"options\" ? Required>" + ">) & { security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; }" ], "path": "packages/core/http/core-http-server/src/router/request.ts", "deprecated": false, @@ -13415,29 +13499,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "@kbn/core-http-server", - "id": "def-server.RouteConfigOptions.security", - "type": "Object", - "tags": [], - "label": "security", - "description": [ - "\nDefines the security requirements for a route, including authorization and authentication.\n" - ], - "signature": [ - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.RouteSecurity", - "text": "RouteSecurity" - }, - " | undefined" - ], - "path": "packages/core/http/core-http-server/src/router/route.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "@kbn/core-http-server", "id": "def-server.RouteConfigOptions.httpResource", @@ -16323,7 +16384,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -16654,7 +16715,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -17602,6 +17663,14 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/resources/upsert.ts" }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install.ts" + }, + { + "plugin": "securitySolution", + "path": "x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install_translated.ts" + }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/actions/response_actions.ts" @@ -17694,10 +17763,6 @@ "plugin": "dataUsage", "path": "x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts" }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stats.ts" - }, { "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts" @@ -17821,7 +17886,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -17968,7 +18033,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -18267,7 +18332,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -18440,7 +18505,7 @@ "section": "def-server.RouteMethod", "text": "RouteMethod" }, - ">, \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; security?: ", + ">, \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; security?: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -19363,7 +19428,7 @@ "\nRoute options: If 'GET' or 'OPTIONS' method, body options won't be returned." ], "signature": [ - "Method extends \"get\" | \"options\" ? Required>" + ">) & { security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; }" ], "path": "packages/core/http/core-http-server/src/router/request.ts", "deprecated": false, @@ -20762,7 +20835,7 @@ "\nThe set of supported parseable Content-Types" ], "signature": [ - "\"application/json\" | \"multipart/form-data\" | \"application/*+json\" | \"application/octet-stream\" | \"application/x-www-form-urlencoded\" | \"text/*\"" + "\"application/json\" | \"application/*+json\" | \"application/octet-stream\" | \"application/x-www-form-urlencoded\" | \"multipart/form-data\" | \"text/*\"" ], "path": "packages/core/http/core-http-server/src/router/route.ts", "deprecated": false, @@ -21358,7 +21431,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -21442,7 +21515,7 @@ "section": "def-server.RouteConfigOptions", "text": "RouteConfigOptions" }, - ", \"security\" | \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", + ", \"description\" | \"summary\" | \"deprecated\" | \"access\" | \"discontinued\"> | undefined; access: ", { "pluginId": "@kbn/core-http-server", "scope": "server", diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 55a02fb53929..b708669c2e29 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 568 | 2 | 242 | 0 | +| 567 | 2 | 242 | 0 | ## Server diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 5923b686ebff..d65f99fef2e3 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 ee7452986953..d1ad90e098d7 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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_http_server_utils.devdocs.json b/api_docs/kbn_core_http_server_utils.devdocs.json new file mode 100644 index 000000000000..176980e37b08 --- /dev/null +++ b/api_docs/kbn_core_http_server_utils.devdocs.json @@ -0,0 +1,186 @@ +{ + "id": "@kbn/core-http-server-utils", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/core-http-server-utils", + "id": "def-server.isCoreKibanaRequest", + "type": "Function", + "tags": [], + "label": "isCoreKibanaRequest", + "description": [], + "signature": [ + "(req: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + ") => boolean" + ], + "path": "packages/core/http/core-http-server-utils/src/request.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-server-utils", + "id": "def-server.isCoreKibanaRequest.$1", + "type": "Object", + "tags": [], + "label": "req", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "packages/core/http/core-http-server-utils/src/request.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/core-http-server-utils", + "id": "def-server.kibanaRequestFactory", + "type": "Function", + "tags": [], + "label": "kibanaRequestFactory", + "description": [ + "\nAllows building a KibanaRequest from a RawRequest, leveraging internal CoreKibanaRequest." + ], + "signature": [ + "(req: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RawRequest", + "text": "RawRequest" + }, + ", routeSchemas: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteValidator", + "text": "RouteValidator" + }, + " | undefined, withoutSecretHeaders: boolean) => ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.KibanaRequest", + "text": "KibanaRequest" + }, + "" + ], + "path": "packages/core/http/core-http-server-utils/src/request.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/core-http-server-utils", + "id": "def-server.kibanaRequestFactory.$1", + "type": "CompoundType", + "tags": [], + "label": "req", + "description": [ + "The raw request to build from" + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RawRequest", + "text": "RawRequest" + } + ], + "path": "packages/core/http/core-http-server-utils/src/request.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/core-http-server-utils", + "id": "def-server.kibanaRequestFactory.$2", + "type": "CompoundType", + "tags": [], + "label": "routeSchemas", + "description": [ + "The route schemas" + ], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteValidator", + "text": "RouteValidator" + }, + " | undefined" + ], + "path": "packages/core/http/core-http-server-utils/src/request.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/core-http-server-utils", + "id": "def-server.kibanaRequestFactory.$3", + "type": "boolean", + "tags": [], + "label": "withoutSecretHeaders", + "description": [ + "Whether we want to exclude secret headers" + ], + "signature": [ + "boolean" + ], + "path": "packages/core/http/core-http-server-utils/src/request.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "A KibanaRequest object" + ], + "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_http_server_utils.mdx b/api_docs/kbn_core_http_server_utils.mdx new file mode 100644 index 000000000000..6633aca139c1 --- /dev/null +++ b/api_docs/kbn_core_http_server_utils.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: kibKbnCoreHttpServerUtilsPluginApi +slug: /kibana-dev-docs/api/kbn-core-http-server-utils +title: "@kbn/core-http-server-utils" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/core-http-server-utils plugin +date: 2024-12-03 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-utils'] +--- +import kbnCoreHttpServerUtilsObj from './kbn_core_http_server_utils.devdocs.json'; + + + +Contact [@elastic/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 | +|-------------------|-----------|------------------------|-----------------| +| 6 | 0 | 2 | 0 | + +## Server + +### Functions + + diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index dbc324bbe189..5567e2a5af4c 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 f89489a201ac..6cfea71eaffb 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 9d28299f569b..d743f16279ba 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2024-11-22 +date: 2024-12-03 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 7cde6c4bbe2a..7adde615137c 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 567361809f5f..0ac752131d67 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index b0a5c82a6566..d8926d7c3e3f 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 3753b5e3f2a3..8f9c96d1b082 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 1310da82e234..e8c551ba6970 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 9238d56eca72..2e3e60c740e8 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 3a740d0f2046..2b98c841824b 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index dd50f8a26b1f..81363e2d8c60 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index 762ef3237137..1efc5ce8cec4 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index 06e3c60cc555..6be2aa265a4a 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index 489343ba64ef..b461602b7cf9 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index 295626f7fe85..267c8ca7ec06 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2024-11-22 +date: 2024-12-03 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 7d353d5470da..dd391bef6167 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 968515173c25..2c1d89369c26 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 0c861fac84ae..e92dbb42156e 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index a72eb5aaa90a..7467c3c278ff 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index a2800ad4b1eb..f97db3c3c112 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index c46d6130dd92..1091e8d8ae9f 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index 7dece8d9fbc3..0b2667b4756a 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 788278bd5ebc..97030cbe9dee 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 a3e0ddba64e2..aef8e3db6898 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2024-11-22 +date: 2024-12-03 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 4f8ded8e32bd..0159d8b222d2 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 b8fc3e4bff22..ca934e7d7fc9 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 a2c46f685f5e..53e4db7c561b 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 d90dcde8d4a9..b2e1537228cc 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 591ebec8dad8..23c2274e15a3 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 6c5ec3b332e5..50ac9d4b57cc 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 ddfe408b0bc0..d07a99390dc3 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 a981f3eadbfa..75124a902a56 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 676135236e92..783da4ddb53f 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 aed3d739273f..f92668accf93 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index 8a3a4b3e4bb5..3443582ec645 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 020659f3e675..cafbdd0dbdfe 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index a39ab5801b0d..21b9b4a11bd1 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 2c566d009301..d1ddd23bceba 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 680b0f497153..d967299d7f00 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2024-11-22 +date: 2024-12-03 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 64cd252ea3c6..6651f38621fb 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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.mdx b/api_docs/kbn_core_rendering_browser.mdx index a6ecbed43a4a..40bc8f495cf7 100644 --- a/api_docs/kbn_core_rendering_browser.mdx +++ b/api_docs/kbn_core_rendering_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser title: "@kbn/core-rendering-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser'] --- import kbnCoreRenderingBrowserObj from './kbn_core_rendering_browser.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index a4b8405f0a0b..45b2d207b252 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index a549d050f2b2..67d55f3ecc1f 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index 42204498ed59..d0577d2523b3 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 8be54d877345..d9714266c585 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 5f6b42c52fd8..f3cbde1178c1 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index ee4927c9ac6a..f678ab1ec3d6 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index e4d8d1c21f94..493afd439a82 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 f55accdd3da1..aba0c61c2614 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 99e8fff16012..d9ca3c27db3d 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 318a99173832..75f59d353648 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 d76859769d88..68a5fee7c690 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 733f73af32a8..e615bec13081 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_core_saved_objects_common.devdocs.json index 4df24e4d3b7f..63ae4b1d1ff3 100644 --- a/api_docs/kbn_core_saved_objects_common.devdocs.json +++ b/api_docs/kbn_core_saved_objects_common.devdocs.json @@ -1906,18 +1906,6 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/persistence/saved_object_store.ts" }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/state_management/selectors.ts" - }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/state_management/selectors.ts" - }, - { - "plugin": "lens", - "path": "x-pack/plugins/lens/public/state_management/selectors.ts" - }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts" @@ -2046,6 +2034,14 @@ "plugin": "lens", "path": "x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx" }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts" + }, { "plugin": "lens", "path": "x-pack/plugins/lens/public/types.ts" @@ -2388,11 +2384,23 @@ }, { "plugin": "lens", - "path": "x-pack/plugins/lens/common/embeddable_factory/index.ts" + "path": "x-pack/plugins/lens/public/react_embeddable/helper.ts" }, { "plugin": "lens", - "path": "x-pack/plugins/lens/common/embeddable_factory/index.ts" + "path": "x-pack/plugins/lens/public/react_embeddable/helper.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/lens_attribute_service.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/lens_attribute_service.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/lens_attribute_service.ts" }, { "plugin": "controls", diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index f96ce7559d8f..4af0177f5296 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2024-11-22 +date: 2024-12-03 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 bfece7777364..22704341fa3f 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 79142154da82..5137325e5f25 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 2873a2347baa..9c1431826cd1 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 4b2d2d94fbb6..43b6f9c7ca40 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.devdocs.json b/api_docs/kbn_core_saved_objects_server.devdocs.json index b64f85ca1c4e..ba262035a1c0 100644 --- a/api_docs/kbn_core_saved_objects_server.devdocs.json +++ b/api_docs/kbn_core_saved_objects_server.devdocs.json @@ -10539,7 +10539,7 @@ ], "label": "migrations", "description": [ - "\nAn optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of {@link SavedObjectMigrationFn | migrations} to be used to migrate the type." + "\nAn optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of\n{@link SavedObjectMigrationFn | migrations} to be used to migrate the type.\n" ], "signature": [ { @@ -11445,7 +11445,7 @@ ], "label": "convertToMultiNamespaceTypeVersion", "description": [ - "\nIf defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to this\nversion.\n\nRequirements:\n\n 1. This string value must be a valid semver version\n 2. This type must have previously specified {@link SavedObjectsNamespaceType | `namespaceType: 'single'`}\n 3. This type must also specify {@link SavedObjectsNamespaceType | `namespaceType: 'multiple'`} *or*\n {@link SavedObjectsNamespaceType | `namespaceType: 'multiple-isolated'`}\n\nExample of a single-namespace type in 7.12:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'single',\n mappings: {...}\n}\n```\n\nExample after converting to a multi-namespace (isolated) type in 8.0:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple-isolated',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nExample after converting to a multi-namespace (shareable) type in 8.1:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nNote: migration function(s) can be optionally specified for any of these versions and will not interfere with the conversion process." + "\nIf defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to\nthis version.\n\nRequirements:\n\n 1. This string value must be a valid semver version\n 2. This type must have previously specified {@link SavedObjectsNamespaceType | `namespaceType: 'single'`}\n 3. This type must also specify {@link SavedObjectsNamespaceType | `namespaceType: 'multiple'`} *or*\n {@link SavedObjectsNamespaceType | `namespaceType: 'multiple-isolated'`}\n\nExample of a single-namespace type in 7.12:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'single',\n mappings: {...}\n}\n```\n\nExample after converting to a multi-namespace (isolated) type in 8.0:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple-isolated',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nExample after converting to a multi-namespace (shareable) type in 8.1:\n\n```ts\n{\n name: 'foo',\n hidden: false,\n namespaceType: 'multiple',\n mappings: {...},\n convertToMultiNamespaceTypeVersion: '8.0.0'\n}\n```\n\nNote: migration function(s) can be optionally specified for any of these versions and will not interfere with the conversion process." ], "signature": [ "string | undefined" diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 92591e051185..fb9b79f4816e 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2024-11-22 +date: 2024-12-03 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 810ae8217ea1..017493d5617a 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 30e04a0e456a..9659a6fe1e22 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 4f8766de1d80..ae7cb4a7add0 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser.mdx b/api_docs/kbn_core_security_browser.mdx index 0d22011dabba..08620be02169 100644 --- a/api_docs/kbn_core_security_browser.mdx +++ b/api_docs/kbn_core_security_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser title: "@kbn/core-security-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser'] --- import kbnCoreSecurityBrowserObj from './kbn_core_security_browser.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_internal.mdx b/api_docs/kbn_core_security_browser_internal.mdx index e5352aebc03c..6361b016784a 100644 --- a/api_docs/kbn_core_security_browser_internal.mdx +++ b/api_docs/kbn_core_security_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-internal title: "@kbn/core-security-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-internal'] --- import kbnCoreSecurityBrowserInternalObj from './kbn_core_security_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_browser_mocks.mdx b/api_docs/kbn_core_security_browser_mocks.mdx index f8e9a2bbb9e5..624b0a5d0b12 100644 --- a/api_docs/kbn_core_security_browser_mocks.mdx +++ b/api_docs/kbn_core_security_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-browser-mocks title: "@kbn/core-security-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-browser-mocks'] --- import kbnCoreSecurityBrowserMocksObj from './kbn_core_security_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_security_common.mdx b/api_docs/kbn_core_security_common.mdx index c02feef9f417..386ddb30bdac 100644 --- a/api_docs/kbn_core_security_common.mdx +++ b/api_docs/kbn_core_security_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-common title: "@kbn/core-security-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-common'] --- import kbnCoreSecurityCommonObj from './kbn_core_security_common.devdocs.json'; diff --git a/api_docs/kbn_core_security_server.mdx b/api_docs/kbn_core_security_server.mdx index 4271b39139b0..b2215891233a 100644 --- a/api_docs/kbn_core_security_server.mdx +++ b/api_docs/kbn_core_security_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server title: "@kbn/core-security-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server'] --- import kbnCoreSecurityServerObj from './kbn_core_security_server.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_internal.mdx b/api_docs/kbn_core_security_server_internal.mdx index 399342f82e6e..a644a1c8d408 100644 --- a/api_docs/kbn_core_security_server_internal.mdx +++ b/api_docs/kbn_core_security_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-internal title: "@kbn/core-security-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-internal'] --- import kbnCoreSecurityServerInternalObj from './kbn_core_security_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_security_server_mocks.mdx b/api_docs/kbn_core_security_server_mocks.mdx index 2f4ed482a6b6..b8afb11f52fa 100644 --- a/api_docs/kbn_core_security_server_mocks.mdx +++ b/api_docs/kbn_core_security_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-security-server-mocks title: "@kbn/core-security-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-security-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-security-server-mocks'] --- import kbnCoreSecurityServerMocksObj from './kbn_core_security_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 8ad680899b13..e1475a8b1af0 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2024-11-22 +date: 2024-12-03 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_server.mdx b/api_docs/kbn_core_status_server.mdx index 4f64deccda68..3ffe739dcf1a 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2024-11-22 +date: 2024-12-03 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 57628ec13400..2d0c5252744c 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 7d3fe8ff0d57..f5b5471a7cbf 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 d6ac39218d2a..21176f25ee98 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2024-11-22 +date: 2024-12-03 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 b2ff8153abec..affb67dfd35a 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index a120e6dae99f..e1e74dd173f0 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index 30c2ada98beb..4ae54cd255a1 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index c54812e7aa71..b7360eaa5643 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 86af71bd5057..ef14e3924099 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index cbb2a3c6fc8e..90c38d173fec 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index 8e3974864c78..6a69407ce5f0 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 064141c14e38..ec4e3e5b92bf 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2024-11-22 +date: 2024-12-03 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 b251038a2046..1a262c962c2c 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 acddb2e6c889..a7ee3280341a 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 017f50bd2f57..37d3a023d3fc 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2024-11-22 +date: 2024-12-03 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 3a54b1f77ae6..5ca0c3bf77fe 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2024-11-22 +date: 2024-12-03 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 a55568434309..4cad5e086158 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 e4315a19ad0c..d103bb0c7d6f 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 d9722b63339e..fdfe69358693 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2024-11-22 +date: 2024-12-03 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 47123344da9b..cb8a524ee13c 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 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 4acc4b467c44..0d4fae499ec4 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser.mdx b/api_docs/kbn_core_user_profile_browser.mdx index d48ca72c2978..c1fcd5b094cc 100644 --- a/api_docs/kbn_core_user_profile_browser.mdx +++ b/api_docs/kbn_core_user_profile_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser title: "@kbn/core-user-profile-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser'] --- import kbnCoreUserProfileBrowserObj from './kbn_core_user_profile_browser.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_internal.mdx b/api_docs/kbn_core_user_profile_browser_internal.mdx index 3e27e905eeec..bef6c0ea9803 100644 --- a/api_docs/kbn_core_user_profile_browser_internal.mdx +++ b/api_docs/kbn_core_user_profile_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-internal title: "@kbn/core-user-profile-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-internal'] --- import kbnCoreUserProfileBrowserInternalObj from './kbn_core_user_profile_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_browser_mocks.mdx b/api_docs/kbn_core_user_profile_browser_mocks.mdx index fc2644c1c23d..4d890925ee07 100644 --- a/api_docs/kbn_core_user_profile_browser_mocks.mdx +++ b/api_docs/kbn_core_user_profile_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-browser-mocks title: "@kbn/core-user-profile-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-browser-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-browser-mocks'] --- import kbnCoreUserProfileBrowserMocksObj from './kbn_core_user_profile_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_common.mdx b/api_docs/kbn_core_user_profile_common.mdx index 03d21ce748b2..b39634e1c9b6 100644 --- a/api_docs/kbn_core_user_profile_common.mdx +++ b/api_docs/kbn_core_user_profile_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-common title: "@kbn/core-user-profile-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-common'] --- import kbnCoreUserProfileCommonObj from './kbn_core_user_profile_common.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server.mdx b/api_docs/kbn_core_user_profile_server.mdx index d14388399452..2c02b4fa2e39 100644 --- a/api_docs/kbn_core_user_profile_server.mdx +++ b/api_docs/kbn_core_user_profile_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server title: "@kbn/core-user-profile-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server'] --- import kbnCoreUserProfileServerObj from './kbn_core_user_profile_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_internal.mdx b/api_docs/kbn_core_user_profile_server_internal.mdx index d8b4ef2cf908..198f309fb2a6 100644 --- a/api_docs/kbn_core_user_profile_server_internal.mdx +++ b/api_docs/kbn_core_user_profile_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-internal title: "@kbn/core-user-profile-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-internal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-internal'] --- import kbnCoreUserProfileServerInternalObj from './kbn_core_user_profile_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_profile_server_mocks.mdx b/api_docs/kbn_core_user_profile_server_mocks.mdx index 944bc788bc82..c3fc8a4dca16 100644 --- a/api_docs/kbn_core_user_profile_server_mocks.mdx +++ b/api_docs/kbn_core_user_profile_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-profile-server-mocks title: "@kbn/core-user-profile-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-profile-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-profile-server-mocks'] --- import kbnCoreUserProfileServerMocksObj from './kbn_core_user_profile_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index 785269e9c6d0..7c4f2b3a3f3d 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index ca638a3d00c8..a33bf4c57ffe 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 20628c7a5eea..3cb164f04dcb 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2024-11-22 +date: 2024-12-03 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 f262bdbd51f1..d1979d309304 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_icons.mdx b/api_docs/kbn_custom_icons.mdx index 3a0d466045b2..af91c339c905 100644 --- a/api_docs/kbn_custom_icons.mdx +++ b/api_docs/kbn_custom_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-icons title: "@kbn/custom-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-icons plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-icons'] --- import kbnCustomIconsObj from './kbn_custom_icons.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index ff0bd8f80807..8655a577dea7 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 4a44abf43323..3f621be4e220 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_forge.mdx b/api_docs/kbn_data_forge.mdx index eba4a2cd58dc..2a3339618636 100644 --- a/api_docs/kbn_data_forge.mdx +++ b/api_docs/kbn_data_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-forge title: "@kbn/data-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-forge plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-forge'] --- import kbnDataForgeObj from './kbn_data_forge.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 43a8ba3b4506..6551b2268ad0 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_data_stream_adapter.mdx b/api_docs/kbn_data_stream_adapter.mdx index 29ccb7af1144..ebb7346d96d6 100644 --- a/api_docs/kbn_data_stream_adapter.mdx +++ b/api_docs/kbn_data_stream_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-stream-adapter title: "@kbn/data-stream-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-stream-adapter plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-stream-adapter'] --- import kbnDataStreamAdapterObj from './kbn_data_stream_adapter.devdocs.json'; diff --git a/api_docs/kbn_data_view_utils.mdx b/api_docs/kbn_data_view_utils.mdx index 739e5c9bb82d..79a9c2dbb7b0 100644 --- a/api_docs/kbn_data_view_utils.mdx +++ b/api_docs/kbn_data_view_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-view-utils title: "@kbn/data-view-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-view-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-view-utils'] --- import kbnDataViewUtilsObj from './kbn_data_view_utils.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 0cc3704e3fe3..1455bf677aff 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 6b637b5f6c63..b65be683d9a4 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index 97257aca63ef..54539c3301c1 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_fleet.mdx b/api_docs/kbn_deeplinks_fleet.mdx index 69468a10bd86..d3b9bb051e83 100644 --- a/api_docs/kbn_deeplinks_fleet.mdx +++ b/api_docs/kbn_deeplinks_fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-fleet title: "@kbn/deeplinks-fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-fleet plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-fleet'] --- import kbnDeeplinksFleetObj from './kbn_deeplinks_fleet.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index c6ef07bcbc11..7ae3d99853bd 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index 4ca9584912c0..a6b5fa3abb5b 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.devdocs.json b/api_docs/kbn_deeplinks_observability.devdocs.json index 09daeec62406..820e8efc49cb 100644 --- a/api_docs/kbn_deeplinks_observability.devdocs.json +++ b/api_docs/kbn_deeplinks_observability.devdocs.json @@ -857,7 +857,7 @@ "label": "AppId", "description": [], "signature": [ - "\"profiling\" | \"metrics\" | \"apm\" | \"synthetics\" | \"ux\" | \"logs\" | \"slo\" | \"observabilityAIAssistant\" | \"observability-overview\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\"" + "\"profiling\" | \"metrics\" | \"apm\" | \"synthetics\" | \"ux\" | \"logs\" | \"slo\" | \"observabilityAIAssistant\" | \"observability-overview\" | \"streams\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\"" ], "path": "packages/deeplinks/observability/deep_links.ts", "deprecated": false, @@ -938,7 +938,7 @@ "section": "def-common.AppId", "text": "AppId" }, - " | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\"" + " | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"streams:overview\"" ], "path": "packages/deeplinks/observability/deep_links.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index cfd4e5927761..af6d377e013d 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 0cbb4e082e5e..1a2a2cd9ef0c 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_security.devdocs.json b/api_docs/kbn_deeplinks_security.devdocs.json index 8378fc426d00..30343ed59fe1 100644 --- a/api_docs/kbn_deeplinks_security.devdocs.json +++ b/api_docs/kbn_deeplinks_security.devdocs.json @@ -58,7 +58,7 @@ "label": "DeepLinkId", "description": [], "signature": [ - "\"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\"" + "\"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:siem_migrations-rules\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\"" ], "path": "packages/deeplinks/security/index.ts", "deprecated": false, @@ -73,7 +73,7 @@ "label": "LinkId", "description": [], "signature": [ - "\"\" | \"cases\" | \"alerts\" | \"rules\" | \"policy\" | \"overview\" | \"dashboards\" | \"kubernetes\" | \"cases_create\" | \"cases_configure\" | \"hosts\" | \"users\" | \"cloud_defend-policies\" | \"cloud_security_posture-dashboard\" | \"cloud_security_posture-findings\" | \"cloud_security_posture-benchmarks\" | \"network\" | \"data_quality\" | \"explore\" | \"assets\" | \"cloud_defend\" | \"notes\" | \"administration\" | \"attack_discovery\" | \"blocklist\" | \"cloud_security_posture-rules\" | \"detections\" | \"detection_response\" | \"endpoints\" | \"event_filters\" | \"exceptions\" | \"host_isolation_exceptions\" | \"hosts-all\" | \"hosts-anomalies\" | \"hosts-risk\" | \"hosts-events\" | \"hosts-sessions\" | \"hosts-uncommon_processes\" | \"investigations\" | \"get_started\" | \"machine_learning-landing\" | \"network-anomalies\" | \"network-dns\" | \"network-events\" | \"network-flows\" | \"network-http\" | \"network-tls\" | \"response_actions_history\" | \"rules-add\" | \"rules-create\" | \"rules-landing\" | \"threat_intelligence\" | \"timelines\" | \"timelines-templates\" | \"trusted_apps\" | \"users-all\" | \"users-anomalies\" | \"users-authentications\" | \"users-events\" | \"users-risk\" | \"entity_analytics\" | \"entity_analytics-management\" | \"entity_analytics-asset-classification\" | \"entity_analytics-entity_store_management\" | \"coverage-overview\"" + "\"\" | \"cases\" | \"alerts\" | \"rules\" | \"policy\" | \"overview\" | \"dashboards\" | \"kubernetes\" | \"cases_create\" | \"cases_configure\" | \"hosts\" | \"users\" | \"cloud_defend-policies\" | \"cloud_security_posture-dashboard\" | \"cloud_security_posture-findings\" | \"cloud_security_posture-benchmarks\" | \"network\" | \"data_quality\" | \"explore\" | \"assets\" | \"cloud_defend\" | \"notes\" | \"administration\" | \"attack_discovery\" | \"blocklist\" | \"cloud_security_posture-rules\" | \"detections\" | \"detection_response\" | \"endpoints\" | \"event_filters\" | \"exceptions\" | \"host_isolation_exceptions\" | \"hosts-all\" | \"hosts-anomalies\" | \"hosts-risk\" | \"hosts-events\" | \"hosts-sessions\" | \"hosts-uncommon_processes\" | \"investigations\" | \"get_started\" | \"machine_learning-landing\" | \"network-anomalies\" | \"network-dns\" | \"network-events\" | \"network-flows\" | \"network-http\" | \"network-tls\" | \"response_actions_history\" | \"rules-add\" | \"rules-create\" | \"rules-landing\" | \"siem_migrations-rules\" | \"threat_intelligence\" | \"timelines\" | \"timelines-templates\" | \"trusted_apps\" | \"users-all\" | \"users-anomalies\" | \"users-authentications\" | \"users-events\" | \"users-risk\" | \"entity_analytics\" | \"entity_analytics-management\" | \"entity_analytics-asset-classification\" | \"entity_analytics-entity_store_management\" | \"coverage-overview\"" ], "path": "packages/deeplinks/security/index.ts", "deprecated": false, diff --git a/api_docs/kbn_deeplinks_security.mdx b/api_docs/kbn_deeplinks_security.mdx index 186f67fc41c3..c54c29870626 100644 --- a/api_docs/kbn_deeplinks_security.mdx +++ b/api_docs/kbn_deeplinks_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-security title: "@kbn/deeplinks-security" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-security plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-security'] --- import kbnDeeplinksSecurityObj from './kbn_deeplinks_security.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_shared.mdx b/api_docs/kbn_deeplinks_shared.mdx index aaa60421f2a1..1539a457301e 100644 --- a/api_docs/kbn_deeplinks_shared.mdx +++ b/api_docs/kbn_deeplinks_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-shared title: "@kbn/deeplinks-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-shared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-shared'] --- import kbnDeeplinksSharedObj from './kbn_deeplinks_shared.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 6e3921a576d3..a504eacb588b 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index 347d472e70cc..d3b5f84e6678 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index d9873efe0b26..c3a20a08c0dd 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 70356eee17d3..f24a7c9a93bf 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 2f09ec4348e3..54aa8ae5d2c5 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2024-11-22 +date: 2024-12-03 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 d3df9f01700c..3883f9059ea0 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2024-11-22 +date: 2024-12-03 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 551cf08b808b..2701e447f13f 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2024-11-22 +date: 2024-12-03 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 0df00d2d4382..c20cd17c10d5 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_contextual_components.mdx b/api_docs/kbn_discover_contextual_components.mdx index 1d210a0def93..399c8f63e9e8 100644 --- a/api_docs/kbn_discover_contextual_components.mdx +++ b/api_docs/kbn_discover_contextual_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-contextual-components title: "@kbn/discover-contextual-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-contextual-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-contextual-components'] --- import kbnDiscoverContextualComponentsObj from './kbn_discover_contextual_components.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index 4d58bcac8bb8..575c61a63f7b 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index 50ca91a1d682..eb3ea0aa8619 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -669,7 +669,7 @@ "label": "alerting", "description": [], "signature": [ - "{ readonly guide: string; readonly actionTypes: string; readonly apmRulesErrorCount: string; readonly apmRulesTransactionDuration: string; readonly apmRulesTransactionError: string; readonly apmRulesAnomaly: string; readonly emailAction: string; readonly emailActionConfig: string; readonly emailExchangeClientSecretConfig: string; readonly emailExchangeClientIdConfig: string; readonly generalSettings: string; readonly indexAction: string; readonly esQuery: string; readonly indexThreshold: string; readonly maintenanceWindows: string; readonly pagerDutyAction: string; readonly preconfiguredConnectors: string; readonly preconfiguredAlertHistoryConnector: string; readonly serviceNowAction: string; readonly serviceNowSIRAction: string; readonly setupPrerequisites: string; readonly slackAction: string; readonly slackApiAction: string; readonly teamsAction: string; readonly connectors: string; }" + "{ readonly guide: string; readonly actionTypes: string; readonly apmRulesErrorCount: string; readonly apmRulesTransactionDuration: string; readonly apmRulesTransactionError: string; readonly apmRulesAnomaly: string; readonly emailAction: string; readonly emailActionConfig: string; readonly emailExchangeClientSecretConfig: string; readonly emailExchangeClientIdConfig: string; readonly generalSettings: string; readonly indexAction: string; readonly esQuery: string; readonly indexThreshold: string; readonly maintenanceWindows: string; readonly pagerDutyAction: string; readonly preconfiguredConnectors: string; readonly preconfiguredAlertHistoryConnector: string; readonly serviceNowAction: string; readonly serviceNowSIRAction: string; readonly setupPrerequisites: string; readonly slackAction: string; readonly slackApiAction: string; readonly teamsAction: string; readonly connectors: string; readonly legacyRuleApiDeprecations: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, @@ -1024,6 +1024,34 @@ "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/doc-links", + "id": "def-common.DocLinks.inferenceManagement", + "type": "Object", + "tags": [], + "label": "inferenceManagement", + "description": [], + "signature": [ + "{ readonly inferenceAPIDocumentation: string; }" + ], + "path": "packages/kbn-doc-links/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/doc-links", + "id": "def-common.DocLinks.cases", + "type": "Object", + "tags": [], + "label": "cases", + "description": [], + "signature": [ + "{ readonly legacyApiDeprecations: string; }" + ], + "path": "packages/kbn-doc-links/src/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 578be64ac226..35e2126df6ab 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/docs](https://github.com/orgs/elastic/teams/docs) for question | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 78 | 0 | 78 | 2 | +| 80 | 0 | 80 | 2 | ## Common diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 12e75295de4c..c986a79cd211 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 524192690ae9..b8416c3ddc46 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index f9b929d16e76..1c566e0da922 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index dc55efcd87a5..db839b71d28b 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_agent_utils.mdx b/api_docs/kbn_elastic_agent_utils.mdx index d174998b5ae7..f9337eea4a0e 100644 --- a/api_docs/kbn_elastic_agent_utils.mdx +++ b/api_docs/kbn_elastic_agent_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-agent-utils title: "@kbn/elastic-agent-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-agent-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-agent-utils'] --- import kbnElasticAgentUtilsObj from './kbn_elastic_agent_utils.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.devdocs.json b/api_docs/kbn_elastic_assistant.devdocs.json index e6e5d9a8e961..f4e458bb3a3b 100644 --- a/api_docs/kbn_elastic_assistant.devdocs.json +++ b/api_docs/kbn_elastic_assistant.devdocs.json @@ -2587,6 +2587,21 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/elastic-assistant", + "id": "def-public.DEFEND_INSIGHTS_STORAGE_KEY", + "type": "string", + "tags": [], + "label": "DEFEND_INSIGHTS_STORAGE_KEY", + "description": [], + "signature": [ + "\"defendInsights\"" + ], + "path": "x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/elastic-assistant", "id": "def-public.ELASTIC_AI_ASSISTANT_TITLE", diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 958429e48df2..96a0ddcc59cf 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 169 | 0 | 140 | 10 | +| 170 | 0 | 141 | 10 | ## Client diff --git a/api_docs/kbn_elastic_assistant_common.mdx b/api_docs/kbn_elastic_assistant_common.mdx index 714f47255cb5..7d8c4aca6ae5 100644 --- a/api_docs/kbn_elastic_assistant_common.mdx +++ b/api_docs/kbn_elastic_assistant_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant-common title: "@kbn/elastic-assistant-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant-common'] --- import kbnElasticAssistantCommonObj from './kbn_elastic_assistant_common.devdocs.json'; diff --git a/api_docs/kbn_entities_schema.devdocs.json b/api_docs/kbn_entities_schema.devdocs.json index ae8daadc3978..0269efb5711d 100644 --- a/api_docs/kbn_entities_schema.devdocs.json +++ b/api_docs/kbn_entities_schema.devdocs.json @@ -120,6 +120,81 @@ } ], "interfaces": [ + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2", + "type": "Interface", + "tags": [], + "label": "EntityV2", + "description": [], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2.entity.id", + "type": "string", + "tags": [], + "label": "'entity.id'", + "description": [], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2.entity.type", + "type": "string", + "tags": [], + "label": "'entity.type'", + "description": [], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2.entity.display_name", + "type": "string", + "tags": [], + "label": "'entity.display_name'", + "description": [], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2.entity.last_seen_timestamp", + "type": "string", + "tags": [], + "label": "'entity.last_seen_timestamp'", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/entities-schema", + "id": "def-common.EntityV2.Unnamed", + "type": "IndexSignature", + "tags": [], + "label": "[metadata: string]: any", + "description": [], + "signature": [ + "[metadata: string]: any" + ], + "path": "x-pack/packages/kbn-entities-schema/src/schema/entity.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/entities-schema", "id": "def-common.MetadataRecord", diff --git a/api_docs/kbn_entities_schema.mdx b/api_docs/kbn_entities_schema.mdx index faee25a2ad6a..44f3602c6853 100644 --- a/api_docs/kbn_entities_schema.mdx +++ b/api_docs/kbn_entities_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-entities-schema title: "@kbn/entities-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/entities-schema plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/entities-schema'] --- import kbnEntitiesSchemaObj from './kbn_entities_schema.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entiti | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 45 | 0 | 45 | 0 | +| 51 | 0 | 51 | 0 | ## Common diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index 63753f340e13..a5b21a524680 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 0cb542fa8fe5..08056225d103 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2024-11-22 +date: 2024-12-03 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 819e0cde2caf..103cdb4662ab 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index e009afd71d46..0a2ccb86bd95 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.devdocs.json b/api_docs/kbn_es_types.devdocs.json index 60ef30c14df1..ec62dd1cd61f 100644 --- a/api_docs/kbn_es_types.devdocs.json +++ b/api_docs/kbn_es_types.devdocs.json @@ -137,12 +137,13 @@ { "parentPluginId": "@kbn/es-types", "id": "def-common.ESQLSearchParams.params", - "type": "Array", + "type": "CompoundType", "tags": [], "label": "params", "description": [], "signature": [ - "Record[] | undefined" + "ScalarValue", + "[] | Record[] | undefined" ], "path": "packages/kbn-es-types/src/search.ts", "deprecated": false, diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index a8438442ffc2..91d392651778 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2024-11-22 +date: 2024-12-03 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 fe1f4988f978..7d28e5b2815f 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_esql_ast.devdocs.json b/api_docs/kbn_esql_ast.devdocs.json index 2c8e443f45d0..bf0442c6badd 100644 --- a/api_docs/kbn_esql_ast.devdocs.json +++ b/api_docs/kbn_esql_ast.devdocs.json @@ -282,13 +282,7 @@ "description": [], "signature": [ "(expression: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ", opts?: ", { "pluginId": "@kbn/esql-ast", @@ -313,13 +307,7 @@ "ES|QL expression AST node to print." ], "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } + "ESQLAstExpression" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", "deprecated": false, @@ -496,13 +484,7 @@ "description": [], "signature": [ "(node: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ", minusCount?: number) => string | undefined" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", @@ -517,13 +499,7 @@ "label": "node", "description": [], "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } + "ESQLAstExpression" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", "deprecated": false, @@ -666,13 +642,7 @@ "description": [], "signature": [ "(expression: ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ") => any" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", @@ -687,13 +657,7 @@ "label": "expression", "description": [], "signature": [ - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - } + "ESQLAstExpression" ], "path": "packages/kbn-esql-ast/src/pretty_print/basic_pretty_printer.ts", "deprecated": false, @@ -2142,6 +2106,57 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.Walker.walkInlineCast", + "type": "Function", + "tags": [], + "label": "walkInlineCast", + "description": [], + "signature": [ + "(node: ", + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + ">) => void" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.Walker.walkInlineCast.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLInlineCast", + "<", + { + "pluginId": "@kbn/esql-ast", + "scope": "common", + "docId": "kibKbnEsqlAstPluginApi", + "section": "def-common.ESQLAstItem", + "text": "ESQLAstItem" + }, + ">" + ], + "path": "packages/kbn-esql-ast/src/walker/walker.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.Walker.walkFunction", @@ -2599,13 +2614,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2621,13 +2630,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2645,13 +2648,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2667,13 +2664,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2693,13 +2684,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2715,13 +2700,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2739,13 +2718,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2761,13 +2734,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2797,13 +2764,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2819,13 +2780,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2843,13 +2798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2865,13 +2814,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2891,13 +2834,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2913,13 +2850,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -2937,13 +2868,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -2959,13 +2884,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -2997,13 +2916,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3019,13 +2932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3043,13 +2950,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3065,13 +2966,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3091,13 +2986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3113,13 +3002,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3137,13 +3020,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3159,13 +3036,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3195,13 +3066,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3217,13 +3082,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3241,13 +3100,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3263,13 +3116,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3289,13 +3136,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3311,13 +3152,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3335,13 +3170,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3357,13 +3186,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3397,13 +3220,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3419,13 +3236,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3443,13 +3254,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3465,13 +3270,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3491,13 +3290,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3513,13 +3306,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3537,13 +3324,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3559,13 +3340,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3595,13 +3370,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3617,13 +3386,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3641,13 +3404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3663,13 +3420,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3689,13 +3440,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3711,13 +3456,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3735,13 +3474,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3757,13 +3490,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3795,13 +3522,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3817,13 +3538,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3841,13 +3556,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3863,13 +3572,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3889,13 +3592,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3911,13 +3608,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -3935,13 +3626,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -3957,13 +3642,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -3993,13 +3672,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4015,13 +3688,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4039,13 +3706,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4061,13 +3722,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4087,13 +3742,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4109,13 +3758,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4133,13 +3776,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4155,13 +3792,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4197,13 +3828,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4219,13 +3844,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4243,13 +3862,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4265,13 +3878,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4291,13 +3898,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4313,13 +3914,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4337,13 +3932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4359,13 +3948,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4395,13 +3978,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4417,13 +3994,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4441,13 +4012,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4463,13 +4028,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4489,13 +4048,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4511,13 +4064,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4535,13 +4082,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4557,13 +4098,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4595,13 +4130,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4617,13 +4146,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4641,13 +4164,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4663,13 +4180,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4689,13 +4200,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4711,13 +4216,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4735,13 +4234,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4757,13 +4250,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4793,13 +4280,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4815,13 +4296,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4839,13 +4314,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4861,13 +4330,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4887,13 +4350,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4909,13 +4366,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -4933,13 +4384,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -4955,13 +4400,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -4995,13 +4434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5017,13 +4450,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5041,13 +4468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5063,13 +4484,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5089,13 +4504,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5111,13 +4520,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5135,13 +4538,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5157,13 +4554,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5193,13 +4584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5215,13 +4600,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5239,13 +4618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5261,13 +4634,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5287,13 +4654,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5309,13 +4670,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5333,13 +4688,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5355,13 +4704,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5393,13 +4736,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5415,13 +4752,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5439,13 +4770,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5461,13 +4786,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5487,13 +4806,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5509,13 +4822,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5533,13 +4840,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5555,13 +4856,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5591,13 +4886,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5613,13 +4902,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5637,13 +4920,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5659,13 +4936,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5685,13 +4956,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5707,13 +4972,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5731,13 +4990,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5753,13 +5006,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5799,13 +5046,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5821,13 +5062,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5845,13 +5080,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5867,13 +5096,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5893,13 +5116,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5915,13 +5132,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -5939,13 +5150,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -5961,13 +5166,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -5997,13 +5196,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6019,13 +5212,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6043,13 +5230,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6065,13 +5246,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6091,13 +5266,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6113,13 +5282,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6137,13 +5300,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6159,13 +5316,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6197,13 +5348,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6219,13 +5364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6243,13 +5382,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6265,13 +5398,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6291,13 +5418,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6313,13 +5434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6337,13 +5452,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6359,13 +5468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6395,13 +5498,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6417,13 +5514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6441,13 +5532,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6463,13 +5548,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6489,13 +5568,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6511,13 +5584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6535,13 +5602,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6557,13 +5618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6597,13 +5652,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6619,13 +5668,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6643,13 +5686,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6665,13 +5702,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6691,13 +5722,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6713,13 +5738,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6737,13 +5756,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6759,13 +5772,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6795,13 +5802,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6817,13 +5818,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6841,13 +5836,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6863,13 +5852,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6889,13 +5872,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6911,13 +5888,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -6935,13 +5906,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -6957,13 +5922,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -6995,13 +5954,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7017,13 +5970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7041,13 +5988,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7063,13 +6004,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7089,13 +6024,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7111,13 +6040,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7135,13 +6058,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7157,13 +6074,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7193,13 +6104,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7215,13 +6120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7239,13 +6138,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7261,13 +6154,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7287,13 +6174,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7309,13 +6190,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7333,13 +6208,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7355,13 +6224,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7397,13 +6260,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7419,13 +6276,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7443,13 +6294,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7465,13 +6310,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7491,13 +6330,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7513,13 +6346,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7537,13 +6364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7559,13 +6380,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7595,13 +6410,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7617,13 +6426,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7641,13 +6444,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7663,13 +6460,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7689,13 +6480,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7711,13 +6496,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7735,13 +6514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7757,13 +6530,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7795,13 +6562,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7817,13 +6578,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7841,13 +6596,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7863,13 +6612,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7889,13 +6632,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7911,13 +6648,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -7935,13 +6666,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -7957,13 +6682,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -7993,13 +6712,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8015,13 +6728,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8039,13 +6746,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8061,13 +6762,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8087,13 +6782,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8109,13 +6798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8133,13 +6816,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8155,13 +6832,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8195,13 +6866,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8217,13 +6882,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8241,13 +6900,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8263,13 +6916,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8289,13 +6936,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8311,13 +6952,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8335,13 +6970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8357,13 +6986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8393,13 +7016,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8415,13 +7032,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8439,13 +7050,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8461,13 +7066,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8487,13 +7086,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8509,13 +7102,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8533,13 +7120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8555,13 +7136,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8593,13 +7168,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8615,13 +7184,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8639,13 +7202,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8661,13 +7218,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8687,13 +7238,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8709,13 +7254,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8733,13 +7272,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8755,13 +7288,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8791,13 +7318,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8813,13 +7334,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8837,13 +7352,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8859,13 +7368,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -8885,13 +7388,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8907,13 +7404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -8931,13 +7422,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -8953,13 +7438,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9001,13 +7480,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9023,13 +7496,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9047,13 +7514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9069,13 +7530,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9095,13 +7550,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9117,13 +7566,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9141,13 +7584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9163,13 +7600,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9199,13 +7630,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9221,13 +7646,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9245,13 +7664,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9267,13 +7680,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9293,13 +7700,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9315,13 +7716,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9339,13 +7734,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9361,13 +7750,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9399,13 +7782,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9421,13 +7798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9445,13 +7816,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9467,13 +7832,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9493,13 +7852,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9515,13 +7868,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9539,13 +7886,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9561,13 +7902,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9597,13 +7932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9619,13 +7948,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9643,13 +7966,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9665,13 +7982,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9691,13 +8002,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9713,13 +8018,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9737,13 +8036,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9759,13 +8052,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9799,13 +8086,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9821,13 +8102,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9845,13 +8120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9867,13 +8136,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9893,13 +8156,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9915,13 +8172,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -9939,13 +8190,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -9961,13 +8206,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -9997,13 +8236,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10019,13 +8252,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10043,13 +8270,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10065,13 +8286,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10091,13 +8306,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10113,13 +8322,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10137,13 +8340,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10159,13 +8356,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10197,13 +8388,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10219,13 +8404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10243,13 +8422,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10265,13 +8438,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10291,13 +8458,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10313,13 +8474,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10337,13 +8492,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10359,13 +8508,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10395,13 +8538,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10417,13 +8554,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10441,13 +8572,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10463,13 +8588,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10489,13 +8608,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10511,13 +8624,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10535,13 +8642,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10557,13 +8658,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10599,13 +8694,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10621,13 +8710,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10645,13 +8728,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10667,13 +8744,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10693,13 +8764,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10715,13 +8780,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10739,13 +8798,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10761,13 +8814,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10797,13 +8844,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10819,13 +8860,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10843,13 +8878,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10865,13 +8894,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10891,13 +8914,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10913,13 +8930,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -10937,13 +8948,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -10959,13 +8964,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -10997,13 +8996,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11019,13 +9012,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11043,13 +9030,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11065,13 +9046,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11091,13 +9066,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11113,13 +9082,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11137,13 +9100,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11159,13 +9116,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11195,13 +9146,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11217,13 +9162,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11241,13 +9180,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11263,13 +9196,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11289,13 +9216,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11311,13 +9232,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11335,13 +9250,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11357,13 +9266,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11397,13 +9300,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11419,13 +9316,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11443,13 +9334,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11465,13 +9350,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11491,13 +9370,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11513,13 +9386,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11537,13 +9404,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11559,13 +9420,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11595,13 +9450,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11617,13 +9466,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11641,13 +9484,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11663,13 +9500,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11689,13 +9520,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11711,13 +9536,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11735,13 +9554,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11757,13 +9570,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11795,13 +9602,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11817,13 +9618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11841,13 +9636,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11863,13 +9652,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11889,13 +9672,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11911,13 +9688,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -11935,13 +9706,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -11957,13 +9722,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -11993,13 +9752,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12015,13 +9768,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12039,13 +9786,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12061,13 +9802,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12087,13 +9822,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12109,13 +9838,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12133,13 +9856,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12155,13 +9872,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12201,13 +9912,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12223,13 +9928,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12247,13 +9946,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12269,13 +9962,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12295,13 +9982,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12317,13 +9998,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12341,13 +10016,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12363,13 +10032,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12399,13 +10062,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12421,13 +10078,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12445,13 +10096,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12467,13 +10112,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12493,13 +10132,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12515,13 +10148,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12539,13 +10166,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12561,13 +10182,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12599,13 +10214,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12621,13 +10230,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12645,13 +10248,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12667,13 +10264,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12693,13 +10284,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12715,13 +10300,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12739,13 +10318,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12761,13 +10334,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12797,13 +10364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12819,13 +10380,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12843,13 +10398,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12865,13 +10414,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12891,13 +10434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12913,13 +10450,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -12937,13 +10468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -12959,13 +10484,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -12999,13 +10518,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13021,13 +10534,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13045,13 +10552,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13067,13 +10568,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13093,13 +10588,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13115,13 +10604,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13139,13 +10622,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13161,13 +10638,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13197,13 +10668,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13219,13 +10684,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13243,13 +10702,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13265,13 +10718,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13291,13 +10738,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13313,13 +10754,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13337,13 +10772,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13359,13 +10788,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13397,13 +10820,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13419,13 +10836,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13443,13 +10854,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13465,13 +10870,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13491,13 +10890,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13513,13 +10906,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13537,13 +10924,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13559,13 +10940,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13595,13 +10970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13617,13 +10986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13641,13 +11004,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13663,13 +11020,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13689,13 +11040,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13711,13 +11056,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13735,13 +11074,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13757,13 +11090,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13799,13 +11126,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13821,13 +11142,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13845,13 +11160,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13867,13 +11176,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13893,13 +11196,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13915,13 +11212,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -13939,13 +11230,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -13961,13 +11246,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -13997,13 +11276,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14019,13 +11292,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14043,13 +11310,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14065,13 +11326,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14091,13 +11346,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14113,13 +11362,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14137,13 +11380,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14159,13 +11396,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14197,13 +11428,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14219,13 +11444,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14243,13 +11462,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14265,13 +11478,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14291,13 +11498,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14313,13 +11514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14337,13 +11532,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14359,13 +11548,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14395,13 +11578,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14417,13 +11594,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14441,13 +11612,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14463,13 +11628,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14489,13 +11648,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14511,13 +11664,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14535,13 +11682,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14557,13 +11698,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14597,13 +11732,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14619,13 +11748,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14643,13 +11766,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14665,13 +11782,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14691,13 +11802,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14713,13 +11818,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14737,13 +11836,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14759,13 +11852,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14795,13 +11882,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14817,13 +11898,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14841,13 +11916,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14863,13 +11932,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14889,13 +11952,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14911,13 +11968,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -14935,13 +11986,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -14957,13 +12002,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -14991,17 +12030,11 @@ "<", "VisitorMethods", ", ", - "SharedData", - ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "SharedData", + ">, ", + "SharedData", + ", ", + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15017,13 +12050,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15041,13 +12068,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15063,13 +12084,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15089,13 +12104,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15111,13 +12120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15135,13 +12138,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15157,13 +12154,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15193,13 +12184,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15215,13 +12200,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15239,13 +12218,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15261,13 +12234,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15287,13 +12254,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15309,13 +12270,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15333,13 +12288,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15355,13 +12304,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15405,13 +12348,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15427,13 +12364,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15451,13 +12382,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15473,13 +12398,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15499,13 +12418,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15521,13 +12434,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15545,13 +12452,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15567,13 +12468,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15603,13 +12498,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15625,13 +12514,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15649,13 +12532,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15671,13 +12548,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15697,13 +12568,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15719,13 +12584,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15743,13 +12602,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15765,13 +12618,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15803,13 +12650,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15825,13 +12666,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15849,13 +12684,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15871,13 +12700,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -15897,13 +12720,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15919,13 +12736,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -15943,13 +12754,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -15965,13 +12770,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16001,13 +12800,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16023,13 +12816,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16047,13 +12834,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16069,13 +12850,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16095,13 +12870,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16117,13 +12886,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16141,13 +12904,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16163,13 +12920,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16203,13 +12954,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16225,13 +12970,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16249,13 +12988,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16271,13 +13004,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16297,13 +13024,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16319,13 +13040,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16343,13 +13058,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16365,13 +13074,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16401,13 +13104,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16423,13 +13120,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16447,13 +13138,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16469,13 +13154,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16495,13 +13174,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16517,13 +13190,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16541,13 +13208,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16563,13 +13224,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16601,13 +13256,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16623,13 +13272,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16647,13 +13290,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16669,13 +13306,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16695,13 +13326,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16717,13 +13342,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { visitColumnExpression: (ctx: ", @@ -16741,13 +13360,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16763,13 +13376,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; }, ", @@ -16799,13 +13406,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; } & { visitSourceExpression: (ctx: ", "SourceExpressionVisitorContext", "<", @@ -16821,13 +13422,7 @@ ">, ", "SharedData", ", ", - { - "pluginId": "@kbn/esql-ast", - "scope": "common", - "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLSingleAstItem", - "text": "ESQLSingleAstItem" - }, + "ESQLAstExpression", ">, inp: Input) => Output; }, ", "SharedData", ">, inp: Input) => Output; } & { ...; } & { ...; }, ", @@ -18521,18 +15116,6 @@ { "plugin": "@kbn/esql-utils", "path": "packages/kbn-esql-utils/src/utils/append_to_query.ts" - }, - { - "plugin": "@kbn/securitysolution-utils", - "path": "packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts" - }, - { - "plugin": "securitySolution", - "path": "x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts" } ] }, @@ -19909,6 +16492,40 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.identifier", + "type": "Function", + "tags": [], + "label": "identifier", + "description": [], + "signature": [ + "(node: ", + "ESQLIdentifier", + ") => string" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.identifier.$1", + "type": "Object", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLIdentifier" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/esql-ast", "id": "def-common.LeafPrinter.column", @@ -20162,6 +16779,40 @@ } ], "returnComment": [] + }, + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.print", + "type": "Function", + "tags": [], + "label": "print", + "description": [], + "signature": [ + "(node: ", + "ESQLProperNode", + ") => string" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/esql-ast", + "id": "def-common.LeafPrinter.print.$1", + "type": "CompoundType", + "tags": [], + "label": "node", + "description": [], + "signature": [ + "ESQLProperNode" + ], + "path": "packages/kbn-esql-ast/src/pretty_print/leaf_printer.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/kbn_esql_ast.mdx b/api_docs/kbn_esql_ast.mdx index 56f6ff9c8c9b..4a5f0a3e7bec 100644 --- a/api_docs/kbn_esql_ast.mdx +++ b/api_docs/kbn_esql_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-ast title: "@kbn/esql-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-ast plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-ast'] --- import kbnEsqlAstObj from './kbn_esql_ast.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 277 | 1 | 216 | 36 | +| 283 | 1 | 222 | 36 | ## Common diff --git a/api_docs/kbn_esql_editor.mdx b/api_docs/kbn_esql_editor.mdx index 7a06bb880eaa..e248e4ea11eb 100644 --- a/api_docs/kbn_esql_editor.mdx +++ b/api_docs/kbn_esql_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-editor title: "@kbn/esql-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-editor plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-editor'] --- import kbnEsqlEditorObj from './kbn_esql_editor.devdocs.json'; diff --git a/api_docs/kbn_esql_utils.mdx b/api_docs/kbn_esql_utils.mdx index 497bc1fece29..b0514fa934b3 100644 --- a/api_docs/kbn_esql_utils.mdx +++ b/api_docs/kbn_esql_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-utils title: "@kbn/esql-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-utils'] --- import kbnEsqlUtilsObj from './kbn_esql_utils.devdocs.json'; diff --git a/api_docs/kbn_esql_validation_autocomplete.mdx b/api_docs/kbn_esql_validation_autocomplete.mdx index 61e10af73c31..88c2ac9e4818 100644 --- a/api_docs/kbn_esql_validation_autocomplete.mdx +++ b/api_docs/kbn_esql_validation_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-esql-validation-autocomplete title: "@kbn/esql-validation-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/esql-validation-autocomplete plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/esql-validation-autocomplete'] --- import kbnEsqlValidationAutocompleteObj from './kbn_esql_validation_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index 981fbeb59012..87e1d520171b 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 485def755f1f..c19339435c2a 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.devdocs.json b/api_docs/kbn_expandable_flyout.devdocs.json index 8224ebb0e15a..10de89b7d365 100644 --- a/api_docs/kbn_expandable_flyout.devdocs.json +++ b/api_docs/kbn_expandable_flyout.devdocs.json @@ -138,57 +138,6 @@ "children": [], "returnComment": [], "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-public.withExpandableFlyoutProvider", - "type": "Function", - "tags": [], - "label": "withExpandableFlyoutProvider", - "description": [], - "signature": [ - "(Component: React.ComponentType, expandableProviderProps?: ", - "ExpandableFlyoutContextProviderProps", - " | undefined) => (props: Props) => React.JSX.Element" - ], - "path": "packages/kbn-expandable-flyout/src/with_provider.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-public.withExpandableFlyoutProvider.$1", - "type": "CompoundType", - "tags": [], - "label": "Component", - "description": [], - "signature": [ - "React.ComponentType" - ], - "path": "packages/kbn-expandable-flyout/src/with_provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "@kbn/expandable-flyout", - "id": "def-public.withExpandableFlyoutProvider.$2", - "type": "Object", - "tags": [], - "label": "expandableProviderProps", - "description": [], - "signature": [ - "ExpandableFlyoutContextProviderProps", - " | undefined" - ], - "path": "packages/kbn-expandable-flyout/src/with_provider.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [], - "initialIsOpen": false } ], "interfaces": [ diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index 219871bfd9ba..9000c27e42bb 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-investigations](https://github.com/org | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 44 | 0 | 17 | 3 | +| 41 | 0 | 14 | 2 | ## Client diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 5336e3235343..918a1fcb1ab0 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 530f30ed9f5f..ffc55a9cb0d6 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 593fbac108a8..d735227da336 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_formatters.mdx b/api_docs/kbn_formatters.mdx index b7ff84515690..28d8b3a1038a 100644 --- a/api_docs/kbn_formatters.mdx +++ b/api_docs/kbn_formatters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-formatters title: "@kbn/formatters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/formatters plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/formatters'] --- import kbnFormattersObj from './kbn_formatters.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 319123ca29b6..dc63d6870186 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_ui_services.mdx b/api_docs/kbn_ftr_common_functional_ui_services.mdx index 26b6daa03c53..0265a519eb55 100644 --- a/api_docs/kbn_ftr_common_functional_ui_services.mdx +++ b/api_docs/kbn_ftr_common_functional_ui_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-ui-services title: "@kbn/ftr-common-functional-ui-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-ui-services plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-ui-services'] --- import kbnFtrCommonFunctionalUiServicesObj from './kbn_ftr_common_functional_ui_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index d5a36e95d2fc..257c25cd2d4a 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 5a31d9244451..c5dc8ad3d6c0 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.devdocs.json b/api_docs/kbn_generate_csv.devdocs.json index a95a53670c1b..535dee81a98d 100644 --- a/api_docs/kbn_generate_csv.devdocs.json +++ b/api_docs/kbn_generate_csv.devdocs.json @@ -64,7 +64,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -240,7 +240,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index bde383f9f1b6..a607f6fda20b 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_grid_layout.devdocs.json b/api_docs/kbn_grid_layout.devdocs.json index acd664c6cac8..411b0d387d6e 100644 --- a/api_docs/kbn_grid_layout.devdocs.json +++ b/api_docs/kbn_grid_layout.devdocs.json @@ -11,7 +11,7 @@ "label": "GridLayout", "description": [], "signature": [ - "({ layout, gridSettings, renderPanelContents, onLayoutChange, }: GridLayoutProps) => React.JSX.Element" + "({ layout, gridSettings, renderPanelContents, onLayoutChange, expandedPanelId, accessMode, }: GridLayoutProps) => React.JSX.Element" ], "path": "packages/kbn-grid-layout/grid/grid_layout.tsx", "deprecated": false, @@ -22,7 +22,7 @@ "id": "def-public.GridLayout.$1", "type": "Object", "tags": [], - "label": "{\n layout,\n gridSettings,\n renderPanelContents,\n onLayoutChange,\n}", + "label": "{\n layout,\n gridSettings,\n renderPanelContents,\n onLayoutChange,\n expandedPanelId,\n accessMode = 'EDIT',\n}", "description": [], "signature": [ "GridLayoutProps" @@ -258,6 +258,21 @@ ], "enums": [], "misc": [ + { + "parentPluginId": "@kbn/grid-layout", + "id": "def-public.GridAccessMode", + "type": "Type", + "tags": [], + "label": "GridAccessMode", + "description": [], + "signature": [ + "\"VIEW\" | \"EDIT\"" + ], + "path": "packages/kbn-grid-layout/grid/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/grid-layout", "id": "def-public.GridLayoutData", diff --git a/api_docs/kbn_grid_layout.mdx b/api_docs/kbn_grid_layout.mdx index 89cee389aa55..3b5b2d38d288 100644 --- a/api_docs/kbn_grid_layout.mdx +++ b/api_docs/kbn_grid_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grid-layout title: "@kbn/grid-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grid-layout plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grid-layout'] --- import kbnGridLayoutObj from './kbn_grid_layout.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 16 | 0 | 16 | 1 | +| 17 | 0 | 17 | 1 | ## Client diff --git a/api_docs/kbn_grouping.mdx b/api_docs/kbn_grouping.mdx index 203be187cdc7..0afb988a8714 100644 --- a/api_docs/kbn_grouping.mdx +++ b/api_docs/kbn_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-grouping title: "@kbn/grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/grouping plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/grouping'] --- import kbnGroupingObj from './kbn_grouping.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 0e26b3e0f20c..07ab2aac3453 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 5dd459ddcaa1..b0f23a50a30b 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2024-11-22 +date: 2024-12-03 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 0d19292e6abd..47a3a083c8ef 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index d72e55d814df..1960482ce187 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index ca0dd9585e71..6f993df67f97 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2024-11-22 +date: 2024-12-03 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 4b4f9e2d6f07..85a33135ef8a 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2024-11-22 +date: 2024-12-03 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 079a606760cf..7e04c4bc6441 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index 8a34d541608e..3a1018ad2270 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 50d97c0830c6..6ef15ebfbb5d 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_index_adapter.mdx b/api_docs/kbn_index_adapter.mdx index b252220048a9..d879aa0fd368 100644 --- a/api_docs/kbn_index_adapter.mdx +++ b/api_docs/kbn_index_adapter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-adapter title: "@kbn/index-adapter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-adapter plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-adapter'] --- import kbnIndexAdapterObj from './kbn_index_adapter.devdocs.json'; diff --git a/api_docs/kbn_index_lifecycle_management_common_shared.mdx b/api_docs/kbn_index_lifecycle_management_common_shared.mdx index 94cca4ab54ef..f1dde434829d 100644 --- a/api_docs/kbn_index_lifecycle_management_common_shared.mdx +++ b/api_docs/kbn_index_lifecycle_management_common_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-lifecycle-management-common-shared title: "@kbn/index-lifecycle-management-common-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-lifecycle-management-common-shared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-lifecycle-management-common-shared'] --- import kbnIndexLifecycleManagementCommonSharedObj from './kbn_index_lifecycle_management_common_shared.devdocs.json'; diff --git a/api_docs/kbn_index_management_shared_types.mdx b/api_docs/kbn_index_management_shared_types.mdx index 9203de44ee15..245bfbb2b888 100644 --- a/api_docs/kbn_index_management_shared_types.mdx +++ b/api_docs/kbn_index_management_shared_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-index-management-shared-types title: "@kbn/index-management-shared-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/index-management-shared-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/index-management-shared-types'] --- import kbnIndexManagementSharedTypesObj from './kbn_index_management_shared_types.devdocs.json'; diff --git a/api_docs/kbn_inference_common.mdx b/api_docs/kbn_inference_common.mdx index 0009101e3db7..94da9c77efb5 100644 --- a/api_docs/kbn_inference_common.mdx +++ b/api_docs/kbn_inference_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference-common title: "@kbn/inference-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference-common'] --- import kbnInferenceCommonObj from './kbn_inference_common.devdocs.json'; diff --git a/api_docs/kbn_inference_integration_flyout.mdx b/api_docs/kbn_inference_integration_flyout.mdx index 120d84215ca4..afbe1bbccd17 100644 --- a/api_docs/kbn_inference_integration_flyout.mdx +++ b/api_docs/kbn_inference_integration_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-inference_integration_flyout title: "@kbn/inference_integration_flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/inference_integration_flyout plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/inference_integration_flyout'] --- import kbnInferenceIntegrationFlyoutObj from './kbn_inference_integration_flyout.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index 6dcaf322f989..37563b02dbf1 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index 90913295ff20..a1cf8e0625a7 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_investigation_shared.mdx b/api_docs/kbn_investigation_shared.mdx index 93a542e6beff..e15da2052ee4 100644 --- a/api_docs/kbn_investigation_shared.mdx +++ b/api_docs/kbn_investigation_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-investigation-shared title: "@kbn/investigation-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/investigation-shared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/investigation-shared'] --- import kbnInvestigationSharedObj from './kbn_investigation_shared.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 66647e17f605..7b4d6cb76c62 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_ipynb.mdx b/api_docs/kbn_ipynb.mdx index 917ee150d86a..db11da137ee7 100644 --- a/api_docs/kbn_ipynb.mdx +++ b/api_docs/kbn_ipynb.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ipynb title: "@kbn/ipynb" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ipynb plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ipynb'] --- import kbnIpynbObj from './kbn_ipynb.devdocs.json'; diff --git a/api_docs/kbn_item_buffer.mdx b/api_docs/kbn_item_buffer.mdx index e7273e3ee196..2271ae79bfd8 100644 --- a/api_docs/kbn_item_buffer.mdx +++ b/api_docs/kbn_item_buffer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-item-buffer title: "@kbn/item-buffer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/item-buffer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/item-buffer'] --- import kbnItemBufferObj from './kbn_item_buffer.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index aa0e2db75dcb..313c3d90e615 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2024-11-22 +date: 2024-12-03 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 69534c60761b..cb52b76f3e65 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 061f972ff92f..0bc116461cd9 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_json_schemas.mdx b/api_docs/kbn_json_schemas.mdx index 13e9452daedc..76f1da98e720 100644 --- a/api_docs/kbn_json_schemas.mdx +++ b/api_docs/kbn_json_schemas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-schemas title: "@kbn/json-schemas" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-schemas plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-schemas'] --- import kbnJsonSchemasObj from './kbn_json_schemas.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index 9ce785871fda..5b12795dee99 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation.mdx b/api_docs/kbn_language_documentation.mdx index 2f811942bd93..b73082cc0553 100644 --- a/api_docs/kbn_language_documentation.mdx +++ b/api_docs/kbn_language_documentation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation title: "@kbn/language-documentation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation'] --- import kbnLanguageDocumentationObj from './kbn_language_documentation.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.devdocs.json b/api_docs/kbn_lens_embeddable_utils.devdocs.json index 60b32a55abdf..c2a2f29e1bda 100644 --- a/api_docs/kbn_lens_embeddable_utils.devdocs.json +++ b/api_docs/kbn_lens_embeddable_utils.devdocs.json @@ -316,7 +316,65 @@ "label": "build", "description": [], "signature": [ - "() => LensAttributes<\"lnsXY\", ", + "() => { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -324,9 +382,125 @@ "section": "def-public.XYState", "text": "XYState" }, - "> | LensAttributes<\"lnsPie\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -334,7 +508,65 @@ "section": "def-public.HeatmapVisualizationState", "text": "HeatmapVisualizationState" }, - "> | LensAttributes<\"lnsGauge\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -342,7 +574,65 @@ "section": "def-public.GaugeVisualizationState", "text": "GaugeVisualizationState" }, - "> | LensAttributes<\"lnsDatatable\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -350,23 +640,197 @@ "section": "def-public.DatatableVisualizationState", "text": "DatatableVisualizationState" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "pluginId": "lens", + "pluginId": "@kbn/core-saved-objects-common", "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "> | LensAttributes<\"lnsMetric\", ", + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - "> | LensAttributes" + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" ], "path": "packages/kbn-lens-embeddable-utils/attribute_builder/lens_attributes_builder.ts", "deprecated": false, @@ -3344,118 +3808,466 @@ "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.PersistedIndexPatternLayer", - "text": "PersistedIndexPatternLayer" + "section": "def-public.PersistedIndexPatternLayer", + "text": "PersistedIndexPatternLayer" + }, + ") => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PersistedIndexPatternLayer", + "text": "PersistedIndexPatternLayer" + } + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.StaticChartColumn.getData.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.StaticChartColumn.getData.$2", + "type": "Object", + "tags": [], + "label": "baseLayer", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PersistedIndexPatternLayer", + "text": "PersistedIndexPatternLayer" + } + ], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.VisualizationAttributesBuilder", + "type": "Interface", + "tags": [], + "label": "VisualizationAttributesBuilder", + "description": [], + "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/lens-embeddable-utils", + "id": "def-common.VisualizationAttributesBuilder.build", + "type": "Function", + "tags": [], + "label": "build", + "description": [], + "signature": [ + "() => { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - ") => ", + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.PersistedIndexPatternLayer", - "text": "PersistedIndexPatternLayer" - } - ], - "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-common.StaticChartColumn.getData.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string" - ], - "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", { - "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-common.StaticChartColumn.getData.$2", - "type": "Object", - "tags": [], - "label": "baseLayer", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.PersistedIndexPatternLayer", - "text": "PersistedIndexPatternLayer" - } - ], - "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-common.VisualizationAttributesBuilder", - "type": "Interface", - "tags": [], - "label": "VisualizationAttributesBuilder", - "description": [], - "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/lens-embeddable-utils", - "id": "def-common.VisualizationAttributesBuilder.build", - "type": "Function", - "tags": [], - "label": "build", - "description": [], - "signature": [ - "() => LensAttributes<\"lnsXY\", ", + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - "> | LensAttributes<\"lnsGauge\", ", + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "> | LensAttributes<\"lnsDatatable\", ", + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "common", @@ -3463,7 +4275,65 @@ "section": "def-common.LegacyMetricState", "text": "LegacyMetricState" }, - "> | LensAttributes<\"lnsMetric\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -3471,7 +4341,65 @@ "section": "def-public.MetricVisualizationState", "text": "MetricVisualizationState" }, - "> | LensAttributes" + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" ], "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", "deprecated": false, @@ -4045,7 +4973,65 @@ "label": "LensAttributes", "description": [], "signature": [ - "LensAttributes<\"lnsXY\", ", + "{ title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -4053,9 +5039,125 @@ "section": "def-public.XYState", "text": "XYState" }, - "> | LensAttributes<\"lnsPie\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -4063,7 +5165,65 @@ "section": "def-public.HeatmapVisualizationState", "text": "HeatmapVisualizationState" }, - "> | LensAttributes<\"lnsGauge\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -4071,7 +5231,65 @@ "section": "def-public.GaugeVisualizationState", "text": "GaugeVisualizationState" }, - "> | LensAttributes<\"lnsDatatable\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -4079,7 +5297,65 @@ "section": "def-public.DatatableVisualizationState", "text": "DatatableVisualizationState" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "common", @@ -4087,7 +5363,65 @@ "section": "def-common.LegacyMetricState", "text": "LegacyMetricState" }, - "> | LensAttributes<\"lnsMetric\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -4095,7 +5429,65 @@ "section": "def-public.MetricVisualizationState", "text": "MetricVisualizationState" }, - "> | LensAttributes" + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" ], "path": "packages/kbn-lens-embeddable-utils/attribute_builder/types.ts", "deprecated": false, diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index f7b95eaf89ee..4b939509b4c1 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_lens_formula_docs.mdx b/api_docs/kbn_lens_formula_docs.mdx index 2bf3769f8014..7112c1008157 100644 --- a/api_docs/kbn_lens_formula_docs.mdx +++ b/api_docs/kbn_lens_formula_docs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-formula-docs title: "@kbn/lens-formula-docs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-formula-docs plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-formula-docs'] --- import kbnLensFormulaDocsObj from './kbn_lens_formula_docs.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 309660590d5c..8fb3be8864c7 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2024-11-22 +date: 2024-12-03 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 f109ef3c783b..837ac4721ebc 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_content_badge.mdx b/api_docs/kbn_managed_content_badge.mdx index 9e093cfc91a2..dde5ec6d1a50 100644 --- a/api_docs/kbn_managed_content_badge.mdx +++ b/api_docs/kbn_managed_content_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-content-badge title: "@kbn/managed-content-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-content-badge plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-content-badge'] --- import kbnManagedContentBadgeObj from './kbn_managed_content_badge.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index 96286947758a..55eea305678c 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index 2f0644094b26..2db4f527e160 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index e73b051b1f28..5479db788c68 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index 15dee22ab50a..dc68e598b6d5 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index 7c3d514f794d..a1cb7fde56bb 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index a76fa0e04720..903896f47ab4 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index aa88fda990f9..23f6c111f935 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index 2da954b6c544..775a385a0c4f 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index 4a96d23c42ca..68f7d07837e9 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; -Contact [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index d1d7a20a5813..302b3f5520e8 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; -Contact [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index ff19cb8ad392..be056860418a 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 06cad3ba4f04..a0dd4ed2bfac 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 734d38e182b3..58f02befefd1 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_manifest.mdx b/api_docs/kbn_manifest.mdx index f21e3a9c1825..b4c1a7d344d9 100644 --- a/api_docs/kbn_manifest.mdx +++ b/api_docs/kbn_manifest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-manifest title: "@kbn/manifest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/manifest plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/manifest'] --- import kbnManifestObj from './kbn_manifest.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 04d70b1064a6..417cef025530 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index aed1ee509663..aa7a2b00efa3 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 06f5c42e15a2..c798d2a14dbf 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index e33da401d2b2..5c04c5bf3c7e 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_cancellable_search.mdx b/api_docs/kbn_ml_cancellable_search.mdx index 7316e0f63115..bccf9871bb70 100644 --- a/api_docs/kbn_ml_cancellable_search.mdx +++ b/api_docs/kbn_ml_cancellable_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-cancellable-search title: "@kbn/ml-cancellable-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-cancellable-search plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-cancellable-search'] --- import kbnMlCancellableSearchObj from './kbn_ml_cancellable_search.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index cb4f89e67e3b..7049fb1c993c 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index ce63110538ba..c7a672f0a9bf 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 107fa77d19dc..a510a28e70f1 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index 1c6d824deb92..328d8ab43cad 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 21a8a50f5fe4..20ed3d344ff0 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 23c2f2bffa09..2ccc1a8d0ca3 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index 1ca2e4d1d556..0f14619eea8d 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_field_stats_flyout.mdx b/api_docs/kbn_ml_field_stats_flyout.mdx index e71bcc3dd597..7ca2933d4270 100644 --- a/api_docs/kbn_ml_field_stats_flyout.mdx +++ b/api_docs/kbn_ml_field_stats_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-field-stats-flyout title: "@kbn/ml-field-stats-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-field-stats-flyout plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-field-stats-flyout'] --- import kbnMlFieldStatsFlyoutObj from './kbn_ml_field_stats_flyout.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 8b54b3c3bd30..fca65dac63dc 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index a3ca6622d64b..67d0e11795de 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 6be5e86f221a..eb3713848a0b 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index d47e358375ee..0432c75446ce 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index 4df32753933d..0c03b4334e57 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index 00ab3e7e96d0..383213651c64 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index f44c4c4f7181..4e51d1d0009d 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_parse_interval.mdx b/api_docs/kbn_ml_parse_interval.mdx index 17cb1ddb12d1..79776bb90c84 100644 --- a/api_docs/kbn_ml_parse_interval.mdx +++ b/api_docs/kbn_ml_parse_interval.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-parse-interval title: "@kbn/ml-parse-interval" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-parse-interval plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-parse-interval'] --- import kbnMlParseIntervalObj from './kbn_ml_parse_interval.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 7c59b5dcc831..f70ee2016d1f 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 339163fc8f9b..41c0612f70e1 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index b03b8628b44c..a77f77c57730 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index 2ef7d97f2367..96cac2b53474 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 2bc0d1e76e66..645d4beed457 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_time_buckets.mdx b/api_docs/kbn_ml_time_buckets.mdx index 6ca7ecacee78..fbc302a9d09d 100644 --- a/api_docs/kbn_ml_time_buckets.mdx +++ b/api_docs/kbn_ml_time_buckets.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-time-buckets title: "@kbn/ml-time-buckets" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-time-buckets plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-time-buckets'] --- import kbnMlTimeBucketsObj from './kbn_ml_time_buckets.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index 8ebe6d0839fe..817cc7be8687 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_ui_actions.mdx b/api_docs/kbn_ml_ui_actions.mdx index 0b5b9ed5aa07..0eeb89193d1b 100644 --- a/api_docs/kbn_ml_ui_actions.mdx +++ b/api_docs/kbn_ml_ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-ui-actions title: "@kbn/ml-ui-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-ui-actions plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-ui-actions'] --- import kbnMlUiActionsObj from './kbn_ml_ui_actions.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index 6f66f080a991..dee866819cc9 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_ml_validators.mdx b/api_docs/kbn_ml_validators.mdx index 3f30b4cff22b..89da130184b6 100644 --- a/api_docs/kbn_ml_validators.mdx +++ b/api_docs/kbn_ml_validators.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-validators title: "@kbn/ml-validators" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-validators plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-validators'] --- import kbnMlValidatorsObj from './kbn_ml_validators.devdocs.json'; diff --git a/api_docs/kbn_mock_idp_utils.mdx b/api_docs/kbn_mock_idp_utils.mdx index c655fda7bcdc..61bab08535a8 100644 --- a/api_docs/kbn_mock_idp_utils.mdx +++ b/api_docs/kbn_mock_idp_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mock-idp-utils title: "@kbn/mock-idp-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mock-idp-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mock-idp-utils'] --- import kbnMockIdpUtilsObj from './kbn_mock_idp_utils.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index a76652b31f69..ed9d2f96307e 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index bcafa0c2f87f..c9172a194bb9 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_object_versioning_utils.mdx b/api_docs/kbn_object_versioning_utils.mdx index 35496ac7dec1..bcf44cf3f807 100644 --- a/api_docs/kbn_object_versioning_utils.mdx +++ b/api_docs/kbn_object_versioning_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning-utils title: "@kbn/object-versioning-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning-utils'] --- import kbnObjectVersioningUtilsObj from './kbn_object_versioning_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index b353f50d6106..78a482ad6984 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_rule_utils.mdx b/api_docs/kbn_observability_alerting_rule_utils.mdx index 110738d4530e..d50cc4663205 100644 --- a/api_docs/kbn_observability_alerting_rule_utils.mdx +++ b/api_docs/kbn_observability_alerting_rule_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-rule-utils title: "@kbn/observability-alerting-rule-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-rule-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-rule-utils'] --- import kbnObservabilityAlertingRuleUtilsObj from './kbn_observability_alerting_rule_utils.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 7b73cf03def5..ad1f805afb93 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx index 29c7ff9bc360..0f54b2e88fe4 100644 --- a/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx +++ b/api_docs/kbn_observability_get_padded_alert_time_range_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-get-padded-alert-time-range-util title: "@kbn/observability-get-padded-alert-time-range-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-get-padded-alert-time-range-util plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-get-padded-alert-time-range-util'] --- import kbnObservabilityGetPaddedAlertTimeRangeUtilObj from './kbn_observability_get_padded_alert_time_range_util.devdocs.json'; diff --git a/api_docs/kbn_observability_logs_overview.devdocs.json b/api_docs/kbn_observability_logs_overview.devdocs.json index 43156c3b352e..e43439900367 100644 --- a/api_docs/kbn_observability_logs_overview.devdocs.json +++ b/api_docs/kbn_observability_logs_overview.devdocs.json @@ -316,6 +316,8 @@ "LogCategoriesGridChangeTimeCellDependencies", " & ", "LogCategoryDocumentExamplesTableDependencies", + " & ", + "DiscoverLinkDependencies", " & { search: ", { "pluginId": "@kbn/search-types", @@ -467,6 +469,8 @@ "LogCategoriesGridChangeTimeCellDependencies", " & ", "LogCategoryDocumentExamplesTableDependencies", + " & ", + "DiscoverLinkDependencies", " & { search: ", { "pluginId": "@kbn/search-types", diff --git a/api_docs/kbn_observability_logs_overview.mdx b/api_docs/kbn_observability_logs_overview.mdx index 716254b67130..736523bbd1b8 100644 --- a/api_docs/kbn_observability_logs_overview.mdx +++ b/api_docs/kbn_observability_logs_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-logs-overview title: "@kbn/observability-logs-overview" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-logs-overview plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-logs-overview'] --- import kbnObservabilityLogsOverviewObj from './kbn_observability_logs_overview.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 29 | 0 | 27 | 4 | +| 29 | 0 | 27 | 5 | ## Client diff --git a/api_docs/kbn_observability_synthetics_test_data.mdx b/api_docs/kbn_observability_synthetics_test_data.mdx index 00c804f5a59b..af1fe1705222 100644 --- a/api_docs/kbn_observability_synthetics_test_data.mdx +++ b/api_docs/kbn_observability_synthetics_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-synthetics-test-data title: "@kbn/observability-synthetics-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-synthetics-test-data plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-synthetics-test-data'] --- import kbnObservabilitySyntheticsTestDataObj from './kbn_observability_synthetics_test_data.devdocs.json'; diff --git a/api_docs/kbn_openapi_bundler.mdx b/api_docs/kbn_openapi_bundler.mdx index a3b31041f8d5..f1bbdfac697b 100644 --- a/api_docs/kbn_openapi_bundler.mdx +++ b/api_docs/kbn_openapi_bundler.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-bundler title: "@kbn/openapi-bundler" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-bundler plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-bundler'] --- import kbnOpenapiBundlerObj from './kbn_openapi_bundler.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index bfbee2a394d5..5626be167782 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index a7642e2dbb0a..84b58776b775 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2024-11-22 +date: 2024-12-03 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 ae2d900614b1..959b2ad43026 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2024-11-22 +date: 2024-12-03 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 9e34f64c111c..95aabcc3d407 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_panel_loader.mdx b/api_docs/kbn_panel_loader.mdx index 68dfa1d652ba..37e99b6c8f23 100644 --- a/api_docs/kbn_panel_loader.mdx +++ b/api_docs/kbn_panel_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-panel-loader title: "@kbn/panel-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/panel-loader plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/panel-loader'] --- import kbnPanelLoaderObj from './kbn_panel_loader.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 4d531e84c0a4..01143124a811 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_check.mdx b/api_docs/kbn_plugin_check.mdx index ce6ca411a31f..a8529cd3e4b9 100644 --- a/api_docs/kbn_plugin_check.mdx +++ b/api_docs/kbn_plugin_check.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-check title: "@kbn/plugin-check" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-check plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-check'] --- import kbnPluginCheckObj from './kbn_plugin_check.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index f491d9819e1e..cd46b3b93b5a 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2024-11-22 +date: 2024-12-03 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 31c4fdab59b2..d209418616b1 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_presentation_containers.mdx b/api_docs/kbn_presentation_containers.mdx index 76f53faf4dde..45859f56729f 100644 --- a/api_docs/kbn_presentation_containers.mdx +++ b/api_docs/kbn_presentation_containers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-containers title: "@kbn/presentation-containers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-containers plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-containers'] --- import kbnPresentationContainersObj from './kbn_presentation_containers.devdocs.json'; diff --git a/api_docs/kbn_presentation_publishing.devdocs.json b/api_docs/kbn_presentation_publishing.devdocs.json index 59b096c6077e..46dd41e293a4 100644 --- a/api_docs/kbn_presentation_publishing.devdocs.json +++ b/api_docs/kbn_presentation_publishing.devdocs.json @@ -930,6 +930,46 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.apiPublishesRendered", + "type": "Function", + "tags": [], + "label": "apiPublishesRendered", + "description": [], + "signature": [ + "(unknownApi: unknown) => unknownApi is ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesRendered", + "text": "PublishesRendered" + } + ], + "path": "packages/presentation/presentation_publishing/interfaces/publishes_rendered.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.apiPublishesRendered.$1", + "type": "Unknown", + "tags": [], + "label": "unknownApi", + "description": [], + "signature": [ + "unknown" + ], + "path": "packages/presentation/presentation_publishing/interfaces/publishes_rendered.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-public.apiPublishesSavedObjectId", @@ -3413,6 +3453,22 @@ "deprecated": true, "trackAdoption": false, "references": [ + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts" + }, + { + "plugin": "lens", + "path": "x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts" + }, { "plugin": "dashboard", "path": "src/plugins/dashboard/public/dashboard_actions/add_to_library_action.tsx" @@ -6068,6 +6124,184 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.PublishesRendered", + "type": "Interface", + "tags": [], + "label": "PublishesRendered", + "description": [], + "path": "packages/presentation/presentation_publishing/interfaces/publishes_rendered.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.PublishesRendered.rendered$", + "type": "Object", + "tags": [], + "label": "rendered$", + "description": [], + "signature": [ + "{ source: ", + "Observable", + " | undefined; readonly value: boolean; error: (err: any) => void; forEach: { (next: (value: boolean) => void): Promise; (next: (value: boolean) => void, promiseCtor: PromiseConstructorLike): Promise; }; complete: () => void; getValue: () => boolean; closed: boolean; pipe: { (): ", + "Observable", + "; (op1: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + "): ", + "Observable", + "; (op1: ", + "OperatorFunction", + ", op2: ", + "OperatorFunction", + ", op3: ", + "OperatorFunction", + ", op4: ", + "OperatorFunction", + ", op5: ", + "OperatorFunction", + ", op6: ", + "OperatorFunction", + ", op7: ", + "OperatorFunction", + ", op8: ", + "OperatorFunction", + ", op9: ", + "OperatorFunction", + ", ...operations: ", + "OperatorFunction", + "[]): ", + "Observable", + "; }; operator: ", + "Operator", + " | undefined; lift: (operator: ", + "Operator", + ") => ", + "Observable", + "; subscribe: { (observerOrNext?: Partial<", + "Observer", + "> | ((value: boolean) => void) | undefined): ", + "Subscription", + "; (next?: ((value: boolean) => void) | null | undefined, error?: ((error: any) => void) | null | undefined, complete?: (() => void) | null | undefined): ", + "Subscription", + "; }; toPromise: { (): Promise; (PromiseCtor: PromiseConstructor): Promise; (PromiseCtor: PromiseConstructorLike): Promise; }; observers: ", + "Observer", + "[]; isStopped: boolean; hasError: boolean; thrownError: any; unsubscribe: () => void; readonly observed: boolean; asObservable: () => ", + "Observable", + "; }" + ], + "path": "packages/presentation/presentation_publishing/interfaces/publishes_rendered.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-public.PublishesSavedObjectId", @@ -7789,6 +8023,36 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/presentation-publishing", + "id": "def-public.PublishesWritableDataViews", + "type": "Type", + "tags": [], + "label": "PublishesWritableDataViews", + "description": [], + "signature": [ + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesDataViews", + "text": "PublishesDataViews" + }, + " & { setDataViews: (dataViews: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[]) => void; }" + ], + "path": "packages/presentation/presentation_publishing/interfaces/publishes_data_views.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/presentation-publishing", "id": "def-public.PublishesWritablePanelDescription", diff --git a/api_docs/kbn_presentation_publishing.mdx b/api_docs/kbn_presentation_publishing.mdx index a98c656953af..55e3be661aca 100644 --- a/api_docs/kbn_presentation_publishing.mdx +++ b/api_docs/kbn_presentation_publishing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-presentation-publishing title: "@kbn/presentation-publishing" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/presentation-publishing plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/presentation-publishing'] --- import kbnPresentationPublishingObj from './kbn_presentation_publishing.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 224 | 0 | 188 | 6 | +| 229 | 0 | 193 | 6 | ## Client diff --git a/api_docs/kbn_product_doc_artifact_builder.mdx b/api_docs/kbn_product_doc_artifact_builder.mdx index 4e062192a740..1d145c296392 100644 --- a/api_docs/kbn_product_doc_artifact_builder.mdx +++ b/api_docs/kbn_product_doc_artifact_builder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-product-doc-artifact-builder title: "@kbn/product-doc-artifact-builder" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/product-doc-artifact-builder plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/product-doc-artifact-builder'] --- import kbnProductDocArtifactBuilderObj from './kbn_product_doc_artifact_builder.devdocs.json'; diff --git a/api_docs/kbn_product_doc_common.devdocs.json b/api_docs/kbn_product_doc_common.devdocs.json index 57e3e65f89df..f5c8ea4e0e65 100644 --- a/api_docs/kbn_product_doc_common.devdocs.json +++ b/api_docs/kbn_product_doc_common.devdocs.json @@ -426,7 +426,7 @@ "label": "productDocIndexPrefix", "description": [], "signature": [ - "\".kibana-ai-product-doc\"" + "\".kibana_ai_product_doc\"" ], "path": "x-pack/packages/ai-infra/product-doc-common/src/indices.ts", "deprecated": false, diff --git a/api_docs/kbn_product_doc_common.mdx b/api_docs/kbn_product_doc_common.mdx index 87420cf0ec64..ff9efa88f98b 100644 --- a/api_docs/kbn_product_doc_common.mdx +++ b/api_docs/kbn_product_doc_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-product-doc-common title: "@kbn/product-doc-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/product-doc-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/product-doc-common'] --- import kbnProductDocCommonObj from './kbn_product_doc_common.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 86bbfdebcf80..32ba388ea429 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index 5e78dfdfe2b3..c19773b55d58 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 2f04de9d9475..6e6c4e356054 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_hooks.mdx b/api_docs/kbn_react_hooks.mdx index 20730bfcd0c0..3499369aa5cc 100644 --- a/api_docs/kbn_react_hooks.mdx +++ b/api_docs/kbn_react_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-hooks title: "@kbn/react-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-hooks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-hooks'] --- import kbnReactHooksObj from './kbn_react_hooks.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 6cd0690a0226..42b1829b1a1f 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 4b5ee413441a..b87aca0b8cc8 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index 754855fb36a5..caf56b307d1c 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index c6c54a1d5b1d..9459e13934e8 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index e44baaccadf5..a81f9b215954 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index 51f325742ccd..7aedab1a9b11 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_recently_accessed.mdx b/api_docs/kbn_recently_accessed.mdx index 4a846cc75a52..78d6597cdca3 100644 --- a/api_docs/kbn_recently_accessed.mdx +++ b/api_docs/kbn_recently_accessed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-recently-accessed title: "@kbn/recently-accessed" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/recently-accessed plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/recently-accessed'] --- import kbnRecentlyAccessedObj from './kbn_recently_accessed.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index 974d732be038..9fed1ad6757a 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 30aa9b8910a5..b9f838f9b076 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index 4cdfaae3a8f6..e557cff63b8d 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.devdocs.json b/api_docs/kbn_repo_source_classifier.devdocs.json index 0d96329a321b..05f9cc5a8323 100644 --- a/api_docs/kbn_repo_source_classifier.devdocs.json +++ b/api_docs/kbn_repo_source_classifier.devdocs.json @@ -76,7 +76,13 @@ "description": [], "signature": [ "(absolute: string) => ", - "ModuleId" + { + "pluginId": "@kbn/repo-source-classifier", + "scope": "common", + "docId": "kibKbnRepoSourceClassifierPluginApi", + "section": "def-common.ModuleId", + "text": "ModuleId" + } ], "path": "packages/kbn-repo-source-classifier/src/repo_source_classifier.ts", "deprecated": false, @@ -105,7 +111,133 @@ } ], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId", + "type": "Interface", + "tags": [], + "label": "ModuleId", + "description": [], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.type", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [ + "Type of the module" + ], + "signature": [ + "\"non-package\" | \"tests or mocks\" | \"static\" | \"tooling\" | \"server package\" | \"browser package\" | \"common package\"" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.group", + "type": "CompoundType", + "tags": [], + "label": "group", + "description": [ + "Specifies the group to which this module belongs" + ], + "signature": [ + "\"search\" | \"security\" | \"observability\" | \"platform\" | \"common\"" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.visibility", + "type": "CompoundType", + "tags": [], + "label": "visibility", + "description": [ + "Specifies the module visibility, i.e. whether it can be accessed by everybody or only modules in the same group" + ], + "signature": [ + "\"private\" | \"shared\"" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.repoRel", + "type": "string", + "tags": [], + "label": "repoRel", + "description": [ + "repo relative path to the module's source file" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.pkgInfo", + "type": "Object", + "tags": [], + "label": "pkgInfo", + "description": [ + "info about the package the source file is within, in the case the file is found within a package" + ], + "signature": [ + "PkgInfo", + " | undefined" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.manifest", + "type": "CompoundType", + "tags": [], + "label": "manifest", + "description": [ + "The type of package, as described in the manifest" + ], + "signature": [ + "KibanaPackageManifest", + " | undefined" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/repo-source-classifier", + "id": "def-common.ModuleId.dirs", + "type": "Array", + "tags": [], + "label": "dirs", + "description": [ + "path segments of the dirname of this" + ], + "signature": [ + "string[]" + ], + "path": "packages/kbn-repo-source-classifier/src/module_id.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [ { diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index e058f3289b52..beb73cf75b9e 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; @@ -21,13 +21,16 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 6 | 0 | 6 | 1 | +| 14 | 0 | 7 | 1 | ## Common ### Classes +### Interfaces + + ### Consts, variables and types diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 7df0a1957e2e..f093fe90c5b8 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_csv_share_panel.mdx b/api_docs/kbn_reporting_csv_share_panel.mdx index e55c53489e81..82e042aef1c8 100644 --- a/api_docs/kbn_reporting_csv_share_panel.mdx +++ b/api_docs/kbn_reporting_csv_share_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-csv-share-panel title: "@kbn/reporting-csv-share-panel" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-csv-share-panel plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-csv-share-panel'] --- import kbnReportingCsvSharePanelObj from './kbn_reporting_csv_share_panel.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv.devdocs.json b/api_docs/kbn_reporting_export_types_csv.devdocs.json index cab900fc5f38..9e4bdaccb78c 100644 --- a/api_docs/kbn_reporting_export_types_csv.devdocs.json +++ b/api_docs/kbn_reporting_export_types_csv.devdocs.json @@ -168,7 +168,7 @@ "section": "def-server.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -192,7 +192,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -565,7 +565,7 @@ "section": "def-server.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -589,7 +589,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_reporting_export_types_csv.mdx b/api_docs/kbn_reporting_export_types_csv.mdx index 304dfce60f47..3f70bdb817dc 100644 --- a/api_docs/kbn_reporting_export_types_csv.mdx +++ b/api_docs/kbn_reporting_export_types_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv title: "@kbn/reporting-export-types-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv'] --- import kbnReportingExportTypesCsvObj from './kbn_reporting_export_types_csv.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_csv_common.mdx b/api_docs/kbn_reporting_export_types_csv_common.mdx index ac431b442f31..3cc02580d869 100644 --- a/api_docs/kbn_reporting_export_types_csv_common.mdx +++ b/api_docs/kbn_reporting_export_types_csv_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-csv-common title: "@kbn/reporting-export-types-csv-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-csv-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-csv-common'] --- import kbnReportingExportTypesCsvCommonObj from './kbn_reporting_export_types_csv_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf.devdocs.json b/api_docs/kbn_reporting_export_types_pdf.devdocs.json index 9e06d9c81052..f0fb7f203f94 100644 --- a/api_docs/kbn_reporting_export_types_pdf.devdocs.json +++ b/api_docs/kbn_reporting_export_types_pdf.devdocs.json @@ -176,7 +176,7 @@ "section": "def-server.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -200,7 +200,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -597,7 +597,7 @@ "section": "def-server.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -621,7 +621,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_reporting_export_types_pdf.mdx b/api_docs/kbn_reporting_export_types_pdf.mdx index 2fb6e8f28c6e..fc4a512b1afa 100644 --- a/api_docs/kbn_reporting_export_types_pdf.mdx +++ b/api_docs/kbn_reporting_export_types_pdf.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf title: "@kbn/reporting-export-types-pdf" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf'] --- import kbnReportingExportTypesPdfObj from './kbn_reporting_export_types_pdf.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_pdf_common.mdx b/api_docs/kbn_reporting_export_types_pdf_common.mdx index 94093ebe7b97..ef46224ef48f 100644 --- a/api_docs/kbn_reporting_export_types_pdf_common.mdx +++ b/api_docs/kbn_reporting_export_types_pdf_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-pdf-common title: "@kbn/reporting-export-types-pdf-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-pdf-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-pdf-common'] --- import kbnReportingExportTypesPdfCommonObj from './kbn_reporting_export_types_pdf_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png.devdocs.json b/api_docs/kbn_reporting_export_types_png.devdocs.json index 7553df09eef8..99fb9ba2966b 100644 --- a/api_docs/kbn_reporting_export_types_png.devdocs.json +++ b/api_docs/kbn_reporting_export_types_png.devdocs.json @@ -176,7 +176,7 @@ "section": "def-server.CoreSetup", "text": "CoreSetup" }, - ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + ", config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -200,7 +200,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_reporting_export_types_png.mdx b/api_docs/kbn_reporting_export_types_png.mdx index d0fe624eec46..16a17ea81b44 100644 --- a/api_docs/kbn_reporting_export_types_png.mdx +++ b/api_docs/kbn_reporting_export_types_png.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png title: "@kbn/reporting-export-types-png" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png'] --- import kbnReportingExportTypesPngObj from './kbn_reporting_export_types_png.devdocs.json'; diff --git a/api_docs/kbn_reporting_export_types_png_common.mdx b/api_docs/kbn_reporting_export_types_png_common.mdx index e24ecc217488..6ae5fbbc4999 100644 --- a/api_docs/kbn_reporting_export_types_png_common.mdx +++ b/api_docs/kbn_reporting_export_types_png_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-export-types-png-common title: "@kbn/reporting-export-types-png-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-export-types-png-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-export-types-png-common'] --- import kbnReportingExportTypesPngCommonObj from './kbn_reporting_export_types_png_common.devdocs.json'; diff --git a/api_docs/kbn_reporting_mocks_server.devdocs.json b/api_docs/kbn_reporting_mocks_server.devdocs.json index 043566a99e0e..2ad48d68483b 100644 --- a/api_docs/kbn_reporting_mocks_server.devdocs.json +++ b/api_docs/kbn_reporting_mocks_server.devdocs.json @@ -29,7 +29,7 @@ "signature": [ "(overrides?: ", "_DeepPartialObject", - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -37,7 +37,7 @@ "section": "def-common.ByteSizeValue", "text": "ByteSizeValue" }, - "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>) => Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; useByteOrderMarkEncoding: boolean; maxConcurrentShardRequests: number; }>; capture: Readonly<{} & { maxAttempts: number; }>; roles: Readonly<{} & { enabled: boolean; allow: string[]; }>; kibanaServer: Readonly<{ hostname?: string | undefined; protocol?: string | undefined; port?: number | undefined; } & {}>; queue: Readonly<{} & { timeout: number | moment.Duration; pollInterval: number | moment.Duration; indexInterval: string; pollEnabled: boolean; pollIntervalErrorMultiplier: number; }>; poll: Readonly<{} & { jobCompletionNotifier: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; jobsRefresh: Readonly<{} & { interval: number; intervalErrorMultiplier: number; }>; }>; export_types: Readonly<{} & { csv: Readonly<{} & { enabled: boolean; }>; png: Readonly<{} & { enabled: boolean; }>; pdf: Readonly<{} & { enabled: boolean; }>; }>; statefulSettings: Readonly<{} & { enabled: boolean; }>; }>>) => Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -60,7 +60,7 @@ "description": [], "signature": [ "_DeepPartialObject", - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_reporting_mocks_server.mdx b/api_docs/kbn_reporting_mocks_server.mdx index 7800bc83c9d2..d2db28bae21b 100644 --- a/api_docs/kbn_reporting_mocks_server.mdx +++ b/api_docs/kbn_reporting_mocks_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-mocks-server title: "@kbn/reporting-mocks-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-mocks-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-mocks-server'] --- import kbnReportingMocksServerObj from './kbn_reporting_mocks_server.devdocs.json'; diff --git a/api_docs/kbn_reporting_public.mdx b/api_docs/kbn_reporting_public.mdx index b2c81f42f8b4..58115068d6d1 100644 --- a/api_docs/kbn_reporting_public.mdx +++ b/api_docs/kbn_reporting_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-public title: "@kbn/reporting-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-public plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-public'] --- import kbnReportingPublicObj from './kbn_reporting_public.devdocs.json'; diff --git a/api_docs/kbn_reporting_server.devdocs.json b/api_docs/kbn_reporting_server.devdocs.json index 2edf31cbaf9e..29373857cb9d 100644 --- a/api_docs/kbn_reporting_server.devdocs.json +++ b/api_docs/kbn_reporting_server.devdocs.json @@ -416,7 +416,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -467,7 +467,7 @@ "section": "def-server.PluginInitializerContext", "text": "PluginInitializerContext" }, - "; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -949,7 +949,7 @@ "label": "getFullRedirectAppUrl", "description": [], "signature": [ - "(config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "(config: Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -973,7 +973,7 @@ "label": "config", "description": [], "signature": [ - "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "Readonly<{ encryptionKey?: string | undefined; } & { enabled: boolean; csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -1661,7 +1661,7 @@ "label": "ReportingConfigType", "description": [], "signature": [ - "{ readonly encryptionKey?: string | undefined; readonly enabled: boolean; readonly csv: Readonly<{} & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; enablePanelActionDownload: boolean; maxSizeBytes: number | ", + "{ readonly encryptionKey?: string | undefined; readonly enabled: boolean; readonly csv: Readonly<{ enablePanelActionDownload?: boolean | undefined; } & { scroll: Readonly<{} & { size: number; duration: string; strategy: \"scroll\" | \"pit\"; }>; checkForFormulas: boolean; escapeFormulaValues: boolean; maxSizeBytes: number | ", { "pluginId": "@kbn/config-schema", "scope": "common", @@ -1949,7 +1949,7 @@ "section": "def-common.Type", "text": "Type" }, - "; maxSizeBytes: ", + "; maxSizeBytes: ", { "pluginId": "@kbn/config-schema", "scope": "common", diff --git a/api_docs/kbn_reporting_server.mdx b/api_docs/kbn_reporting_server.mdx index 4e74a76505d6..e4078c796b5c 100644 --- a/api_docs/kbn_reporting_server.mdx +++ b/api_docs/kbn_reporting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-server title: "@kbn/reporting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-server'] --- import kbnReportingServerObj from './kbn_reporting_server.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 002eab56e827..b69b31c42766 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_response_ops_feature_flag_service.mdx b/api_docs/kbn_response_ops_feature_flag_service.mdx index d777149cd330..323a53ab8beb 100644 --- a/api_docs/kbn_response_ops_feature_flag_service.mdx +++ b/api_docs/kbn_response_ops_feature_flag_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-feature-flag-service title: "@kbn/response-ops-feature-flag-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-feature-flag-service plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-feature-flag-service'] --- import kbnResponseOpsFeatureFlagServiceObj from './kbn_response_ops_feature_flag_service.devdocs.json'; diff --git a/api_docs/kbn_response_ops_rule_params.mdx b/api_docs/kbn_response_ops_rule_params.mdx index f0e59e494c8b..c3e71da7ac36 100644 --- a/api_docs/kbn_response_ops_rule_params.mdx +++ b/api_docs/kbn_response_ops_rule_params.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-response-ops-rule-params title: "@kbn/response-ops-rule-params" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/response-ops-rule-params plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/response-ops-rule-params'] --- import kbnResponseOpsRuleParamsObj from './kbn_response_ops_rule_params.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index af96ca9b3820..fe5fd4236fe4 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rollup.mdx b/api_docs/kbn_rollup.mdx index 17dc5651ef5a..2f7a740e3cbf 100644 --- a/api_docs/kbn_rollup.mdx +++ b/api_docs/kbn_rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rollup title: "@kbn/rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rollup plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rollup'] --- import kbnRollupObj from './kbn_rollup.devdocs.json'; diff --git a/api_docs/kbn_router_to_openapispec.mdx b/api_docs/kbn_router_to_openapispec.mdx index 870d1ef869b5..7157417647b2 100644 --- a/api_docs/kbn_router_to_openapispec.mdx +++ b/api_docs/kbn_router_to_openapispec.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-to-openapispec title: "@kbn/router-to-openapispec" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-to-openapispec plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-to-openapispec'] --- import kbnRouterToOpenapispecObj from './kbn_router_to_openapispec.devdocs.json'; diff --git a/api_docs/kbn_router_utils.mdx b/api_docs/kbn_router_utils.mdx index 958014037334..a916eba9f065 100644 --- a/api_docs/kbn_router_utils.mdx +++ b/api_docs/kbn_router_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-router-utils title: "@kbn/router-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/router-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/router-utils'] --- import kbnRouterUtilsObj from './kbn_router_utils.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index 9e2cea991b59..7d311e0e8872 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index f7d51280be1a..3899d5cc19ef 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 09a29804d2de..e6c7e1e08ae1 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_saved_search_component.devdocs.json b/api_docs/kbn_saved_search_component.devdocs.json new file mode 100644 index 000000000000..faaed21b5130 --- /dev/null +++ b/api_docs/kbn_saved_search_component.devdocs.json @@ -0,0 +1,301 @@ +{ + "id": "@kbn/saved-search-component", + "client": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.LazySavedSearchComponent", + "type": "Function", + "tags": [], + "label": "LazySavedSearchComponent", + "description": [], + "signature": [ + "React.ForwardRefExoticComponent<", + { + "pluginId": "@kbn/saved-search-component", + "scope": "public", + "docId": "kibKbnSavedSearchComponentPluginApi", + "section": "def-public.SavedSearchComponentProps", + "text": "SavedSearchComponentProps" + }, + " & React.RefAttributes<{}>>" + ], + "path": "packages/kbn-saved-search-component/index.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.LazySavedSearchComponent.$1", + "type": "Uncategorized", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "P" + ], + "path": "node_modules/@types/react/ts5.0/index.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies", + "type": "Interface", + "tags": [], + "label": "SavedSearchComponentDependencies", + "description": [], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies.embeddable", + "type": "Object", + "tags": [], + "label": "embeddable", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableStart", + "text": "EmbeddableStart" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies.searchSource", + "type": "Object", + "tags": [], + "label": "searchSource", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.ISearchStartSearchSource", + "text": "ISearchStartSearchSource" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentDependencies.dataViews", + "type": "Object", + "tags": [], + "label": "dataViews", + "description": [], + "signature": [ + { + "pluginId": "dataViews", + "scope": "public", + "docId": "kibDataViewsPluginApi", + "section": "def-public.DataViewsServicePublic", + "text": "DataViewsServicePublic" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps", + "type": "Interface", + "tags": [], + "label": "SavedSearchComponentProps", + "description": [], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.dependencies", + "type": "Object", + "tags": [], + "label": "dependencies", + "description": [], + "signature": [ + { + "pluginId": "@kbn/saved-search-component", + "scope": "public", + "docId": "kibKbnSavedSearchComponentPluginApi", + "section": "def-public.SavedSearchComponentDependencies", + "text": "SavedSearchComponentDependencies" + } + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.index", + "type": "string", + "tags": [], + "label": "index", + "description": [], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.timeRange", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.query", + "type": "Object", + "tags": [], + "label": "query", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.filters", + "type": "Array", + "tags": [], + "label": "filters", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.timestampField", + "type": "string", + "tags": [], + "label": "timestampField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.height", + "type": "CompoundType", + "tags": [], + "label": "height", + "description": [], + "signature": [ + "Property", + ".Height | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/saved-search-component", + "id": "def-public.SavedSearchComponentProps.displayOptions", + "type": "Object", + "tags": [], + "label": "displayOptions", + "description": [], + "signature": [ + { + "pluginId": "discover", + "scope": "public", + "docId": "kibDiscoverPluginApi", + "section": "def-public.NonPersistedDisplayOptions", + "text": "NonPersistedDisplayOptions" + }, + " | undefined" + ], + "path": "packages/kbn-saved-search-component/src/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_saved_search_component.mdx b/api_docs/kbn_saved_search_component.mdx new file mode 100644 index 000000000000..6d72787f6d76 --- /dev/null +++ b/api_docs/kbn_saved_search_component.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: kibKbnSavedSearchComponentPluginApi +slug: /kibana-dev-docs/api/kbn-saved-search-component +title: "@kbn/saved-search-component" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/saved-search-component plugin +date: 2024-12-03 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-search-component'] +--- +import kbnSavedSearchComponentObj from './kbn_saved_search_component.devdocs.json'; + + + +Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 15 | 0 | 14 | 0 | + +## Client + +### Functions + + +### Interfaces + + diff --git a/api_docs/kbn_scout.devdocs.json b/api_docs/kbn_scout.devdocs.json new file mode 100644 index 000000000000..8d2b4e60a782 --- /dev/null +++ b/api_docs/kbn_scout.devdocs.json @@ -0,0 +1,2203 @@ +{ + "id": "@kbn/scout", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client", + "type": "Class", + "tags": [], + "label": "Client", + "description": [], + "signature": [ + "default", + " extends ", + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.diagnostic", + "type": "Object", + "tags": [], + "label": "diagnostic", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.name", + "type": "CompoundType", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string | symbol" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.connectionPool", + "type": "Object", + "tags": [], + "label": "connectionPool", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.transport", + "type": "Object", + "tags": [], + "label": "transport", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.serializer", + "type": "Object", + "tags": [], + "label": "serializer", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.helpers", + "type": "Object", + "tags": [], + "label": "helpers", + "description": [], + "signature": [ + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "opts", + "description": [], + "signature": [ + "ClientOptions" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.child", + "type": "Function", + "tags": [], + "label": "child", + "description": [], + "signature": [ + "(opts: ", + "ClientOptions", + ") => ", + "default" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.child.$1", + "type": "Object", + "tags": [], + "label": "opts", + "description": [], + "signature": [ + "ClientOptions" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.Client.close", + "type": "Function", + "tags": [], + "label": "close", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "node_modules/@elastic/elasticsearch/lib/client.d.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient", + "type": "Class", + "tags": [], + "label": "KbnClient", + "description": [], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.status", + "type": "Object", + "tags": [], + "label": "status", + "description": [], + "signature": [ + "KbnClientStatus" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.plugins", + "type": "Object", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "KbnClientPlugins" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.version", + "type": "Object", + "tags": [], + "label": "version", + "description": [], + "signature": [ + "KbnClientVersion" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.savedObjects", + "type": "Object", + "tags": [], + "label": "savedObjects", + "description": [], + "signature": [ + "KbnClientSavedObjects" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.spaces", + "type": "Object", + "tags": [], + "label": "spaces", + "description": [], + "signature": [ + "KbnClientSpaces" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [], + "signature": [ + "KbnClientUiSettings" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.importExport", + "type": "Object", + "tags": [], + "label": "importExport", + "description": [], + "signature": [ + "KbnClientImportExport" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [ + "\nBasic Kibana server client that implements common behaviors for talking\nto the Kibana server from dev tooling." + ], + "signature": [ + "any" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.KbnClientOptions", + "text": "KbnClientOptions" + } + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.request", + "type": "Function", + "tags": [], + "label": "request", + "description": [ + "\nMake a direct request to the Kibana server" + ], + "signature": [ + "(options: ", + "ReqOptions", + ") => Promise<", + "AxiosResponse", + ">" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.request.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + "ReqOptions" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.resolveUrl", + "type": "Function", + "tags": [], + "label": "resolveUrl", + "description": [], + "signature": [ + "(relativeUrl: string) => string" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KbnClient.resolveUrl.$1", + "type": "string", + "tags": [], + "label": "relativeUrl", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/kbn_client/kbn_client.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl", + "type": "Class", + "tags": [], + "label": "KibanaUrl", + "description": [], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.baseUrl", + "type": "Object", + "tags": [], + "label": "#baseUrl", + "description": [], + "signature": [ + "URL" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "baseUrl", + "description": [], + "signature": [ + "URL" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.get", + "type": "Function", + "tags": [], + "label": "get", + "description": [ + "\nGet an absolute URL based on Kibana's URL" + ], + "signature": [ + "(rel?: string | undefined, options?: ", + "PathOptions", + " | undefined) => string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.get.$1", + "type": "string", + "tags": [], + "label": "rel", + "description": [ + "relative url, resolved relative to Kibana's url" + ], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.get.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "optional modifications to apply to the URL" + ], + "signature": [ + "PathOptions", + " | undefined" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.app", + "type": "Function", + "tags": [], + "label": "app", + "description": [ + "\nGet the URL for an app" + ], + "signature": [ + "(appName: string, options?: ", + "PathOptions", + " | undefined) => string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.app.$1", + "type": "string", + "tags": [], + "label": "appName", + "description": [ + "name of the app to get the URL for" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.app.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [ + "optional modifications to apply to the URL" + ], + "signature": [ + "PathOptions", + " | undefined" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.KibanaUrl.toString", + "type": "Function", + "tags": [], + "label": "toString", + "description": [], + "signature": [ + "() => string" + ], + "path": "packages/kbn-scout/src/common/services/kibana_url.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager", + "type": "Class", + "tags": [], + "label": "SamlSessionManager", + "description": [ + "\nManages cookies associated with user roles" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.SamlSessionManagerOptions", + "text": "SamlSessionManagerOptions" + } + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getApiCredentialsForRole", + "type": "Function", + "tags": [], + "label": "getApiCredentialsForRole", + "description": [], + "signature": [ + "(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined) => Promise<{ Cookie: string; }>" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getApiCredentialsForRole.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getApiCredentialsForRole.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getInteractiveUserSessionCookieWithRoleScope", + "type": "Function", + "tags": [], + "label": "getInteractiveUserSessionCookieWithRoleScope", + "description": [], + "signature": [ + "(role: string, options?: ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined) => Promise" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getInteractiveUserSessionCookieWithRoleScope.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getInteractiveUserSessionCookieWithRoleScope.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.GetCookieOptions", + "text": "GetCookieOptions" + }, + " | undefined" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getEmail", + "type": "Function", + "tags": [], + "label": "getEmail", + "description": [], + "signature": [ + "(role: string) => Promise" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getEmail.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getUserData", + "type": "Function", + "tags": [], + "label": "getUserData", + "description": [], + "signature": [ + "(role: string) => Promise<", + "UserProfile", + ">" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.SamlSessionManager.getUserData.$1", + "type": "string", + "tags": [], + "label": "role", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/auth/session_manager.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog", + "type": "Class", + "tags": [], + "label": "ToolingLog", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + }, + " implements ", + { + "pluginId": "@kbn/some-dev-log", + "scope": "common", + "docId": "kibKbnSomeDevLogPluginApi", + "section": "def-common.SomeDevLog", + "text": "SomeDevLog" + } + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "writerConfig", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLogTextWriterConfig", + "text": "ToolingLogTextWriterConfig" + }, + " | undefined" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLogOptions", + "text": "ToolingLogOptions" + }, + " | undefined" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.getIndent", + "type": "Function", + "tags": [], + "label": "getIndent", + "description": [ + "\nGet the current indentation level of the ToolingLog" + ], + "signature": [ + "() => number" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.indent", + "type": "Function", + "tags": [], + "label": "indent", + "description": [], + "signature": [ + "{ (delta: number): void; (delta: number, block: () => Promise): Promise; (delta: number, block: () => T): T; }" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.indent.$1", + "type": "number", + "tags": [], + "label": "delta", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.indent.$2", + "type": "Function", + "tags": [], + "label": "block", + "description": [], + "signature": [ + "(() => T | Promise) | undefined" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.verbose", + "type": "Function", + "tags": [], + "label": "verbose", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.verbose.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.debug", + "type": "Function", + "tags": [], + "label": "debug", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.debug.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.info", + "type": "Function", + "tags": [], + "label": "info", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.info.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.success", + "type": "Function", + "tags": [], + "label": "success", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.success.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.warning", + "type": "Function", + "tags": [], + "label": "warning", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.warning.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.error", + "type": "Function", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "(error: string | Error) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.error.$1", + "type": "CompoundType", + "tags": [], + "label": "error", + "description": [], + "signature": [ + "string | Error" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.write", + "type": "Function", + "tags": [], + "label": "write", + "description": [], + "signature": [ + "(...args: any[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.write.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "any[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.getWriters", + "type": "Function", + "tags": [], + "label": "getWriters", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Writer", + "text": "Writer" + }, + "[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.setWriters", + "type": "Function", + "tags": [], + "label": "setWriters", + "description": [], + "signature": [ + "(writers: ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Writer", + "text": "Writer" + }, + "[]) => void" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.setWriters.$1", + "type": "Array", + "tags": [], + "label": "writers", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Writer", + "text": "Writer" + }, + "[]" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.getWritten$", + "type": "Function", + "tags": [], + "label": "getWritten$", + "description": [], + "signature": [ + "() => ", + "Observable", + "<", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.Message", + "text": "Message" + }, + ">" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.withType", + "type": "Function", + "tags": [], + "label": "withType", + "description": [ + "\nCreate a new ToolingLog which sets a different \"type\", allowing messages to be filtered out by \"source\"" + ], + "signature": [ + "(type: string) => ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ToolingLog.withType.$1", + "type": "string", + "tags": [], + "label": "type", + "description": [ + "A string that will be passed along with messages from this logger which can be used to filter messages with `ignoreSources`" + ], + "signature": [ + "string" + ], + "path": "packages/kbn-tooling-log/src/tooling_log.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + } + ], + "functions": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.createLazyPageObject", + "type": "Function", + "tags": [], + "label": "createLazyPageObject", + "description": [ + "\nCreates a lazily instantiated proxy for a Page Object class, deferring the creation of the instance until\na property or method is accessed. It helps avoiding instantiation of page objects that may not be used\nin certain test scenarios.\n" + ], + "signature": [ + "(PageObjectClass: new (page: ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPage", + "text": "ScoutPage" + }, + ", ...args: any[]) => T, scoutPage: ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPage", + "text": "ScoutPage" + }, + ", constructorArgs: any[]) => T" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/utils/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.createLazyPageObject.$1", + "type": "Object", + "tags": [], + "label": "PageObjectClass", + "description": [ + "- The page object class to be instantiated lazily." + ], + "signature": [ + "new (page: ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPage", + "text": "ScoutPage" + }, + ", ...args: any[]) => T" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/utils/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.createLazyPageObject.$2", + "type": "CompoundType", + "tags": [], + "label": "scoutPage", + "description": [ + "- ScoutPage instance, that extendes the Playwright `page` fixture and passed to the page object class constructor." + ], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPage", + "text": "ScoutPage" + } + ], + "path": "packages/kbn-scout/src/playwright/page_objects/utils/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.createLazyPageObject.$3", + "type": "Array", + "tags": [], + "label": "constructorArgs", + "description": [ + "- Additional arguments to be passed to the page object class constructor." + ], + "signature": [ + "any[]" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/utils/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "A proxy object that behaves like an instance of the page object class, instantiating it on demand." + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.createPlaywrightConfig", + "type": "Function", + "tags": [], + "label": "createPlaywrightConfig", + "description": [], + "signature": [ + "(options: ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPlaywrightOptions", + "text": "ScoutPlaywrightOptions" + }, + ") => ", + "PlaywrightTestConfig", + "<{}, {}>" + ], + "path": "packages/kbn-scout/src/playwright/config/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.createPlaywrightConfig.$1", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPlaywrightOptions", + "text": "ScoutPlaywrightOptions" + } + ], + "path": "packages/kbn-scout/src/playwright/config/index.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.expect", + "type": "Function", + "tags": [], + "label": "expect", + "description": [], + "signature": [ + "{ (actual: T, messageOrOptions?: string | { message?: string | undefined; } | undefined): MakeMatchers; soft: (actual: T, messageOrOptions?: string | { message?: string | undefined; } | undefined) => MakeMatchers; poll: (actual: () => T | Promise, messageOrOptions?: string | { message?: string | undefined; timeout?: number | undefined; intervals?: number[] | undefined; } | undefined) => GenericAssertions> & PlaywrightTest.Matchers, T> & SnapshotAssertions & { not: BaseMatchers, T>; }; extend ", + "MatcherReturnType", + " | Promise<", + "MatcherReturnType", + ">>>(matchers: MoreMatchers): ", + "Expect", + "<{} & MoreMatchers>; configure: (configuration: { message?: string | undefined; timeout?: number | undefined; soft?: boolean | undefined; }) => ", + "Expect", + "<{}>; getState(): unknown; not: Omit; } & AsymmetricMatchers" + ], + "path": "packages/kbn-scout/src/playwright/expect.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.expect.$1", + "type": "Uncategorized", + "tags": [], + "label": "actual", + "description": [], + "signature": [ + "T" + ], + "path": "node_modules/playwright/types/test.d.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.expect.$2", + "type": "CompoundType", + "tags": [], + "label": "messageOrOptions", + "description": [], + "signature": [ + "string | { message?: string | undefined; } | undefined" + ], + "path": "node_modules/playwright/types/test.d.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.runTestsCli", + "type": "Function", + "tags": [], + "label": "runTestsCli", + "description": [ + "\nStart servers and run the tests" + ], + "signature": [ + "() => void" + ], + "path": "packages/kbn-scout/src/cli/run_tests_cli.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.startServersCli", + "type": "Function", + "tags": [], + "label": "startServersCli", + "description": [ + "\nStart servers" + ], + "signature": [ + "() => void" + ], + "path": "packages/kbn-scout/src/cli/start_servers_cli.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.test", + "type": "Function", + "tags": [], + "label": "test", + "description": [], + "signature": [ + "TestType", + "<", + "PlaywrightTestArgs", + " & ", + "PlaywrightTestOptions", + " & { browserAuth: ", + "LoginFixture", + "; } & { page: ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPage", + "text": "ScoutPage" + }, + "; kbnUrl: ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.KibanaUrl", + "text": "KibanaUrl" + }, + "; } & ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutTestFixtures", + "text": "ScoutTestFixtures" + }, + ", ", + "PlaywrightWorkerArgs", + " & ", + "PlaywrightWorkerOptions", + " & ", + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutWorkerFixtures", + "text": "ScoutWorkerFixtures" + }, + ">" + ], + "path": "packages/kbn-scout/src/playwright/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "interfaces": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture", + "type": "Interface", + "tags": [], + "label": "EsArchiverFixture", + "description": [], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture.loadIfNeeded", + "type": "Function", + "tags": [], + "label": "loadIfNeeded", + "description": [], + "signature": [ + "(name: string, performance?: ", + { + "pluginId": "@kbn/es-archiver", + "scope": "common", + "docId": "kibKbnEsArchiverPluginApi", + "section": "def-common.LoadActionPerfOptions", + "text": "LoadActionPerfOptions" + }, + " | undefined) => Promise>" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture.loadIfNeeded.$1", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.EsArchiverFixture.loadIfNeeded.$2", + "type": "Object", + "tags": [], + "label": "performance", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-archiver", + "scope": "common", + "docId": "kibKbnEsArchiverPluginApi", + "section": "def-common.LoadActionPerfOptions", + "text": "LoadActionPerfOptions" + }, + " | undefined" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects", + "type": "Interface", + "tags": [], + "label": "PageObjects", + "description": [], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects.datePicker", + "type": "Object", + "tags": [], + "label": "datePicker", + "description": [], + "signature": [ + "DatePicker" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects.discover", + "type": "Object", + "tags": [], + "label": "discover", + "description": [], + "signature": [ + "DiscoverApp" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects.dashboard", + "type": "Object", + "tags": [], + "label": "dashboard", + "description": [], + "signature": [ + "DashboardApp" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.PageObjects.filterBar", + "type": "Object", + "tags": [], + "label": "filterBar", + "description": [], + "signature": [ + "FilterBar" + ], + "path": "packages/kbn-scout/src/playwright/page_objects/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutPlaywrightOptions", + "type": "Interface", + "tags": [], + "label": "ScoutPlaywrightOptions", + "description": [], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutPlaywrightOptions", + "text": "ScoutPlaywrightOptions" + }, + " extends Pick<", + "PlaywrightTestConfig", + "<{}, {}>, \"testDir\" | \"workers\">" + ], + "path": "packages/kbn-scout/src/playwright/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutPlaywrightOptions.testDir", + "type": "string", + "tags": [], + "label": "testDir", + "description": [], + "path": "packages/kbn-scout/src/playwright/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutPlaywrightOptions.workers", + "type": "CompoundType", + "tags": [], + "label": "workers", + "description": [], + "signature": [ + "2 | 1 | undefined" + ], + "path": "packages/kbn-scout/src/playwright/types/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestFixtures", + "type": "Interface", + "tags": [], + "label": "ScoutTestFixtures", + "description": [], + "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestFixtures.browserAuth", + "type": "Object", + "tags": [], + "label": "browserAuth", + "description": [], + "signature": [ + "LoginFixture" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestFixtures.page", + "type": "CompoundType", + "tags": [], + "label": "page", + "description": [], + "signature": [ + "Page", + " & { gotoApp: (appName: string, options?: { referer?: string | undefined; timeout?: number | undefined; waitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle\" | \"commit\" | undefined; } | undefined) => Promise<", + "Response", + " | null>; waitForLoadingIndicatorHidden: () => Promise<", + "ElementHandle", + " | null>; testSubj: { check: (selector: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; click: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; clickCount?: number | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; dblclick: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; fill: (selector: string, value: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; focus: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; getAttribute: (selector: string, name: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; hover: (selector: string, options?: { force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; innerText: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isEnabled: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isChecked: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isHidden: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isVisible: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; locator: (selector: string, options?: { has?: ", + "Locator", + " | undefined; hasNot?: ", + "Locator", + " | undefined; hasNotText?: string | RegExp | undefined; hasText?: string | RegExp | undefined; } | undefined) => ", + "Locator", + "; waitForSelector: (selector: string, options?: PageWaitForSelectorOptions | undefined) => Promise<", + "ElementHandle", + " | null>; typeWithDelay: (selector: string, text: string, options?: { delay: number; } | undefined) => Promise; clearInput: (selector: string) => Promise; }; }" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestFixtures.pageObjects", + "type": "Object", + "tags": [], + "label": "pageObjects", + "description": [], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.PageObjects", + "text": "PageObjects" + } + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestOptions", + "type": "Interface", + "tags": [], + "label": "ScoutTestOptions", + "description": [], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.ScoutTestOptions", + "text": "ScoutTestOptions" + }, + " extends ", + "PlaywrightTestOptions" + ], + "path": "packages/kbn-scout/src/playwright/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestOptions.serversConfigDir", + "type": "string", + "tags": [], + "label": "serversConfigDir", + "description": [], + "path": "packages/kbn-scout/src/playwright/types/index.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutTestOptions.VALID_CONFIG_MARKER", + "type": "boolean", + "tags": [], + "label": "[VALID_CONFIG_MARKER]", + "description": [], + "path": "packages/kbn-scout/src/playwright/types/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures", + "type": "Interface", + "tags": [], + "label": "ScoutWorkerFixtures", + "description": [], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.log", + "type": "Object", + "tags": [], + "label": "log", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.config", + "type": "Object", + "tags": [], + "label": "config", + "description": [], + "signature": [ + "ScoutServerConfig" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.kbnUrl", + "type": "Object", + "tags": [], + "label": "kbnUrl", + "description": [], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.KibanaUrl", + "text": "KibanaUrl" + } + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.esClient", + "type": "Object", + "tags": [], + "label": "esClient", + "description": [], + "signature": [ + "default" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.kbnClient", + "type": "Object", + "tags": [], + "label": "kbnClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.KbnClient", + "text": "KbnClient" + } + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.uiSettings", + "type": "Object", + "tags": [], + "label": "uiSettings", + "description": [], + "signature": [ + "UiSettingsFixture" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.esArchiver", + "type": "Object", + "tags": [], + "label": "esArchiver", + "description": [], + "signature": [ + { + "pluginId": "@kbn/scout", + "scope": "common", + "docId": "kibKbnScoutPluginApi", + "section": "def-common.EsArchiverFixture", + "text": "EsArchiverFixture" + } + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutWorkerFixtures.samlAuth", + "type": "Object", + "tags": [], + "label": "samlAuth", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.SamlSessionManager", + "text": "SamlSessionManager" + } + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/worker_scope.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/scout", + "id": "def-common.ScoutPage", + "type": "Type", + "tags": [], + "label": "ScoutPage", + "description": [ + "\nExtends the Playwright 'Page' interface with methods specific to Kibana.\nReasons to use 'ReturnType' instead of Explicit Typings:\n- DRY Principle: automatically stays in sync with the Playwright API, reducing maintenance overhead.\n- Future-Proofing: If Playwright changes the return type of methods, these types will update accordingly.\nRecommendation: define Explicit Types as return types only if methods (e.g. 'typeWithDelay')\nhave any additional logic or Kibana-specific behavior." + ], + "signature": [ + "Page", + " & { gotoApp: (appName: string, options?: { referer?: string | undefined; timeout?: number | undefined; waitUntil?: \"load\" | \"domcontentloaded\" | \"networkidle\" | \"commit\" | undefined; } | undefined) => Promise<", + "Response", + " | null>; waitForLoadingIndicatorHidden: () => Promise<", + "ElementHandle", + " | null>; testSubj: { check: (selector: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; click: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; clickCount?: number | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; dblclick: (selector: string, options?: { button?: \"right\" | \"left\" | \"middle\" | undefined; delay?: number | undefined; force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; fill: (selector: string, value: string, options?: { force?: boolean | undefined; noWaitAfter?: boolean | undefined; strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; focus: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; getAttribute: (selector: string, name: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; hover: (selector: string, options?: { force?: boolean | undefined; modifiers?: (\"Alt\" | \"Control\" | \"Meta\" | \"Shift\" | \"ControlOrMeta\")[] | undefined; noWaitAfter?: boolean | undefined; position?: { x: number; y: number; } | undefined; strict?: boolean | undefined; timeout?: number | undefined; trial?: boolean | undefined; } | undefined) => Promise; innerText: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isEnabled: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isChecked: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isHidden: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; isVisible: (selector: string, options?: { strict?: boolean | undefined; timeout?: number | undefined; } | undefined) => Promise; locator: (selector: string, options?: { has?: ", + "Locator", + " | undefined; hasNot?: ", + "Locator", + " | undefined; hasNotText?: string | RegExp | undefined; hasText?: string | RegExp | undefined; } | undefined) => ", + "Locator", + "; waitForSelector: (selector: string, options?: PageWaitForSelectorOptions | undefined) => Promise<", + "ElementHandle", + " | null>; typeWithDelay: (selector: string, text: string, options?: { delay: number; } | undefined) => Promise; clearInput: (selector: string) => Promise; }; }" + ], + "path": "packages/kbn-scout/src/playwright/fixtures/types/test_scope.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_scout.mdx b/api_docs/kbn_scout.mdx new file mode 100644 index 000000000000..b868c759fe85 --- /dev/null +++ b/api_docs/kbn_scout.mdx @@ -0,0 +1,39 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnScoutPluginApi +slug: /kibana-dev-docs/api/kbn-scout +title: "@kbn/scout" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/scout plugin +date: 2024-12-03 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/scout'] +--- +import kbnScoutObj from './kbn_scout.devdocs.json'; + + + +Contact [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 119 | 0 | 86 | 8 | + +## Common + +### Functions + + +### Classes + + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/kbn_screenshotting_server.mdx b/api_docs/kbn_screenshotting_server.mdx index 3bfec8779641..be432e83d606 100644 --- a/api_docs/kbn_screenshotting_server.mdx +++ b/api_docs/kbn_screenshotting_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-screenshotting-server title: "@kbn/screenshotting-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/screenshotting-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/screenshotting-server'] --- import kbnScreenshottingServerObj from './kbn_screenshotting_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_components.devdocs.json b/api_docs/kbn_search_api_keys_components.devdocs.json index f27bd9c7b38e..1f515d460091 100644 --- a/api_docs/kbn_search_api_keys_components.devdocs.json +++ b/api_docs/kbn_search_api_keys_components.devdocs.json @@ -110,9 +110,9 @@ "label": "useSearchApiKey", "description": [], "signature": [ - "() => { displayedApiKey: string | null; apiKey: string | null; toggleApiKeyVisibility: () => void; updateApiKey: ({ id, encoded }: { id: string; encoded: string; }) => void; status: ", + "() => { apiKey: string | null; toggleApiKeyVisibility: () => void; updateApiKey: ({ id, encoded }: { id: string; encoded: string; }) => void; status: ", "Status", - "; apiKeyIsVisible: boolean; }" + "; }" ], "path": "packages/kbn-search-api-keys-components/src/hooks/use_search_api_key.ts", "deprecated": false, diff --git a/api_docs/kbn_search_api_keys_components.mdx b/api_docs/kbn_search_api_keys_components.mdx index a6048f1d3237..4f4ef836fc8d 100644 --- a/api_docs/kbn_search_api_keys_components.mdx +++ b/api_docs/kbn_search_api_keys_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-components title: "@kbn/search-api-keys-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-components'] --- import kbnSearchApiKeysComponentsObj from './kbn_search_api_keys_components.devdocs.json'; diff --git a/api_docs/kbn_search_api_keys_server.mdx b/api_docs/kbn_search_api_keys_server.mdx index 553ec485329a..d065d49232bd 100644 --- a/api_docs/kbn_search_api_keys_server.mdx +++ b/api_docs/kbn_search_api_keys_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-keys-server title: "@kbn/search-api-keys-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-keys-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-keys-server'] --- import kbnSearchApiKeysServerObj from './kbn_search_api_keys_server.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 104d624a4d2a..0cf7b6a85222 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.devdocs.json b/api_docs/kbn_search_connectors.devdocs.json index a4721ab941fb..31b9ff22f7e0 100644 --- a/api_docs/kbn_search_connectors.devdocs.json +++ b/api_docs/kbn_search_connectors.devdocs.json @@ -1338,6 +1338,98 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName", + "type": "Function", + "tags": [], + "label": "generateConnectorName", + "description": [], + "signature": [ + "(client: ", + { + "pluginId": "@kbn/core-elasticsearch-server", + "scope": "server", + "docId": "kibKbnCoreElasticsearchServerPluginApi", + "section": "def-server.ElasticsearchClient", + "text": "ElasticsearchClient" + }, + ", connectorType: string, isNative: boolean, userConnectorName?: string | undefined) => Promise<{ connectorName: string; indexName: string; }>" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$1", + "type": "Object", + "tags": [], + "label": "client", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-elasticsearch-server", + "scope": "server", + "docId": "kibKbnCoreElasticsearchServerPluginApi", + "section": "def-server.ElasticsearchClient", + "text": "ElasticsearchClient" + } + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$2", + "type": "string", + "tags": [], + "label": "connectorType", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$3", + "type": "boolean", + "tags": [], + "label": "isNative", + "description": [], + "signature": [ + "boolean" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.generateConnectorName.$4", + "type": "string", + "tags": [], + "label": "userConnectorName", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-search-connectors/lib/generate_connector_name.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/search-connectors", "id": "def-common.getConnectorsDict", @@ -7161,6 +7253,21 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/search-connectors", + "id": "def-common.MANAGED_CONNECTOR_INDEX_PREFIX", + "type": "string", + "tags": [], + "label": "MANAGED_CONNECTOR_INDEX_PREFIX", + "description": [], + "signature": [ + "\"content-\"" + ], + "path": "packages/kbn-search-connectors/constants/connectors.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [ diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index 7924fda854d7..5ba6722443d6 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-ki | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3948 | 0 | 3948 | 0 | +| 3954 | 0 | 3954 | 0 | ## Common diff --git a/api_docs/kbn_search_errors.mdx b/api_docs/kbn_search_errors.mdx index dc45d6dea21f..ed60763f601e 100644 --- a/api_docs/kbn_search_errors.mdx +++ b/api_docs/kbn_search_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-errors title: "@kbn/search-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-errors plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-errors'] --- import kbnSearchErrorsObj from './kbn_search_errors.devdocs.json'; diff --git a/api_docs/kbn_search_index_documents.mdx b/api_docs/kbn_search_index_documents.mdx index 83b39f59a7ba..f5d8aa98d839 100644 --- a/api_docs/kbn_search_index_documents.mdx +++ b/api_docs/kbn_search_index_documents.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-index-documents title: "@kbn/search-index-documents" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-index-documents plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-index-documents'] --- import kbnSearchIndexDocumentsObj from './kbn_search_index_documents.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 7a8efa3f3555..2171084dde53 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; diff --git a/api_docs/kbn_search_shared_ui.mdx b/api_docs/kbn_search_shared_ui.mdx index 9b4aed1b3dbc..ebad34cd2bd6 100644 --- a/api_docs/kbn_search_shared_ui.mdx +++ b/api_docs/kbn_search_shared_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-shared-ui title: "@kbn/search-shared-ui" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-shared-ui plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-shared-ui'] --- import kbnSearchSharedUiObj from './kbn_search_shared_ui.devdocs.json'; diff --git a/api_docs/kbn_search_types.mdx b/api_docs/kbn_search_types.mdx index 178df97d3604..4ead6d8c9968 100644 --- a/api_docs/kbn_search_types.mdx +++ b/api_docs/kbn_search_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-types title: "@kbn/search-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-types'] --- import kbnSearchTypesObj from './kbn_search_types.devdocs.json'; diff --git a/api_docs/kbn_security_api_key_management.mdx b/api_docs/kbn_security_api_key_management.mdx index 55b3058aba26..3b3612d40743 100644 --- a/api_docs/kbn_security_api_key_management.mdx +++ b/api_docs/kbn_security_api_key_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-api-key-management title: "@kbn/security-api-key-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-api-key-management plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-api-key-management'] --- import kbnSecurityApiKeyManagementObj from './kbn_security_api_key_management.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core.mdx b/api_docs/kbn_security_authorization_core.mdx index 1d17f2d087be..c9ed463683ca 100644 --- a/api_docs/kbn_security_authorization_core.mdx +++ b/api_docs/kbn_security_authorization_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core title: "@kbn/security-authorization-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core'] --- import kbnSecurityAuthorizationCoreObj from './kbn_security_authorization_core.devdocs.json'; diff --git a/api_docs/kbn_security_authorization_core_common.mdx b/api_docs/kbn_security_authorization_core_common.mdx index bff499fa9345..74f2c37abcd9 100644 --- a/api_docs/kbn_security_authorization_core_common.mdx +++ b/api_docs/kbn_security_authorization_core_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-authorization-core-common title: "@kbn/security-authorization-core-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-authorization-core-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-authorization-core-common'] --- import kbnSecurityAuthorizationCoreCommonObj from './kbn_security_authorization_core_common.devdocs.json'; diff --git a/api_docs/kbn_security_form_components.devdocs.json b/api_docs/kbn_security_form_components.devdocs.json index 4fb983c29b46..9dccf63965ba 100644 --- a/api_docs/kbn_security_form_components.devdocs.json +++ b/api_docs/kbn_security_form_components.devdocs.json @@ -246,11 +246,11 @@ "DisambiguateSet", " & { labelType?: \"legend\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", "DisambiguateSet", " & { labelType?: \"label\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", { "pluginId": "@kbn/security-form-components", "scope": "common", @@ -276,11 +276,11 @@ "DisambiguateSet", " & { labelType?: \"legend\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & Omit, \"disabled\">) | (", "DisambiguateSet", " & { labelType?: \"label\" | undefined; } & ", "CommonProps", - " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"columnCompressedSwitch\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", + " & { display?: \"center\" | \"row\" | \"columnCompressed\" | \"centerCompressed\" | \"rowCompressed\" | undefined; hasEmptyLabelSpace?: boolean | undefined; fullWidth?: boolean | undefined; describedByIds?: string[] | undefined; hasChildLabel?: boolean | undefined; children: React.ReactElement>; label?: React.ReactNode; labelAppend?: any; id?: string | undefined; isInvalid?: boolean | undefined; error?: React.ReactNode | React.ReactNode[]; helpText?: React.ReactNode | React.ReactNode[]; isDisabled?: boolean | undefined; } & React.HTMLAttributes)) & ", { "pluginId": "@kbn/security-form-components", "scope": "common", diff --git a/api_docs/kbn_security_form_components.mdx b/api_docs/kbn_security_form_components.mdx index 78f402c754e0..b7cf6dbe337d 100644 --- a/api_docs/kbn_security_form_components.mdx +++ b/api_docs/kbn_security_form_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-form-components title: "@kbn/security-form-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-form-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-form-components'] --- import kbnSecurityFormComponentsObj from './kbn_security_form_components.devdocs.json'; diff --git a/api_docs/kbn_security_hardening.mdx b/api_docs/kbn_security_hardening.mdx index 5fdea6e06368..59150e002d37 100644 --- a/api_docs/kbn_security_hardening.mdx +++ b/api_docs/kbn_security_hardening.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-hardening title: "@kbn/security-hardening" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-hardening plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-hardening'] --- import kbnSecurityHardeningObj from './kbn_security_hardening.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_common.mdx b/api_docs/kbn_security_plugin_types_common.mdx index 7e87f9068bb7..7860df573efe 100644 --- a/api_docs/kbn_security_plugin_types_common.mdx +++ b/api_docs/kbn_security_plugin_types_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-common title: "@kbn/security-plugin-types-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-common plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-common'] --- import kbnSecurityPluginTypesCommonObj from './kbn_security_plugin_types_common.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_public.mdx b/api_docs/kbn_security_plugin_types_public.mdx index 50fe01f23aeb..a80602c8ca04 100644 --- a/api_docs/kbn_security_plugin_types_public.mdx +++ b/api_docs/kbn_security_plugin_types_public.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-public title: "@kbn/security-plugin-types-public" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-public plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-public'] --- import kbnSecurityPluginTypesPublicObj from './kbn_security_plugin_types_public.devdocs.json'; diff --git a/api_docs/kbn_security_plugin_types_server.mdx b/api_docs/kbn_security_plugin_types_server.mdx index f27bffd19872..dacb26ea39d3 100644 --- a/api_docs/kbn_security_plugin_types_server.mdx +++ b/api_docs/kbn_security_plugin_types_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-plugin-types-server title: "@kbn/security-plugin-types-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-plugin-types-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-plugin-types-server'] --- import kbnSecurityPluginTypesServerObj from './kbn_security_plugin_types_server.devdocs.json'; diff --git a/api_docs/kbn_security_role_management_model.mdx b/api_docs/kbn_security_role_management_model.mdx index 7e0dda8f661b..0227136a820f 100644 --- a/api_docs/kbn_security_role_management_model.mdx +++ b/api_docs/kbn_security_role_management_model.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-role-management-model title: "@kbn/security-role-management-model" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-role-management-model plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-role-management-model'] --- import kbnSecurityRoleManagementModelObj from './kbn_security_role_management_model.devdocs.json'; diff --git a/api_docs/kbn_security_solution_distribution_bar.devdocs.json b/api_docs/kbn_security_solution_distribution_bar.devdocs.json index edcd3cad12f9..51fdf64ef88c 100644 --- a/api_docs/kbn_security_solution_distribution_bar.devdocs.json +++ b/api_docs/kbn_security_solution_distribution_bar.devdocs.json @@ -84,7 +84,7 @@ "distribution data points" ], "signature": [ - "{ key: string; count: number; color: string; label?: React.ReactNode; }[]" + "{ key: string; count: number; color: string; label?: React.ReactNode; isCurrentFilter?: boolean | undefined; filter?: (() => void) | undefined; reset?: ((event: React.MouseEvent) => void) | undefined; }[]" ], "path": "x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx", "deprecated": false, diff --git a/api_docs/kbn_security_solution_distribution_bar.mdx b/api_docs/kbn_security_solution_distribution_bar.mdx index 99d8879d9858..6db68ac78df8 100644 --- a/api_docs/kbn_security_solution_distribution_bar.mdx +++ b/api_docs/kbn_security_solution_distribution_bar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-distribution-bar title: "@kbn/security-solution-distribution-bar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-distribution-bar plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-distribution-bar'] --- import kbnSecuritySolutionDistributionBarObj from './kbn_security_solution_distribution_bar.devdocs.json'; diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index 4dc2e1497ec1..cfae5b98640c 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index 29b2e83f6ca2..a6c6a0bc8b4c 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index cfe0f246f27b..b59dc38d0d65 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index 9b1d2c09bbd1..51a54e68c6d3 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_security_ui_components.mdx b/api_docs/kbn_security_ui_components.mdx index 6ae7a98a4773..995a86bd5225 100644 --- a/api_docs/kbn_security_ui_components.mdx +++ b/api_docs/kbn_security_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-ui-components title: "@kbn/security-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-ui-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-ui-components'] --- import kbnSecurityUiComponentsObj from './kbn_security_ui_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 47d9a5051ce6..375acf648570 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index c1afd0809f45..c8fbe41adc82 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 3aabc7cd739f..29c7acff0d35 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 58fed3c2bc90..7c918c80d9e8 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2024-11-22 +date: 2024-12-03 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 2932db77d5b7..ea26ddab6a94 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2024-11-22 +date: 2024-12-03 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 6d347fbdffff..3c9d620a2b6f 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2024-11-22 +date: 2024-12-03 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 523fa351e275..1cadbad642b5 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2024-11-22 +date: 2024-12-03 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 8f29dc09e7cf..c97c65e92668 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2024-11-22 +date: 2024-12-03 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 bc746058c2d1..475670953a92 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2024-11-22 +date: 2024-12-03 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 150d70f74d87..35eabcf16f60 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2024-11-22 +date: 2024-12-03 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 69e1df6de9c3..5acbde47bdf9 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2024-11-22 +date: 2024-12-03 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 8d97bf400220..65cd4a1e4db0 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2024-11-22 +date: 2024-12-03 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 ac34362ddd91..47034d9238fd 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 4dd48414d4e7..f3596fe402d0 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index a4966c61a76f..796441a88f2f 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2024-11-22 +date: 2024-12-03 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 2a87cc0882f0..b69ebb507b46 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2024-11-22 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_securitysolution_utils.devdocs.json index 7dbb4b59056c..8fa42be623b6 100644 --- a/api_docs/kbn_securitysolution_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_utils.devdocs.json @@ -242,6 +242,60 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.debounceAsync", + "type": "Function", + "tags": [], + "label": "debounceAsync", + "description": [ + "\nUnlike lodash's debounce, which resolves intermediate calls with the most\nrecent value, this implementation waits to resolve intermediate calls until\nthe next invocation resolves.\n" + ], + "signature": [ + "(fn: (...args: Args) => Result, intervalMs: number) => (...args: Args) => Promise>" + ], + "path": "packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.debounceAsync.$1", + "type": "Function", + "tags": [], + "label": "fn", + "description": [ + "an async function" + ], + "signature": [ + "(...args: Args) => Result" + ], + "path": "packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/securitysolution-utils", + "id": "def-common.debounceAsync.$2", + "type": "number", + "tags": [], + "label": "intervalMs", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-securitysolution-utils/src/debounce_async/debounce_async.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "A debounced async function that resolves on the next invocation" + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/securitysolution-utils", "id": "def-common.getIndexListFromEsqlQuery", @@ -412,13 +466,13 @@ "label": "isAggregatingQuery", "description": [], "signature": [ - "(ast: ", + "(astExpression: ", { "pluginId": "@kbn/esql-ast", "scope": "common", "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLAst", - "text": "ESQLAst" + "section": "def-common.ESQLAstQueryExpression", + "text": "ESQLAstQueryExpression" }, ") => boolean" ], @@ -429,17 +483,17 @@ { "parentPluginId": "@kbn/securitysolution-utils", "id": "def-common.isAggregatingQuery.$1", - "type": "Array", + "type": "Object", "tags": [], - "label": "ast", + "label": "astExpression", "description": [], "signature": [ { "pluginId": "@kbn/esql-ast", "scope": "common", "docId": "kibKbnEsqlAstPluginApi", - "section": "def-common.ESQLAst", - "text": "ESQLAst" + "section": "def-common.ESQLAstQueryExpression", + "text": "ESQLAstQueryExpression" } ], "path": "packages/kbn-securitysolution-utils/src/esql/compute_if_esql_query_aggregating.ts", diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index 1d682e7bdd98..3bd451984fd2 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-detection-engine](https://github.com/orgs/elastic/tea | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 60 | 0 | 54 | 0 | +| 63 | 0 | 55 | 0 | ## Common diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index cba4987e0efd..e321b98542f9 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2024-11-22 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_server_route_repository.devdocs.json index 274e388eb054..b402826a9d60 100644 --- a/api_docs/kbn_server_route_repository.devdocs.json +++ b/api_docs/kbn_server_route_repository.devdocs.json @@ -88,7 +88,15 @@ "label": "formatRequest", "description": [], "signature": [ - "(endpoint: string, pathParams: Record) => { method: Method; pathname: string; version: string; }" + "(endpoint: string, pathParams: Record) => { method: \"get\" | ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.DestructiveRouteMethod", + "text": "DestructiveRouteMethod" + }, + "; pathname: string; version: string; }" ], "path": "packages/kbn-server-route-repository-utils/src/format_request.ts", "deprecated": false, @@ -136,7 +144,15 @@ "label": "parseEndpoint", "description": [], "signature": [ - "(endpoint: string) => { method: Method; pathname: string; version: string; }" + "(endpoint: string) => { method: \"get\" | ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.DestructiveRouteMethod", + "text": "DestructiveRouteMethod" + }, + "; pathname: string; version: string; }" ], "path": "packages/kbn-server-route-repository-utils/src/parse_endpoint.ts", "deprecated": false, @@ -185,15 +201,15 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - ">; logger: ", + " | undefined, any, any, any>>; logger: ", { "pluginId": "@kbn/logging", "scope": "common", @@ -255,15 +271,15 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "; }" + " | undefined, any, any, any>; }" ], "path": "packages/kbn-server-route-repository/src/register_routes.ts", "deprecated": false, @@ -344,49 +360,6 @@ } ], "interfaces": [ - { - "parentPluginId": "@kbn/server-route-repository", - "id": "def-server.DefaultRouteCreateOptions", - "type": "Interface", - "tags": [], - "label": "DefaultRouteCreateOptions", - "description": [], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/server-route-repository", - "id": "def-server.DefaultRouteCreateOptions.options", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.RouteConfigOptions", - "text": "RouteConfigOptions" - }, - "<", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.RouteMethod", - "text": "RouteMethod" - }, - "> | undefined" - ], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/server-route-repository", "id": "def-server.DefaultRouteHandlerResources", @@ -468,7 +441,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>) => Promise<", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => Promise<", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -513,7 +494,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -539,7 +528,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>) => ", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -588,7 +585,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -600,34 +605,6 @@ } ], "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/server-route-repository", - "id": "def-server.RouteState", - "type": "Interface", - "tags": [], - "label": "RouteState", - "description": [], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/server-route-repository", - "id": "def-server.RouteState.Unnamed", - "type": "IndexSignature", - "tags": [], - "label": "[endpoint: string]: any", - "description": [], - "signature": [ - "[endpoint: string]: any" - ], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false } ], "enums": [], @@ -664,7 +641,7 @@ "section": "def-common.ServerRouteCreateOptions", "text": "ServerRouteCreateOptions" }, - "> ? TRouteParamsRT extends ", + " | undefined> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -703,15 +680,7 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " | undefined, any, any, ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRouteCreateOptions", - "text": "ServerRouteCreateOptions" - }, - "> ? TRouteParamsRT extends ", + " | undefined, any, any, any> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -726,6 +695,36 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/server-route-repository", + "id": "def-server.DefaultRouteCreateOptions", + "type": "Type", + "tags": [], + "label": "DefaultRouteCreateOptions", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteConfigOptions", + "text": "RouteConfigOptions" + }, + "<\"get\" | ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.DestructiveRouteMethod", + "text": "DestructiveRouteMethod" + }, + ">" + ], + "path": "packages/kbn-server-route-repository-utils/src/typings.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/server-route-repository", "id": "def-server.EndpointOf", @@ -782,15 +781,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - " ? TReturnType extends ", + " ? TReturnType extends ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -852,7 +843,15 @@ "label": "ServerRoute", "description": [], "signature": [ - "{ endpoint: TEndpoint; handler: ServerRouteHandler; } & TRouteCreateOptions & (TRouteParamsRT extends ", + "{ endpoint: TEndpoint; handler: ServerRouteHandler; security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; } & (TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -860,7 +859,15 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " ? { params: TRouteParamsRT; } : {})" + " ? { params: TRouteParamsRT; } : {}) & (TRouteCreateOptions extends ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.DefaultRouteCreateOptions", + "text": "DefaultRouteCreateOptions" + }, + " ? { options: TRouteCreateOptions; } : {})" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -891,7 +898,15 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " | undefined, any, any, Record>; }" + " | undefined, any, any, ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRouteCreateOptions", + "text": "ServerRouteCreateOptions" + }, + " | undefined>; }" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index 64b4eec29841..c7f27f9b9f5b 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 42 | 0 | 42 | 0 | +| 39 | 0 | 39 | 0 | ## Server diff --git a/api_docs/kbn_server_route_repository_client.devdocs.json b/api_docs/kbn_server_route_repository_client.devdocs.json index be6f4e7ecf2d..03e5c79e9668 100644 --- a/api_docs/kbn_server_route_repository_client.devdocs.json +++ b/api_docs/kbn_server_route_repository_client.devdocs.json @@ -180,7 +180,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>) => Promise<", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => Promise<", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -225,7 +233,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -251,7 +267,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>) => ", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -300,7 +324,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -348,7 +380,7 @@ "section": "def-common.ServerRouteCreateOptions", "text": "ServerRouteCreateOptions" }, - "> ? TRouteParamsRT extends ", + " | undefined> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", diff --git a/api_docs/kbn_server_route_repository_client.mdx b/api_docs/kbn_server_route_repository_client.mdx index 9da960e4f48b..38a373079d66 100644 --- a/api_docs/kbn_server_route_repository_client.mdx +++ b/api_docs/kbn_server_route_repository_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-client title: "@kbn/server-route-repository-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-client plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-client'] --- import kbnServerRouteRepositoryClientObj from './kbn_server_route_repository_client.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository_utils.devdocs.json b/api_docs/kbn_server_route_repository_utils.devdocs.json index 4f96f6bafd37..b33006a95896 100644 --- a/api_docs/kbn_server_route_repository_utils.devdocs.json +++ b/api_docs/kbn_server_route_repository_utils.devdocs.json @@ -27,7 +27,15 @@ "label": "formatRequest", "description": [], "signature": [ - "(endpoint: string, pathParams: Record) => { method: Method; pathname: string; version: string; }" + "(endpoint: string, pathParams: Record) => { method: \"get\" | ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.DestructiveRouteMethod", + "text": "DestructiveRouteMethod" + }, + "; pathname: string; version: string; }" ], "path": "packages/kbn-server-route-repository-utils/src/format_request.ts", "deprecated": false, @@ -75,7 +83,15 @@ "label": "parseEndpoint", "description": [], "signature": [ - "(endpoint: string) => { method: Method; pathname: string; version: string; }" + "(endpoint: string) => { method: \"get\" | ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.DestructiveRouteMethod", + "text": "DestructiveRouteMethod" + }, + "; pathname: string; version: string; }" ], "path": "packages/kbn-server-route-repository-utils/src/parse_endpoint.ts", "deprecated": false, @@ -102,49 +118,6 @@ } ], "interfaces": [ - { - "parentPluginId": "@kbn/server-route-repository-utils", - "id": "def-common.DefaultRouteCreateOptions", - "type": "Interface", - "tags": [], - "label": "DefaultRouteCreateOptions", - "description": [], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/server-route-repository-utils", - "id": "def-common.DefaultRouteCreateOptions.options", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.RouteConfigOptions", - "text": "RouteConfigOptions" - }, - "<", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.RouteMethod", - "text": "RouteMethod" - }, - "> | undefined" - ], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/server-route-repository-utils", "id": "def-common.DefaultRouteHandlerResources", @@ -226,7 +199,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>) => Promise<", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => Promise<", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -271,7 +252,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -297,7 +286,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>) => ", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -346,7 +343,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions>" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -361,10 +366,10 @@ }, { "parentPluginId": "@kbn/server-route-repository-utils", - "id": "def-common.RouteState", + "id": "def-common.ServerRouteCreateOptions", "type": "Interface", "tags": [], - "label": "RouteState", + "label": "ServerRouteCreateOptions", "description": [], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -372,13 +377,13 @@ "children": [ { "parentPluginId": "@kbn/server-route-repository-utils", - "id": "def-common.RouteState.Unnamed", + "id": "def-common.ServerRouteCreateOptions.Unnamed", "type": "IndexSignature", "tags": [], - "label": "[endpoint: string]: any", + "label": "[x: string]: any", "description": [], "signature": [ - "[endpoint: string]: any" + "[x: string]: any" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -422,7 +427,7 @@ "section": "def-common.ServerRouteCreateOptions", "text": "ServerRouteCreateOptions" }, - "> ? TRouteParamsRT extends ", + " | undefined> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -461,15 +466,7 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " | undefined, any, any, ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.ServerRouteCreateOptions", - "text": "ServerRouteCreateOptions" - }, - "> ? TRouteParamsRT extends ", + " | undefined, any, any, any> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -505,6 +502,36 @@ "trackAdoption": false, "initialIsOpen": false }, + { + "parentPluginId": "@kbn/server-route-repository-utils", + "id": "def-common.DefaultRouteCreateOptions", + "type": "Type", + "tags": [], + "label": "DefaultRouteCreateOptions", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteConfigOptions", + "text": "RouteConfigOptions" + }, + "<\"get\" | ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.DestructiveRouteMethod", + "text": "DestructiveRouteMethod" + }, + ">" + ], + "path": "packages/kbn-server-route-repository-utils/src/typings.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, { "parentPluginId": "@kbn/server-route-repository-utils", "id": "def-common.EndpointOf", @@ -561,15 +588,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - " ? TReturnType extends ", + " ? TReturnType extends ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -631,7 +650,15 @@ "label": "ServerRoute", "description": [], "signature": [ - "{ endpoint: TEndpoint; handler: ServerRouteHandler; } & TRouteCreateOptions & (TRouteParamsRT extends ", + "{ endpoint: TEndpoint; handler: ServerRouteHandler; security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; } & (TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -639,22 +666,15 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " ? { params: TRouteParamsRT; } : {})" - ], - "path": "packages/kbn-server-route-repository-utils/src/typings.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "@kbn/server-route-repository-utils", - "id": "def-common.ServerRouteCreateOptions", - "type": "Type", - "tags": [], - "label": "ServerRouteCreateOptions", - "description": [], - "signature": [ - "{ [x: string]: any; }" + " ? { params: TRouteParamsRT; } : {}) & (TRouteCreateOptions extends ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.DefaultRouteCreateOptions", + "text": "DefaultRouteCreateOptions" + }, + " ? { options: TRouteCreateOptions; } : {})" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -700,7 +720,15 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " | undefined, any, any, Record>; }" + " | undefined, any, any, ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRouteCreateOptions", + "text": "ServerRouteCreateOptions" + }, + " | undefined>; }" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, diff --git a/api_docs/kbn_server_route_repository_utils.mdx b/api_docs/kbn_server_route_repository_utils.mdx index a317cddd3bd1..e439098ba349 100644 --- a/api_docs/kbn_server_route_repository_utils.mdx +++ b/api_docs/kbn_server_route_repository_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository-utils title: "@kbn/server-route-repository-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository-utils'] --- import kbnServerRouteRepositoryUtilsObj from './kbn_server_route_repository_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 30 | 0 | 30 | 2 | +| 28 | 0 | 28 | 2 | ## Common diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index d24313c36c3e..7f064985631c 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; -Contact [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index e6d76ca16d65..d22ce4172aa6 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; -Contact [@elastic/appex-sharedux @elastic/kibana-management @elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/appex-sharedux ) for questions regarding this plugin. +Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index 7ee47b57b925..5963967d8bcf 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 5e6673894abd..f8a1e6cc37fd 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; -Contact [@elastic/search-kibana @elastic/kibana-management](https://github.com/orgs/elastic/teams/search-kibana ) for questions regarding this plugin. +Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 955805f53c14..3442c34bdbb8 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; -Contact [@elastic/security-solution @elastic/kibana-management](https://github.com/orgs/elastic/teams/security-solution ) for questions regarding this plugin. +Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index b3e2b555841a..a174fe461afa 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index d2d1cbaa2939..75eddfcf4e29 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 21587a72b825..07f0127523f5 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index 706f66605412..a4aa5096b502 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index 3e2fca4714ce..28ae6716f3ee 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2024-11-22 +date: 2024-12-03 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 fd0d1d4c1baf..e0021c7cc216 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2024-11-22 +date: 2024-12-03 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 94517cadd709..9ec03f02229b 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 7534b9bfe0a8..76154e77fe20 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index e826fee642c0..a17e903b6449 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 26936e7338f7..d9b5c7ee64b3 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index bf5f2668e9e1..7dd85fe4f2e9 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index 629569e223d1..fe89aed70871 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index b56d10878ac8..6db103816744 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index f976ab6f9976..db98855c73e1 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 7f3d5139535f..5aaa50af518f 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index 4c8b98f26dc2..900dd0cc6123 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 5cbcd0da1066..c165fada0a6b 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index 957184bb209a..fb041bb4b4df 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 51e107d20ac8..64c89f889588 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index cc8fd32c04b3..45b634682af6 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index 629b6a7e9fa3..99b41b41931c 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index f0e7f5a8ed5b..c5b24bded152 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2024-11-22 +date: 2024-12-03 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 eee4deff4dfa..2c2fc5d74945 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 fb41c34b0a7d..1de155e2e8a7 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2024-11-22 +date: 2024-12-03 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 925dd54b7b21..128345119553 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 16bce72a18e5..8827e97e3052 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2024-11-22 +date: 2024-12-03 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 f4c97a8ec7c5..69a3478aed4b 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 0a913ddaf832..be2cff9d73bd 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2024-11-22 +date: 2024-12-03 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 3f892eb2a327..81784c476720 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2024-11-22 +date: 2024-12-03 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 e80b3adf798f..a57150fe66db 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 5be22a01245a..079c87c939d2 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 765729743570..6d4583ce83a9 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2024-11-22 +date: 2024-12-03 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 9b847c50bb6b..18b799330558 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2024-11-22 +date: 2024-12-03 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 11302955a772..97f657a264c8 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index 268aa6643148..7e4a649020b6 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index 7676f40f2caf..e0fad918bab4 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2024-11-22 +date: 2024-12-03 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 b05834eb29d9..c90d09d43a62 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2024-11-22 +date: 2024-12-03 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 2ed058123211..820ab7568a2f 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2024-11-22 +date: 2024-12-03 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 1ba1e92db0a4..f19e0a6f0d20 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_tabbed_modal.mdx b/api_docs/kbn_shared_ux_tabbed_modal.mdx index 81fe8f76a765..96f5752bb324 100644 --- a/api_docs/kbn_shared_ux_tabbed_modal.mdx +++ b/api_docs/kbn_shared_ux_tabbed_modal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-tabbed-modal title: "@kbn/shared-ux-tabbed-modal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-tabbed-modal plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-tabbed-modal'] --- import kbnSharedUxTabbedModalObj from './kbn_shared_ux_tabbed_modal.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_table_persist.mdx b/api_docs/kbn_shared_ux_table_persist.mdx index 05e63c3c0a34..0263713730b9 100644 --- a/api_docs/kbn_shared_ux_table_persist.mdx +++ b/api_docs/kbn_shared_ux_table_persist.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-table-persist title: "@kbn/shared-ux-table-persist" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-table-persist plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-table-persist'] --- import kbnSharedUxTablePersistObj from './kbn_shared_ux_table_persist.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index 599ae12c50cc..2a99930e98c0 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.devdocs.json b/api_docs/kbn_slo_schema.devdocs.json index 13f17bcf471b..57d2f788dc03 100644 --- a/api_docs/kbn_slo_schema.devdocs.json +++ b/api_docs/kbn_slo_schema.devdocs.json @@ -606,7 +606,7 @@ "label": "CreateSLOInput", "description": [], "signature": [ - "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" + "{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/create.ts", "deprecated": false, @@ -661,7 +661,7 @@ "section": "def-common.Duration", "text": "Duration" }, - " | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" + " | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/create.ts", "deprecated": false, @@ -835,7 +835,7 @@ "label": "FindSLODefinitionsResponse", "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: { id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }[]; }" + "{ page: number; perPage: number; total: number; results: { id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }[]; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find_definition.ts", "deprecated": false, @@ -895,7 +895,7 @@ "label": "FindSLOResponse", "description": [], "signature": [ - "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; })[]; }" + "{ page: number; perPage: number; total: number; results: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; })[]; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/find.ts", "deprecated": false, @@ -993,7 +993,7 @@ "label": "GetSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get.ts", "deprecated": false, @@ -1263,7 +1263,7 @@ "label": "ResetSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/reset.ts", "deprecated": false, @@ -1278,7 +1278,7 @@ "label": "SLODefinitionResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1293,7 +1293,7 @@ "label": "SLOWithSummaryResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/slo.ts", "deprecated": false, @@ -1398,7 +1398,7 @@ "label": "UpdateSLOInput", "description": [], "signature": [ - "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | undefined; timeWindow?: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; } | undefined; budgetingMethod?: \"occurrences\" | \"timeslices\" | undefined; objective?: ({ target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }) | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" + "{ name?: string | undefined; description?: string | undefined; indicator?: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | undefined; timeWindow?: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; } | undefined; budgetingMethod?: \"occurrences\" | \"timeslices\" | undefined; objective?: ({ target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }) | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/update.ts", "deprecated": false, @@ -1453,7 +1453,7 @@ "section": "def-common.Duration", "text": "Duration" }, - " | undefined; preventInitialBackfill?: boolean | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" + " | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/update.ts", "deprecated": false, @@ -1468,7 +1468,7 @@ "label": "UpdateSLOResponse", "description": [], "signature": [ - "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" + "{ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; }" ], "path": "x-pack/packages/kbn-slo-schema/src/rest_specs/routes/update.ts", "deprecated": false, @@ -3250,7 +3250,13 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; tags: ", + "; syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>; tags: ", "ArrayC", "<", "StringC", @@ -5171,6 +5177,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -5194,7 +5202,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -6811,6 +6827,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -6834,7 +6852,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -9945,6 +9971,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -9968,7 +9996,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -12867,7 +12903,13 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>" + "; syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>" ], "path": "x-pack/packages/kbn-slo-schema/src/schema/slo.ts", "deprecated": false, @@ -14444,6 +14486,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -14467,7 +14511,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -14554,6 +14606,8 @@ "label": "settingsSchema", "description": [], "signature": [ + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -14577,7 +14631,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>" + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>" ], "path": "x-pack/packages/kbn-slo-schema/src/schema/slo.ts", "deprecated": false, @@ -15982,6 +16044,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -16005,7 +16069,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -17562,6 +17634,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -17585,7 +17659,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", @@ -20241,7 +20323,13 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; tags: ", + "; syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>; tags: ", "ArrayC", "<", "StringC", @@ -21664,6 +21752,8 @@ "text": "Duration" }, ", string, unknown>; }>]>; settings: ", + "IntersectionC", + "<[", "TypeC", "<{ syncDelay: ", "Type", @@ -21687,7 +21777,15 @@ }, ", string, unknown>; preventInitialBackfill: ", "BooleanC", - "; }>; revision: ", + "; }>, ", + "PartialC", + "<{ syncField: ", + "UnionC", + "<[", + "StringC", + ", ", + "NullC", + "]>; }>]>; revision: ", "NumberC", "; enabled: ", "BooleanC", diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 82694decc22a..acb6a8173eeb 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index fc741cd9e054..1c0edd62e378 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_sort_predicates.mdx b/api_docs/kbn_sort_predicates.mdx index e717a22e863e..92284a5b23c2 100644 --- a/api_docs/kbn_sort_predicates.mdx +++ b/api_docs/kbn_sort_predicates.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sort-predicates title: "@kbn/sort-predicates" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sort-predicates plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sort-predicates'] --- import kbnSortPredicatesObj from './kbn_sort_predicates.devdocs.json'; diff --git a/api_docs/kbn_sse_utils.mdx b/api_docs/kbn_sse_utils.mdx index 4782f0f18926..59a569431001 100644 --- a/api_docs/kbn_sse_utils.mdx +++ b/api_docs/kbn_sse_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils title: "@kbn/sse-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils'] --- import kbnSseUtilsObj from './kbn_sse_utils.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_client.mdx b/api_docs/kbn_sse_utils_client.mdx index c761b9f95e07..938c72543d30 100644 --- a/api_docs/kbn_sse_utils_client.mdx +++ b/api_docs/kbn_sse_utils_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-client title: "@kbn/sse-utils-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-client plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-client'] --- import kbnSseUtilsClientObj from './kbn_sse_utils_client.devdocs.json'; diff --git a/api_docs/kbn_sse_utils_server.mdx b/api_docs/kbn_sse_utils_server.mdx index 7e962c561ce6..b644dd00225b 100644 --- a/api_docs/kbn_sse_utils_server.mdx +++ b/api_docs/kbn_sse_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-sse-utils-server title: "@kbn/sse-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/sse-utils-server plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/sse-utils-server'] --- import kbnSseUtilsServerObj from './kbn_sse_utils_server.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index f79d228215f3..381a352aa0af 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2024-11-22 +date: 2024-12-03 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 1e1acd737950..a6775c662e9b 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2024-11-22 +date: 2024-12-03 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 c8fae6017655..1fc5797c7af7 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_synthetics_e2e.mdx b/api_docs/kbn_synthetics_e2e.mdx index d56371762c6c..711deb91b9bb 100644 --- a/api_docs/kbn_synthetics_e2e.mdx +++ b/api_docs/kbn_synthetics_e2e.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-e2e title: "@kbn/synthetics-e2e" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-e2e plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-e2e'] --- import kbnSyntheticsE2eObj from './kbn_synthetics_e2e.devdocs.json'; diff --git a/api_docs/kbn_synthetics_private_location.mdx b/api_docs/kbn_synthetics_private_location.mdx index ac3c669df109..af24792bd8bf 100644 --- a/api_docs/kbn_synthetics_private_location.mdx +++ b/api_docs/kbn_synthetics_private_location.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-synthetics-private-location title: "@kbn/synthetics-private-location" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/synthetics-private-location plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/synthetics-private-location'] --- import kbnSyntheticsPrivateLocationObj from './kbn_synthetics_private_location.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index d2a8bebfbfa0..334f1857e3fa 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.devdocs.json b/api_docs/kbn_test.devdocs.json index f00d113bde3f..d06c2234a316 100644 --- a/api_docs/kbn_test.devdocs.json +++ b/api_docs/kbn_test.devdocs.json @@ -200,6 +200,275 @@ ], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner", + "type": "Class", + "tags": [], + "label": "DedicatedTaskRunner", + "description": [], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getPort", + "type": "Function", + "tags": [], + "label": "getPort", + "description": [], + "signature": [ + "(uiPort: number) => number" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getPort.$1", + "type": "number", + "tags": [], + "label": "uiPort", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getUuid", + "type": "Function", + "tags": [], + "label": "getUuid", + "description": [], + "signature": [ + "(mainUuid: string) => string" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getUuid.$1", + "type": "string", + "tags": [], + "label": "mainUuid", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.enabled", + "type": "boolean", + "tags": [], + "label": "enabled", + "description": [ + "\nTrue when the FTR config indicates that Kibana has a dedicated task runner process, otherwise false. If this\nproperty is false then all other methods on this class will throw when they are called, so if you're not\ncertain where your code will be run make sure to check `dedicatedTaskRunner.enabled` before calling\nother methods." + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.Unnamed", + "type": "Function", + "tags": [], + "label": "Constructor", + "description": [], + "signature": [ + "any" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.Unnamed.$1", + "type": "Object", + "tags": [], + "label": "config", + "description": [], + "signature": [ + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.Config", + "text": "Config" + } + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.Unnamed.$2", + "type": "Object", + "tags": [], + "label": "log", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getPort", + "type": "Function", + "tags": [], + "label": "getPort", + "description": [ + "\nThe port number that the dedicated task runner is running on" + ], + "signature": [ + "() => number" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getUrl", + "type": "Function", + "tags": [], + "label": "getUrl", + "description": [ + "\nThe full URL for the dedicated task runner process" + ], + "signature": [ + "() => string" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.hasUuid", + "type": "Function", + "tags": [], + "label": "hasUuid", + "description": [ + "\nReturns true if the `--server.uuid` setting was passed to the Kibana server, allowing the UUID to\nbe deterministic and ensuring that `dedicatedTaskRunner.getUuid()` won't throw." + ], + "signature": [ + "() => boolean" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getUuid", + "type": "Function", + "tags": [], + "label": "getUuid", + "description": [ + "\nIf `--server.uuid` is passed to Kibana in the FTR config file then the dedicated task runner will\nuse a UUID derived from that and it will be synchronously available to users via this function.\nOtherwise this function will through." + ], + "signature": [ + "() => string" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getClient", + "type": "Function", + "tags": [], + "label": "getClient", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.KbnClient", + "text": "KbnClient" + } + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [ + "a `KbnClient` instance that is configured to talk directly to the dedicated task runner. Not really sure how useful this is." + ] + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.DedicatedTaskRunner.getSupertest", + "type": "Function", + "tags": [], + "label": "getSupertest", + "description": [], + "signature": [ + "() => ", + "node_modules/@types/supertest/lib/agent", + "<", + "SuperTestStatic", + ".Test>" + ], + "path": "packages/kbn-test/src/functional_test_runner/lib/dedicated_task_runner.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [ + "a Supertest instance that will send requests to the dedicated task runner." + ] + } + ], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/test", "id": "def-common.DockerServersService", @@ -2333,6 +2602,63 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.getArgValue", + "type": "Function", + "tags": [], + "label": "getArgValue", + "description": [ + "\nGet the value of an arg from the CliArg flags." + ], + "signature": [ + "(args: ", + "KibanaCliArg", + "[], name: string) => ", + "ArgValue", + " | ", + "ArgValue", + "[] | undefined" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.getArgValue.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "KibanaCliArg", + "[]" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.getArgValue.$2", + "type": "string", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/test", "id": "def-common.getDockerFileMountPath", @@ -2513,6 +2839,103 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.initLogsDir", + "type": "Function", + "tags": [], + "label": "initLogsDir", + "description": [], + "signature": [ + "(log: ", + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + }, + ", logsDir: string) => Promise" + ], + "path": "packages/kbn-test/src/functional_tests/lib/logs_dir.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.initLogsDir.$1", + "type": "Object", + "tags": [], + "label": "log", + "description": [], + "signature": [ + { + "pluginId": "@kbn/tooling-log", + "scope": "common", + "docId": "kibKbnToolingLogPluginApi", + "section": "def-common.ToolingLog", + "text": "ToolingLog" + } + ], + "path": "packages/kbn-test/src/functional_tests/lib/logs_dir.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.initLogsDir.$2", + "type": "string", + "tags": [], + "label": "logsDir", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/functional_tests/lib/logs_dir.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.parseRawFlags", + "type": "Function", + "tags": [], + "label": "parseRawFlags", + "description": [], + "signature": [ + "(rawFlags: string[]) => ", + "KibanaCliArg", + "[]" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.parseRawFlags.$1", + "type": "Array", + "tags": [], + "label": "rawFlags", + "description": [], + "signature": [ + "string[]" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/test", "id": "def-common.readConfigFile", @@ -2642,6 +3065,61 @@ "returnComment": [], "initialIsOpen": false }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.remapPluginPaths", + "type": "Function", + "tags": [], + "label": "remapPluginPaths", + "description": [ + "\nParse the list of Kibana CLI Arg flags and extract the loggers config so that they can be extended\nin a subsequent FTR config" + ], + "signature": [ + "(args: ", + "KibanaCliArg", + "[], kibanaInstallDir: string) => ", + "KibanaCliArg", + "[]" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.remapPluginPaths.$1", + "type": "Array", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "KibanaCliArg", + "[]" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.remapPluginPaths.$2", + "type": "string", + "tags": [], + "label": "kibanaInstallDir", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-test/src/functional_tests/lib/kibana_cli_args.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, { "parentPluginId": "@kbn/test", "id": "def-common.runCheckFtrCodeOwnersCli", @@ -4195,7 +4673,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -4269,7 +4753,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -4343,7 +4833,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -4417,7 +4913,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -4491,7 +4993,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -4565,7 +5073,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -4639,7 +5153,13 @@ "text": "EsVersion" }, "; (serviceName: \"dedicatedTaskRunner\"): ", - "DedicatedTaskRunner", + { + "pluginId": "@kbn/test", + "scope": "common", + "docId": "kibKbnTestPluginApi", + "section": "def-common.DedicatedTaskRunner", + "text": "DedicatedTaskRunner" + }, "; (serviceName: T): ServiceMap[T]; }" ], "path": "packages/kbn-test/src/functional_test_runner/public_types.ts", @@ -5584,6 +6104,104 @@ } ], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts", + "type": "Interface", + "tags": [], + "label": "UrlParts", + "description": [], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts.protocol", + "type": "string", + "tags": [], + "label": "protocol", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts.hostname", + "type": "string", + "tags": [], + "label": "hostname", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts.port", + "type": "number", + "tags": [], + "label": "port", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts.auth", + "type": "string", + "tags": [], + "label": "auth", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts.username", + "type": "string", + "tags": [], + "label": "username", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "@kbn/test", + "id": "def-common.UrlParts.password", + "type": "string", + "tags": [], + "label": "password", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "packages/kbn-test/kbn_test_config.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false } ], "enums": [], diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index 4540645d3910..7d2f6d15b250 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 320 | 4 | 272 | 14 | +| 353 | 4 | 298 | 14 | ## Common diff --git a/api_docs/kbn_test_eui_helpers.mdx b/api_docs/kbn_test_eui_helpers.mdx index 47d42a7b4145..f7625b6d0035 100644 --- a/api_docs/kbn_test_eui_helpers.mdx +++ b/api_docs/kbn_test_eui_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-eui-helpers title: "@kbn/test-eui-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-eui-helpers plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-eui-helpers'] --- import kbnTestEuiHelpersObj from './kbn_test_eui_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 110eb95c420f..fb69f623ea84 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2024-11-22 +date: 2024-12-03 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.devdocs.json b/api_docs/kbn_test_subj_selector.devdocs.json index 2ab9cc3c4a7a..dafcf5ceb970 100644 --- a/api_docs/kbn_test_subj_selector.devdocs.json +++ b/api_docs/kbn_test_subj_selector.devdocs.json @@ -26,7 +26,7 @@ "tags": [], "label": "subj", "description": [ - "\nConverts a testSubject selector into a CSS selector.\n\ntestSubject selector syntax rules:\n\n - `data-test-subj` values can include spaces\n\n - prefixing a value with `*` will allow matching a `data-test-subj` attribute containing at least one occurrence of value within the string.\n - example: `*foo`\n - css equivalent: `[data-test-subj*=\"foo\"]`\n - DOM match example:
data-test-subj=\"bar-foo\"
\n\n - prefixing a value with `~` will allow matching a `data-test-subj` attribute represented as a whitespace-separated list of words, one of which is exactly value\n - example: `~foo`\n - css equivalent: `[data-test-subj~=\"foo\"]`\n - DOM match example:
data-test-subj=\"foo bar\"
\n\n - the `>` character is used between two values to indicate that the value on the right must match an element inside an element matched by the value on the left\n - example: `foo > bar`\n - css equivalent: `[data-test-subj=foo] [data-test-subj=bar]`\n - DOM match example:\n
data-test-subj=\"foo\"\n
data-test-subj=\"bar\"
\n
\n\n - the `&` character is used between two values to indicate that the value on both sides must both match the element\n - example: `foo & bar`\n - css equivalent: `[data-test-subj=foo][data-test-subj=bar]`\n - DOM match example:
data-test-subj=\"foo bar\"
" + "\nConverts a testSubject selector into a CSS selector.\n\ntestSubject selector syntax rules:\n\n - `data-test-subj` values can include spaces\n\n - prefixing a value with `*` will allow matching a `data-test-subj` attribute containing at least one occurrence of value within the string.\n - example: `*foo`\n - css equivalent: `[data-test-subj*=\"foo\"]`\n - DOM match example:
\n\n - prefixing a value with `^` will allow matching a `data-test-subj` attribute beginning with the specified value.\n - example: `^foo`\n - css equivalent: `[data-test-subj^=\"foo\"]`\n - DOM match example:
\n\n - prefixing a value with `~` will allow matching a `data-test-subj` attribute represented as a whitespace-separated list of words, one of which is exactly value\n - example: `~foo`\n - css equivalent: `[data-test-subj~=\"foo\"]`\n - DOM match example:
\n\n - the `>` character is used between two values to indicate that the value on the right must match an element inside an element matched by the value on the left\n - example: `foo > bar`\n - css equivalent: `[data-test-subj=foo] [data-test-subj=bar]`\n - DOM match example:\n
\n
\n
\n\n - the `&` character is used between two values to indicate that the value on both sides must both match the element\n - example: `foo & bar`\n - css equivalent: `[data-test-subj=foo][data-test-subj=bar]`\n - DOM match example:
" ], "signature": [ "(selector: string) => string" diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 0bf193f4157c..02c286b503a3 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_timerange.mdx b/api_docs/kbn_timerange.mdx index e6e3019fe75a..acc61504485a 100644 --- a/api_docs/kbn_timerange.mdx +++ b/api_docs/kbn_timerange.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-timerange title: "@kbn/timerange" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/timerange plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/timerange'] --- import kbnTimerangeObj from './kbn_timerange.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index cc46129af142..edf7f58b4bda 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_transpose_utils.mdx b/api_docs/kbn_transpose_utils.mdx index d29dc282dc1d..6c930f1bafb8 100644 --- a/api_docs/kbn_transpose_utils.mdx +++ b/api_docs/kbn_transpose_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-transpose-utils title: "@kbn/transpose-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/transpose-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/transpose-utils'] --- import kbnTransposeUtilsObj from './kbn_transpose_utils.devdocs.json'; diff --git a/api_docs/kbn_triggers_actions_ui_types.mdx b/api_docs/kbn_triggers_actions_ui_types.mdx index 93da565cf4d8..f7d11a0f01fc 100644 --- a/api_docs/kbn_triggers_actions_ui_types.mdx +++ b/api_docs/kbn_triggers_actions_ui_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-triggers-actions-ui-types title: "@kbn/triggers-actions-ui-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/triggers-actions-ui-types plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/triggers-actions-ui-types'] --- import kbnTriggersActionsUiTypesObj from './kbn_triggers_actions_ui_types.devdocs.json'; diff --git a/api_docs/kbn_try_in_console.mdx b/api_docs/kbn_try_in_console.mdx index 1733473c9cf7..0783a6380f40 100644 --- a/api_docs/kbn_try_in_console.mdx +++ b/api_docs/kbn_try_in_console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-try-in-console title: "@kbn/try-in-console" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/try-in-console plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/try-in-console'] --- import kbnTryInConsoleObj from './kbn_try_in_console.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.devdocs.json b/api_docs/kbn_ts_projects.devdocs.json index 6847c2a76965..f9a2cddcbfe0 100644 --- a/api_docs/kbn_ts_projects.devdocs.json +++ b/api_docs/kbn_ts_projects.devdocs.json @@ -213,6 +213,22 @@ "deprecated": false, "trackAdoption": false }, + { + "parentPluginId": "@kbn/ts-projects", + "id": "def-common.TsProject.isEsm", + "type": "CompoundType", + "tags": [], + "label": "isEsm", + "description": [ + "the package is esm or not" + ], + "signature": [ + "boolean | undefined" + ], + "path": "packages/kbn-ts-projects/ts_project.ts", + "deprecated": false, + "trackAdoption": false + }, { "parentPluginId": "@kbn/ts-projects", "id": "def-common.TsProject.rootImportReq", diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index 34fc4a73aa96..e0587ede01cf 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kiban | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 39 | 0 | 25 | 1 | +| 40 | 0 | 25 | 1 | ## Common diff --git a/api_docs/kbn_typed_react_router_config.devdocs.json b/api_docs/kbn_typed_react_router_config.devdocs.json index 9bab557b023f..f20c6013c647 100644 --- a/api_docs/kbn_typed_react_router_config.devdocs.json +++ b/api_docs/kbn_typed_react_router_config.devdocs.json @@ -1,26 +1,10 @@ { "id": "@kbn/typed-react-router-config", "client": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "server": { - "classes": [], - "functions": [], - "interfaces": [], - "enums": [], - "misc": [], - "objects": [] - }, - "common": { "classes": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.NotFoundRouteException", + "id": "def-public.NotFoundRouteException", "type": "Class", "tags": [], "label": "NotFoundRouteException", @@ -28,9 +12,9 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.NotFoundRouteException", + "section": "def-public.NotFoundRouteException", "text": "NotFoundRouteException" }, " extends Error" @@ -41,7 +25,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.NotFoundRouteException.Unnamed", + "id": "def-public.NotFoundRouteException.Unnamed", "type": "Function", "tags": [], "label": "Constructor", @@ -55,7 +39,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.NotFoundRouteException.Unnamed.$1", + "id": "def-public.NotFoundRouteException.Unnamed.$1", "type": "string", "tags": [], "label": "message", @@ -78,7 +62,52 @@ "functions": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.createRouter", + "id": "def-public.BreadcrumbsContextProvider", + "type": "Function", + "tags": [], + "label": "BreadcrumbsContextProvider", + "description": [], + "signature": [ + "({\n children,\n}: { children: React.ReactNode; }) => React.JSX.Element" + ], + "path": "packages/kbn-typed-react-router-config/src/breadcrumbs/context.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-public.BreadcrumbsContextProvider.$1", + "type": "Object", + "tags": [], + "label": "{\n children,\n}", + "description": [], + "path": "packages/kbn-typed-react-router-config/src/breadcrumbs/context.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-public.BreadcrumbsContextProvider.$1.children", + "type": "CompoundType", + "tags": [], + "label": "children", + "description": [], + "signature": [ + "string | number | boolean | React.ReactElement> | Iterable | React.ReactPortal | null | undefined" + ], + "path": "packages/kbn-typed-react-router-config/src/breadcrumbs/context.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-public.createRouter", "type": "Function", "tags": [], "label": "createRouter", @@ -87,9 +116,9 @@ "(routes: TRoutes) => ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, "" @@ -100,7 +129,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.createRouter.$1", + "id": "def-public.createRouter.$1", "type": "Uncategorized", "tags": [], "label": "routes", @@ -119,7 +148,43 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.CurrentRouteContextProvider", + "id": "def-public.createRouterBreadcrumbComponent", + "type": "Function", + "tags": [], + "label": "createRouterBreadcrumbComponent", + "description": [], + "signature": [ + "() => ", + "RouterBreadcrumb", + "" + ], + "path": "packages/kbn-typed-react-router-config/src/breadcrumbs/create_router_breadcrumb_component.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-public.createUseBreadcrumbs", + "type": "Function", + "tags": [], + "label": "createUseBreadcrumbs", + "description": [], + "signature": [ + "() => UseBreadcrumbs" + ], + "path": "packages/kbn-typed-react-router-config/src/breadcrumbs/use_router_breadcrumb.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-public.CurrentRouteContextProvider", "type": "Function", "tags": [], "label": "CurrentRouteContextProvider", @@ -128,17 +193,17 @@ "({ match, element, children, }: { match: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMatch", + "section": "def-public.RouteMatch", "text": "RouteMatch" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Route", + "section": "def-public.Route", "text": "Route" }, ">; element: React.ReactElement>; children: React.ReactElement>; }) => React.JSX.Element" @@ -149,7 +214,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.CurrentRouteContextProvider.$1", + "id": "def-public.CurrentRouteContextProvider.$1", "type": "Object", "tags": [], "label": "{\n match,\n element,\n children,\n}", @@ -160,7 +225,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.CurrentRouteContextProvider.$1.match", + "id": "def-public.CurrentRouteContextProvider.$1.match", "type": "Object", "tags": [], "label": "match", @@ -168,17 +233,17 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMatch", + "section": "def-public.RouteMatch", "text": "RouteMatch" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Route", + "section": "def-public.Route", "text": "Route" }, ">" @@ -189,7 +254,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.CurrentRouteContextProvider.$1.element", + "id": "def-public.CurrentRouteContextProvider.$1.element", "type": "Object", "tags": [], "label": "element", @@ -203,7 +268,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.CurrentRouteContextProvider.$1.children", + "id": "def-public.CurrentRouteContextProvider.$1.children", "type": "Object", "tags": [], "label": "children", @@ -223,7 +288,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Outlet", + "id": "def-public.Outlet", "type": "Function", "tags": [], "label": "Outlet", @@ -240,7 +305,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.OutletContextProvider", + "id": "def-public.OutletContextProvider", "type": "Function", "tags": [], "label": "OutletContextProvider", @@ -254,7 +319,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.OutletContextProvider.$1", + "id": "def-public.OutletContextProvider.$1", "type": "Object", "tags": [], "label": "{\n element,\n children,\n}", @@ -265,7 +330,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.OutletContextProvider.$1.element", + "id": "def-public.OutletContextProvider.$1.element", "type": "Object", "tags": [], "label": "element", @@ -279,7 +344,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.OutletContextProvider.$1.children", + "id": "def-public.OutletContextProvider.$1.children", "type": "CompoundType", "tags": [], "label": "children", @@ -299,7 +364,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterContextProvider", + "id": "def-public.RouterContextProvider", "type": "Function", "tags": [], "label": "RouterContextProvider", @@ -308,17 +373,17 @@ "({ router, children, }: { router: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", + "section": "def-public.RouteMap", "text": "RouteMap" }, ">; children: React.ReactNode; }) => React.JSX.Element" @@ -329,7 +394,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterContextProvider.$1", + "id": "def-public.RouterContextProvider.$1", "type": "Object", "tags": [], "label": "{\n router,\n children,\n}", @@ -340,7 +405,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterContextProvider.$1.router", + "id": "def-public.RouterContextProvider.$1.router", "type": "Object", "tags": [], "label": "router", @@ -348,17 +413,17 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", + "section": "def-public.RouteMap", "text": "RouteMap" }, ">" @@ -369,7 +434,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterContextProvider.$1.children", + "id": "def-public.RouterContextProvider.$1.children", "type": "CompoundType", "tags": [], "label": "children", @@ -389,7 +454,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteRenderer", + "id": "def-public.RouteRenderer", "type": "Function", "tags": [], "label": "RouteRenderer", @@ -406,7 +471,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterProvider", + "id": "def-public.RouterProvider", "type": "Function", "tags": [], "label": "RouterProvider", @@ -415,17 +480,17 @@ "({\n children,\n router,\n history,\n}: { router: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", + "section": "def-public.RouteMap", "text": "RouteMap" }, ">; history: ", @@ -438,7 +503,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterProvider.$1", + "id": "def-public.RouterProvider.$1", "type": "Object", "tags": [], "label": "{\n children,\n router,\n history,\n}", @@ -449,7 +514,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterProvider.$1.router", + "id": "def-public.RouterProvider.$1.router", "type": "Object", "tags": [], "label": "router", @@ -457,17 +522,17 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", + "section": "def-public.RouteMap", "text": "RouteMap" }, ">" @@ -478,7 +543,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterProvider.$1.history", + "id": "def-public.RouterProvider.$1.history", "type": "Object", "tags": [], "label": "history", @@ -493,7 +558,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouterProvider.$1.children", + "id": "def-public.RouterProvider.$1.children", "type": "CompoundType", "tags": [], "label": "children", @@ -513,7 +578,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useCurrentRoute", + "id": "def-public.useCurrentRoute", "type": "Function", "tags": [], "label": "useCurrentRoute", @@ -522,17 +587,17 @@ "() => { match: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMatch", + "section": "def-public.RouteMatch", "text": "RouteMatch" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Route", + "section": "def-public.Route", "text": "Route" }, ">; element: React.ReactElement>; }" @@ -546,7 +611,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useMatchRoutes", + "id": "def-public.useMatchRoutes", "type": "Function", "tags": [], "label": "useMatchRoutes", @@ -555,17 +620,17 @@ "(path: string | undefined) => ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMatch", + "section": "def-public.RouteMatch", "text": "RouteMatch" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Route", + "section": "def-public.Route", "text": "Route" }, ">[]" @@ -576,7 +641,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useMatchRoutes.$1", + "id": "def-public.useMatchRoutes.$1", "type": "string", "tags": [], "label": "path", @@ -595,7 +660,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useParams", + "id": "def-public.useParams", "type": "Function", "tags": [], "label": "useParams", @@ -604,9 +669,9 @@ "(args: any[]) => ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.DefaultOutput", + "section": "def-public.DefaultOutput", "text": "DefaultOutput" }, " | undefined" @@ -617,7 +682,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useParams.$1", + "id": "def-public.useParams.$1", "type": "Array", "tags": [], "label": "args", @@ -636,7 +701,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useRoutePath", + "id": "def-public.useRoutePath", "type": "Function", "tags": [], "label": "useRoutePath", @@ -653,7 +718,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.useRouter", + "id": "def-public.useRouter", "type": "Function", "tags": [], "label": "useRouter", @@ -662,20 +727,12 @@ "() => ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, - "<", - { - "pluginId": "@kbn/typed-react-router-config", - "scope": "common", - "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", - "text": "RouteMap" - }, - ">" + "" ], "path": "packages/kbn-typed-react-router-config/src/use_router.tsx", "deprecated": false, @@ -688,7 +745,7 @@ "interfaces": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.DefaultOutput", + "id": "def-public.DefaultOutput", "type": "Interface", "tags": [], "label": "DefaultOutput", @@ -699,7 +756,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.DefaultOutput.path", + "id": "def-public.DefaultOutput.path", "type": "Object", "tags": [], "label": "path", @@ -713,7 +770,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.DefaultOutput.query", + "id": "def-public.DefaultOutput.query", "type": "Object", "tags": [], "label": "query", @@ -730,7 +787,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Route", + "id": "def-public.Route", "type": "Interface", "tags": [], "label": "Route", @@ -741,7 +798,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Route.element", + "id": "def-public.Route.element", "type": "Object", "tags": [], "label": "element", @@ -755,7 +812,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Route.children", + "id": "def-public.Route.children", "type": "Object", "tags": [], "label": "children", @@ -763,9 +820,9 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", + "section": "def-public.RouteMap", "text": "RouteMap" }, " | undefined" @@ -776,7 +833,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Route.params", + "id": "def-public.Route.params", "type": "Object", "tags": [], "label": "params", @@ -791,7 +848,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Route.defaults", + "id": "def-public.Route.defaults", "type": "Object", "tags": [], "label": "defaults", @@ -805,7 +862,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Route.pre", + "id": "def-public.Route.pre", "type": "Object", "tags": [], "label": "pre", @@ -822,7 +879,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteMatch", + "id": "def-public.RouteMatch", "type": "Interface", "tags": [], "label": "RouteMatch", @@ -830,9 +887,9 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMatch", + "section": "def-public.RouteMatch", "text": "RouteMatch" }, "" @@ -843,7 +900,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteMatch.route", + "id": "def-public.RouteMatch.route", "type": "CompoundType", "tags": [], "label": "route", @@ -857,7 +914,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteMatch.match", + "id": "def-public.RouteMatch.match", "type": "Object", "tags": [], "label": "match", @@ -878,7 +935,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router", + "id": "def-public.Router", "type": "Interface", "tags": [], "label": "Router", @@ -886,9 +943,9 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Router", + "section": "def-public.Router", "text": "Router" }, "" @@ -899,7 +956,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.matchRoutes", + "id": "def-public.Router.matchRoutes", "type": "Function", "tags": [], "label": "matchRoutes", @@ -908,9 +965,9 @@ "{ >(path: TPath, location: ", @@ -918,9 +975,9 @@ "): ToRouteMatch<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Match", + "section": "def-public.Match", "text": "Match" }, ">; (location: ", @@ -928,17 +985,17 @@ "): ToRouteMatch<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Match", + "section": "def-public.Match", "text": "Match" }, ">>; }" @@ -949,7 +1006,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.matchRoutes.$1", + "id": "def-public.Router.matchRoutes.$1", "type": "Uncategorized", "tags": [], "label": "path", @@ -964,7 +1021,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.matchRoutes.$2", + "id": "def-public.Router.matchRoutes.$2", "type": "Object", "tags": [], "label": "location", @@ -983,7 +1040,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.matchRoutes", + "id": "def-public.Router.matchRoutes", "type": "Function", "tags": [], "label": "matchRoutes", @@ -992,9 +1049,9 @@ "{ >(path: TPath, location: ", @@ -1002,9 +1059,9 @@ "): ToRouteMatch<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Match", + "section": "def-public.Match", "text": "Match" }, ">; (location: ", @@ -1012,17 +1069,17 @@ "): ToRouteMatch<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Match", + "section": "def-public.Match", "text": "Match" }, ">>; }" @@ -1033,7 +1090,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.matchRoutes.$1", + "id": "def-public.Router.matchRoutes.$1", "type": "Object", "tags": [], "label": "location", @@ -1052,7 +1109,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams", + "id": "def-public.Router.getParams", "type": "Function", "tags": [], "label": "getParams", @@ -1061,9 +1118,9 @@ "{ >(path: TPath, location: ", @@ -1071,17 +1128,17 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1089,33 +1146,33 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, location: ", @@ -1123,41 +1180,41 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ", T3 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, path3: T3, location: ", @@ -1165,33 +1222,33 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1199,17 +1256,17 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; }" @@ -1220,7 +1277,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$1", + "id": "def-public.Router.getParams.$1", "type": "Uncategorized", "tags": [], "label": "path", @@ -1235,7 +1292,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$2", + "id": "def-public.Router.getParams.$2", "type": "Object", "tags": [], "label": "location", @@ -1254,7 +1311,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams", + "id": "def-public.Router.getParams", "type": "Function", "tags": [], "label": "getParams", @@ -1263,9 +1320,9 @@ "{ >(path: TPath, location: ", @@ -1273,17 +1330,17 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1291,33 +1348,33 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, location: ", @@ -1325,41 +1382,41 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ", T3 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, path3: T3, location: ", @@ -1367,33 +1424,33 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1401,17 +1458,17 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; }" @@ -1422,7 +1479,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$1", + "id": "def-public.Router.getParams.$1", "type": "Uncategorized", "tags": [], "label": "path", @@ -1437,7 +1494,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$2", + "id": "def-public.Router.getParams.$2", "type": "Object", "tags": [], "label": "location", @@ -1453,7 +1510,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$3", + "id": "def-public.Router.getParams.$3", "type": "Uncategorized", "tags": [], "label": "optional", @@ -1471,7 +1528,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams", + "id": "def-public.Router.getParams", "type": "Function", "tags": [], "label": "getParams", @@ -1480,9 +1537,9 @@ "{ >(path: TPath, location: ", @@ -1490,17 +1547,17 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1508,33 +1565,33 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, location: ", @@ -1542,41 +1599,41 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ", T3 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, path3: T3, location: ", @@ -1584,33 +1641,33 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1618,17 +1675,17 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; }" @@ -1639,7 +1696,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$1", + "id": "def-public.Router.getParams.$1", "type": "Uncategorized", "tags": [], "label": "path1", @@ -1654,7 +1711,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$2", + "id": "def-public.Router.getParams.$2", "type": "Uncategorized", "tags": [], "label": "path2", @@ -1669,7 +1726,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$3", + "id": "def-public.Router.getParams.$3", "type": "Object", "tags": [], "label": "location", @@ -1688,7 +1745,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams", + "id": "def-public.Router.getParams", "type": "Function", "tags": [], "label": "getParams", @@ -1697,9 +1754,9 @@ "{ >(path: TPath, location: ", @@ -1707,17 +1764,17 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1725,33 +1782,33 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, location: ", @@ -1759,41 +1816,41 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ", T3 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, path3: T3, location: ", @@ -1801,33 +1858,33 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1835,17 +1892,17 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; }" @@ -1856,7 +1913,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$1", + "id": "def-public.Router.getParams.$1", "type": "Uncategorized", "tags": [], "label": "path1", @@ -1871,7 +1928,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$2", + "id": "def-public.Router.getParams.$2", "type": "Uncategorized", "tags": [], "label": "path2", @@ -1886,7 +1943,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$3", + "id": "def-public.Router.getParams.$3", "type": "Uncategorized", "tags": [], "label": "path3", @@ -1901,7 +1958,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$4", + "id": "def-public.Router.getParams.$4", "type": "Object", "tags": [], "label": "location", @@ -1920,7 +1977,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams", + "id": "def-public.Router.getParams", "type": "Function", "tags": [], "label": "getParams", @@ -1929,9 +1986,9 @@ "{ >(path: TPath, location: ", @@ -1939,17 +1996,17 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -1957,33 +2014,33 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, location: ", @@ -1991,41 +2048,41 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , T2 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ", T3 extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, ">(path1: T1, path2: T2, path3: T3, location: ", @@ -2033,33 +2090,33 @@ "): ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; , TOptional extends boolean>(path: TPath, location: ", @@ -2067,17 +2124,17 @@ ", optional: TOptional): TOptional extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, " | undefined : ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, "; }" @@ -2088,7 +2145,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$1", + "id": "def-public.Router.getParams.$1", "type": "Uncategorized", "tags": [], "label": "path", @@ -2103,7 +2160,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$2", + "id": "def-public.Router.getParams.$2", "type": "Object", "tags": [], "label": "location", @@ -2119,7 +2176,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getParams.$3", + "id": "def-public.Router.getParams.$3", "type": "Uncategorized", "tags": [], "label": "optional", @@ -2137,7 +2194,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.link", + "id": "def-public.Router.link", "type": "Function", "tags": [], "label": "link", @@ -2146,25 +2203,25 @@ ">(path: TPath, ...args: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeAsArgs", + "section": "def-public.TypeAsArgs", "text": "TypeAsArgs" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, ">) => string" @@ -2175,7 +2232,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.link.$1", + "id": "def-public.Router.link.$1", "type": "Uncategorized", "tags": [], "label": "path", @@ -2190,7 +2247,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.link.$2", + "id": "def-public.Router.link.$2", "type": "Uncategorized", "tags": [], "label": "args", @@ -2198,17 +2255,17 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeAsArgs", + "section": "def-public.TypeAsArgs", "text": "TypeAsArgs" }, "<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.TypeOf", + "section": "def-public.TypeOf", "text": "TypeOf" }, ">" @@ -2223,7 +2280,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getRoutePath", + "id": "def-public.Router.getRoutePath", "type": "Function", "tags": [], "label": "getRoutePath", @@ -2232,9 +2289,9 @@ "(route: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteWithPath", + "section": "def-public.RouteWithPath", "text": "RouteWithPath" }, ") => string" @@ -2245,7 +2302,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getRoutePath.$1", + "id": "def-public.Router.getRoutePath.$1", "type": "Object", "tags": [], "label": "route", @@ -2253,9 +2310,9 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteWithPath", + "section": "def-public.RouteWithPath", "text": "RouteWithPath" } ], @@ -2269,7 +2326,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getRoutesToMatch", + "id": "def-public.Router.getRoutesToMatch", "type": "Function", "tags": [], "label": "getRoutesToMatch", @@ -2278,9 +2335,9 @@ "(path: string) => ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.FlattenRoutesOf", + "section": "def-public.FlattenRoutesOf", "text": "FlattenRoutesOf" }, "" @@ -2291,7 +2348,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Router.getRoutesToMatch.$1", + "id": "def-public.Router.getRoutesToMatch.$1", "type": "string", "tags": [], "label": "path", @@ -2312,7 +2369,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteWithPath", + "id": "def-public.RouteWithPath", "type": "Interface", "tags": [], "label": "RouteWithPath", @@ -2320,17 +2377,17 @@ "signature": [ { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteWithPath", + "section": "def-public.RouteWithPath", "text": "RouteWithPath" }, " extends ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Route", + "section": "def-public.Route", "text": "Route" } ], @@ -2340,7 +2397,7 @@ "children": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteWithPath.path", + "id": "def-public.RouteWithPath.path", "type": "string", "tags": [], "label": "path", @@ -2357,7 +2414,7 @@ "misc": [ { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.FlattenRoutesOf", + "id": "def-public.FlattenRoutesOf", "type": "Type", "tags": [], "label": "FlattenRoutesOf", @@ -2375,7 +2432,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.Match", + "id": "def-public.Match", "type": "Type", "tags": [], "label": "Match", @@ -2390,7 +2447,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.OutputOf", + "id": "def-public.OutputOf", "type": "Type", "tags": [], "label": "OutputOf", @@ -2399,17 +2456,17 @@ "OutputOfRoutes<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Match", + "section": "def-public.Match", "text": "Match" }, "> & ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.DefaultOutput", + "section": "def-public.DefaultOutput", "text": "DefaultOutput" } ], @@ -2420,7 +2477,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.PathsOf", + "id": "def-public.PathsOf", "type": "Type", "tags": [], "label": "PathsOf", @@ -2431,9 +2488,9 @@ "<{ [key in keyof TRouteMap]: key | (TRouteMap[key] extends { children: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.RouteMap", + "section": "def-public.RouteMap", "text": "RouteMap" }, "; } ? ", @@ -2441,9 +2498,9 @@ "<`${key & string}/*`> | ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.PathsOf", + "section": "def-public.PathsOf", "text": "PathsOf" }, " : never); }>" @@ -2455,7 +2512,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.RouteMap", + "id": "def-public.RouteMap", "type": "Type", "tags": [], "label": "RouteMap", @@ -2464,9 +2521,9 @@ "{ [x: string]: ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Route", + "section": "def-public.Route", "text": "Route" }, "; }" @@ -2478,7 +2535,7 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.TypeAsArgs", + "id": "def-public.TypeAsArgs", "type": "Type", "tags": [], "label": "TypeAsArgs", @@ -2495,7 +2552,24 @@ }, { "parentPluginId": "@kbn/typed-react-router-config", - "id": "def-common.TypeOf", + "id": "def-public.TypeAsParams", + "type": "Type", + "tags": [], + "label": "TypeAsParams", + "description": [], + "signature": [ + "keyof TObject extends never ? {} : ", + "RequiredKeys", + " extends never ? never : { params: TObject; }" + ], + "path": "packages/kbn-typed-react-router-config/src/types/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/typed-react-router-config", + "id": "def-public.TypeOf", "type": "Type", "tags": [], "label": "TypeOf", @@ -2504,17 +2578,17 @@ "TypeOfRoutes<", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.Match", + "section": "def-public.Match", "text": "Match" }, "> & (TWithDefaultOutput extends true ? ", { "pluginId": "@kbn/typed-react-router-config", - "scope": "common", + "scope": "public", "docId": "kibKbnTypedReactRouterConfigPluginApi", - "section": "def-common.DefaultOutput", + "section": "def-public.DefaultOutput", "text": "DefaultOutput" }, " : {})" @@ -2526,5 +2600,21 @@ } ], "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] } } \ No newline at end of file diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index f9ca394a7d8d..4c60563b2291 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; @@ -21,19 +21,19 @@ Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 86 | 0 | 86 | 1 | +| 92 | 0 | 92 | 2 | -## Common +## Client ### Functions - + ### Classes - + ### Interfaces - + ### Consts, variables and types - + diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index 55621afbc3ba..dad32cac09d5 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 8183be2c396b..a340b03cf1a9 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 7d9158b31993..9dabec875b0b 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.devdocs.json b/api_docs/kbn_unified_data_table.devdocs.json index 1398b8b7116a..0a59133908c6 100644 --- a/api_docs/kbn_unified_data_table.devdocs.json +++ b/api_docs/kbn_unified_data_table.devdocs.json @@ -823,7 +823,7 @@ "label": "UnifiedDataTable", "description": [], "signature": [ - "({ ariaLabelledBy, columns, columnsMeta, showColumnTokens, canDragAndDropColumns, configHeaderRowHeight, headerRowHeightState, onUpdateHeaderRowHeight, controlColumnIds, rowAdditionalLeadingControls, dataView, loadingState, onFilter, onResize, onSetColumns, onSort, rows, searchDescription, searchTitle, settings, showTimeCol, showFullScreenButton, sort, useNewFieldsApi, isSortEnabled, isPaginationEnabled, cellActionsTriggerId, cellActionsMetadata, cellActionsHandling, visibleCellActions, className, rowHeightState, onUpdateRowHeight, maxAllowedSampleSize, sampleSizeState, onUpdateSampleSize, isPlainRecord, rowsPerPageState, onUpdateRowsPerPage, onFieldEdited, services, renderCustomGridBody, renderCustomToolbar, externalControlColumns, trailingControlColumns, totalHits, onFetchMoreRecords, renderDocumentView, setExpandedDoc, expandedDoc, configRowHeight, showMultiFields, maxDocFieldsDisplayed, externalAdditionalControls, rowsPerPageOptions, externalCustomRenderers, additionalFieldGroups, consumer, componentsTourSteps, gridStyleOverride, rowLineHeightOverride, customGridColumnsConfiguration, enableComparisonMode, cellContext, renderCellPopover, getRowIndicator, dataGridDensityState, onUpdateDataGridDensity, }: ", + "({ ariaLabelledBy, columns, columnsMeta, showColumnTokens, canDragAndDropColumns, configHeaderRowHeight, headerRowHeightState, onUpdateHeaderRowHeight, controlColumnIds, rowAdditionalLeadingControls, dataView, loadingState, onFilter, onResize, onSetColumns, onSort, rows, searchDescription, searchTitle, settings, showTimeCol, showFullScreenButton, sort, useNewFieldsApi, isSortEnabled, isPaginationEnabled, cellActionsTriggerId, cellActionsMetadata, cellActionsHandling, visibleCellActions, className, rowHeightState, onUpdateRowHeight, maxAllowedSampleSize, sampleSizeState, onUpdateSampleSize, isPlainRecord, rowsPerPageState, onUpdateRowsPerPage, onFieldEdited, services, renderCustomGridBody, renderCustomToolbar, externalControlColumns, trailingControlColumns, totalHits, onFetchMoreRecords, renderDocumentView, setExpandedDoc, expandedDoc, configRowHeight, showMultiFields, maxDocFieldsDisplayed, externalAdditionalControls, rowsPerPageOptions, externalCustomRenderers, additionalFieldGroups, consumer, componentsTourSteps, gridStyleOverride, rowLineHeightOverride, customGridColumnsConfiguration, enableComparisonMode, cellContext, renderCellPopover, getRowIndicator, dataGridDensityState, onUpdateDataGridDensity, onUpdatePageIndex, }: ", { "pluginId": "@kbn/unified-data-table", "scope": "public", @@ -842,7 +842,7 @@ "id": "def-public.UnifiedDataTable.$1", "type": "Object", "tags": [], - "label": "{\n ariaLabelledBy,\n columns,\n columnsMeta,\n showColumnTokens,\n canDragAndDropColumns,\n configHeaderRowHeight,\n headerRowHeightState,\n onUpdateHeaderRowHeight,\n controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT,\n rowAdditionalLeadingControls,\n dataView,\n loadingState,\n onFilter,\n onResize,\n onSetColumns,\n onSort,\n rows,\n searchDescription,\n searchTitle,\n settings,\n showTimeCol,\n showFullScreenButton = true,\n sort,\n useNewFieldsApi,\n isSortEnabled = true,\n isPaginationEnabled = true,\n cellActionsTriggerId,\n cellActionsMetadata,\n cellActionsHandling = 'replace',\n visibleCellActions,\n className,\n rowHeightState,\n onUpdateRowHeight,\n maxAllowedSampleSize,\n sampleSizeState,\n onUpdateSampleSize,\n isPlainRecord = false,\n rowsPerPageState,\n onUpdateRowsPerPage,\n onFieldEdited,\n services,\n renderCustomGridBody,\n renderCustomToolbar,\n externalControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n trailingControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n totalHits,\n onFetchMoreRecords,\n renderDocumentView,\n setExpandedDoc,\n expandedDoc,\n configRowHeight,\n showMultiFields = true,\n maxDocFieldsDisplayed = 50,\n externalAdditionalControls,\n rowsPerPageOptions,\n externalCustomRenderers,\n additionalFieldGroups,\n consumer = 'discover',\n componentsTourSteps,\n gridStyleOverride,\n rowLineHeightOverride,\n customGridColumnsConfiguration,\n enableComparisonMode,\n cellContext,\n renderCellPopover,\n getRowIndicator,\n dataGridDensityState,\n onUpdateDataGridDensity,\n}", + "label": "{\n ariaLabelledBy,\n columns,\n columnsMeta,\n showColumnTokens,\n canDragAndDropColumns,\n configHeaderRowHeight,\n headerRowHeightState,\n onUpdateHeaderRowHeight,\n controlColumnIds = CONTROL_COLUMN_IDS_DEFAULT,\n rowAdditionalLeadingControls,\n dataView,\n loadingState,\n onFilter,\n onResize,\n onSetColumns,\n onSort,\n rows,\n searchDescription,\n searchTitle,\n settings,\n showTimeCol,\n showFullScreenButton = true,\n sort,\n useNewFieldsApi,\n isSortEnabled = true,\n isPaginationEnabled = true,\n cellActionsTriggerId,\n cellActionsMetadata,\n cellActionsHandling = 'replace',\n visibleCellActions,\n className,\n rowHeightState,\n onUpdateRowHeight,\n maxAllowedSampleSize,\n sampleSizeState,\n onUpdateSampleSize,\n isPlainRecord = false,\n rowsPerPageState,\n onUpdateRowsPerPage,\n onFieldEdited,\n services,\n renderCustomGridBody,\n renderCustomToolbar,\n externalControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n trailingControlColumns, // TODO: deprecate in favor of rowAdditionalLeadingControls\n totalHits,\n onFetchMoreRecords,\n renderDocumentView,\n setExpandedDoc,\n expandedDoc,\n configRowHeight,\n showMultiFields = true,\n maxDocFieldsDisplayed = 50,\n externalAdditionalControls,\n rowsPerPageOptions,\n externalCustomRenderers,\n additionalFieldGroups,\n consumer = 'discover',\n componentsTourSteps,\n gridStyleOverride,\n rowLineHeightOverride,\n customGridColumnsConfiguration,\n enableComparisonMode,\n cellContext,\n renderCellPopover,\n getRowIndicator,\n dataGridDensityState,\n onUpdateDataGridDensity,\n onUpdatePageIndex,\n}", "description": [], "signature": [ { @@ -1962,6 +1962,40 @@ ], "returnComment": [] }, + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-public.UnifiedDataTableProps.onUpdatePageIndex", + "type": "Function", + "tags": [], + "label": "onUpdatePageIndex", + "description": [ + "\n\nthis callback is triggered when user navigates to a different page\n" + ], + "signature": [ + "((pageIndex: number) => void) | undefined" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/unified-data-table", + "id": "def-public.UnifiedDataTableProps.onUpdatePageIndex.$1", + "type": "number", + "tags": [], + "label": "pageIndex", + "description": [], + "signature": [ + "number" + ], + "path": "packages/kbn-unified-data-table/src/components/data_table.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, { "parentPluginId": "@kbn/unified-data-table", "id": "def-public.UnifiedDataTableProps.maxAllowedSampleSize", @@ -3144,7 +3178,7 @@ "label": "CustomCellRenderer", "description": [], "signature": [ - "{ [x: string]: (props: ", + "{ [x: string]: React.FunctionComponent<", { "pluginId": "@kbn/unified-data-table", "scope": "public", @@ -3152,7 +3186,7 @@ "section": "def-public.DataGridCellValueElementProps", "text": "DataGridCellValueElementProps" }, - ") => React.ReactElement>; }" + ">; }" ], "path": "packages/kbn-unified-data-table/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index f64d39ea763d..b8313c9fd1fd 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 184 | 0 | 108 | 1 | +| 186 | 0 | 109 | 1 | ## Client diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index a0dff14745b5..a0b82df40b47 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 27798da4853c..c1f54be675e4 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_badge.mdx b/api_docs/kbn_unsaved_changes_badge.mdx index bd5fc698832c..1db7abc927de 100644 --- a/api_docs/kbn_unsaved_changes_badge.mdx +++ b/api_docs/kbn_unsaved_changes_badge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-badge title: "@kbn/unsaved-changes-badge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-badge plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-badge'] --- import kbnUnsavedChangesBadgeObj from './kbn_unsaved_changes_badge.devdocs.json'; diff --git a/api_docs/kbn_unsaved_changes_prompt.mdx b/api_docs/kbn_unsaved_changes_prompt.mdx index 3d7f1d13ac42..56383bcf3c70 100644 --- a/api_docs/kbn_unsaved_changes_prompt.mdx +++ b/api_docs/kbn_unsaved_changes_prompt.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unsaved-changes-prompt title: "@kbn/unsaved-changes-prompt" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unsaved-changes-prompt plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unsaved-changes-prompt'] --- import kbnUnsavedChangesPromptObj from './kbn_unsaved_changes_prompt.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 595677944190..5222c704661a 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index e47bdddd5c2d..cd218a070b83 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.devdocs.json b/api_docs/kbn_utility_types.devdocs.json index 6d177a2aa2cf..b9cdddfd3ad0 100644 --- a/api_docs/kbn_utility_types.devdocs.json +++ b/api_docs/kbn_utility_types.devdocs.json @@ -361,11 +361,11 @@ "signature": [ "(Exclude<", "ValuesType", - "<{ [TKey in keyof TObject]: {} extends Pick ? ", + "<{ [TKey in keyof TObject as string]: string extends TKey ? Record : {} extends Pick ? ", "DeepPartial", ">> : DedotKey; }>, undefined> extends any ? (k: Exclude<", "ValuesType", - "<{ [TKey in keyof TObject]: {} extends Pick ? ", + "<{ [TKey in keyof TObject as string]: string extends TKey ? Record : {} extends Pick ? ", "DeepPartial", ">> : DedotKey; }>, undefined>) => void : never) extends (k: infer I) => void ? I : never" ], diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index 40fe2128fb54..87ecf211ccc4 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2024-11-22 +date: 2024-12-03 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 a06e735b99af..4b49518487ea 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2024-11-22 +date: 2024-12-03 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 a25ca1af3e9a..3dec60b9418d 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 0a0219896da7..c68e7f789a97 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_visualization_utils.mdx b/api_docs/kbn_visualization_utils.mdx index 940e0a88cd7e..c2fcf6978f62 100644 --- a/api_docs/kbn_visualization_utils.mdx +++ b/api_docs/kbn_visualization_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-utils title: "@kbn/visualization-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-utils'] --- import kbnVisualizationUtilsObj from './kbn_visualization_utils.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index df3dff9fb6c9..231e5ddd1e1a 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 2837099abf79..0517fbdcc640 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod.devdocs.json b/api_docs/kbn_zod.devdocs.json index 4fbf59e5edf5..9f1ada94d8e6 100644 --- a/api_docs/kbn_zod.devdocs.json +++ b/api_docs/kbn_zod.devdocs.json @@ -19198,7 +19198,7 @@ "label": "ZodFirstPartySchemaTypes", "description": [], "signature": [ - "Zod.ZodString | Zod.ZodBoolean | Zod.ZodNumber | Zod.ZodUnknown | Zod.ZodNull | Zod.ZodAny | Zod.ZodUndefined | Zod.ZodBigInt | Zod.ZodDate | Zod.ZodSymbol | Zod.ZodNever | Zod.ZodVoid | Zod.ZodTuple | Zod.ZodNaN | Zod.ZodArray | Zod.ZodObject | Zod.ZodUnion | Zod.ZodDiscriminatedUnion | Zod.ZodIntersection | Zod.ZodRecord | Zod.ZodMap | Zod.ZodSet | Zod.ZodFunction | Zod.ZodLazy | Zod.ZodLiteral | Zod.ZodEnum | Zod.ZodEffects | Zod.ZodNativeEnum | Zod.ZodOptional | Zod.ZodNullable | Zod.ZodDefault | Zod.ZodCatch | Zod.ZodPromise | Zod.ZodBranded | Zod.ZodPipeline | Zod.ZodReadonly" + "Zod.ZodString | Zod.ZodBoolean | Zod.ZodNumber | Zod.ZodNull | Zod.ZodUnknown | Zod.ZodAny | Zod.ZodUndefined | Zod.ZodBigInt | Zod.ZodDate | Zod.ZodSymbol | Zod.ZodNever | Zod.ZodVoid | Zod.ZodTuple | Zod.ZodNaN | Zod.ZodArray | Zod.ZodObject | Zod.ZodUnion | Zod.ZodDiscriminatedUnion | Zod.ZodIntersection | Zod.ZodRecord | Zod.ZodMap | Zod.ZodSet | Zod.ZodFunction | Zod.ZodLazy | Zod.ZodLiteral | Zod.ZodEnum | Zod.ZodEffects | Zod.ZodNativeEnum | Zod.ZodOptional | Zod.ZodNullable | Zod.ZodDefault | Zod.ZodCatch | Zod.ZodPromise | Zod.ZodBranded | Zod.ZodPipeline | Zod.ZodReadonly" ], "path": "node_modules/zod/lib/types.d.ts", "deprecated": false, diff --git a/api_docs/kbn_zod.mdx b/api_docs/kbn_zod.mdx index c41764cb16c3..086e598844ac 100644 --- a/api_docs/kbn_zod.mdx +++ b/api_docs/kbn_zod.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod title: "@kbn/zod" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod'] --- import kbnZodObj from './kbn_zod.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx index 80f634d7b555..963af679b9ae 100644 --- a/api_docs/kbn_zod_helpers.mdx +++ b/api_docs/kbn_zod_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-zod-helpers title: "@kbn/zod-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/zod-helpers plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] --- import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 988b049574fc..5aa289d15279 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2024-11-22 +date: 2024-12-03 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 133ca02a6cbc..5d988082e379 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2024-11-22 +date: 2024-12-03 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 4c68a44bbbb3..6787003f7894 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2024-11-22 +date: 2024-12-03 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 b7e342898acb..5c57711ffd9d 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.devdocs.json b/api_docs/lens.devdocs.json index 57dcd5ec5057..013522ad1baf 100644 --- a/api_docs/lens.devdocs.json +++ b/api_docs/lens.devdocs.json @@ -1,2581 +1,1497 @@ { "id": "lens", "client": { - "classes": [ + "classes": [], + "functions": [ { "parentPluginId": "lens", - "id": "def-public.Embeddable", - "type": "Class", + "id": "def-public.isLensApi", + "type": "Function", "tags": [], - "label": "Embeddable", + "label": "isLensApi", "description": [], "signature": [ + "(api: unknown) => api is { uuid: string; panelTitle: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Embeddable", - "text": "Embeddable" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - " extends ", + "; hidePanelTitle: ", { - "pluginId": "embeddable", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibEmbeddablePluginApi", - "section": "def-public.Embeddable", - "text": "Embeddable" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - "<", + "; defaultPanelTitle?: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableInput", - "text": "LensEmbeddableInput" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - ", ", + " | undefined; dataLoading: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableOutput", - "text": "LensEmbeddableOutput" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - ", any> implements ", + "; blockingError: ", { - "pluginId": "embeddable", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibEmbeddablePluginApi", - "section": "def-public.ReferenceOrValueEmbeddable", - "text": "ReferenceOrValueEmbeddable" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - "<", - "LensByValueInput", - ", ", - "LensByReferenceInput", - ">,", + "; panelDescription: ", { - "pluginId": "embeddable", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibEmbeddablePluginApi", - "section": "def-public.SelfStyledEmbeddable", - "text": "SelfStyledEmbeddable" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - ",", + "; defaultPanelDescription?: ", { - "pluginId": "embeddable", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibEmbeddablePluginApi", - "section": "def-public.FilterableEmbeddable", - "text": "FilterableEmbeddable" - } - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; disabledActionIds: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.type", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; setDisabledActionIds: (ids: string[] | undefined) => void; getAllTriggersDisabled?: (() => boolean) | undefined; parentApi?: (", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.deferEmbeddableLoad", - "type": "boolean", - "tags": [], - "label": "deferEmbeddableLoad", - "description": [], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-containers", + "scope": "public", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-public.PresentationContainer", + "text": "PresentationContainer" }, + " & Partial, ", - { - "pluginId": "embeddable", - "scope": "public", - "docId": "kibEmbeddablePluginApi", - "section": "def-public.ContainerOutput", - "text": "ContainerOutput" - }, - "> | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesPanelTitle", + "text": "PublishesPanelTitle" }, + ", \"hidePanelTitle\"> & ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getUserMessages", - "type": "Function", - "tags": [], - "label": "getUserMessages", - "description": [], - "signature": [ - "(locationId: \"banner\" | \"toolbar\" | \"visualization\" | \"embeddableBadge\" | \"visualizationOnEmbeddable\" | \"visualizationInEditor\" | \"textBasedLanguagesQueryInput\" | \"dimensionButton\" | (\"banner\" | \"toolbar\" | \"visualization\" | \"embeddableBadge\" | \"visualizationOnEmbeddable\" | \"visualizationInEditor\" | \"textBasedLanguagesQueryInput\" | \"dimensionButton\")[] | undefined, filters: ", - "UserMessageFilters", - " | undefined) => ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.UserMessage", - "text": "UserMessage" - }, - "[]" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getUserMessages.$1", - "type": "CompoundType", - "tags": [], - "label": "locationId", - "description": [], - "signature": [ - "\"banner\" | \"toolbar\" | \"visualization\" | \"embeddableBadge\" | \"visualizationOnEmbeddable\" | \"visualizationInEditor\" | \"textBasedLanguagesQueryInput\" | \"dimensionButton\" | (\"banner\" | \"toolbar\" | \"visualization\" | \"embeddableBadge\" | \"visualizationOnEmbeddable\" | \"visualizationInEditor\" | \"textBasedLanguagesQueryInput\" | \"dimensionButton\")[] | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getUserMessages.$2", - "type": "Object", - "tags": [], - "label": "filters", - "description": [], - "signature": [ - "UserMessageFilters", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesViewMode", + "text": "PublishesViewMode" }, + ">) | undefined; hasLockedHoverActions$?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.reportsEmbeddableLoad", - "type": "Function", - "tags": [], - "label": "reportsEmbeddableLoad", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + " | undefined; lockHoverActions?: ((lock: boolean) => void) | undefined; type: string; phase$: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.supportedTriggers", - "type": "Function", - "tags": [], - "label": "supportedTriggers", - "description": [], - "signature": [ - "() => string[]" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getInspectorAdapters", - "type": "Function", - "tags": [], - "label": "getInspectorAdapters", - "description": [], - "signature": [ - "() => ", - { - "pluginId": "inspector", - "scope": "common", - "docId": "kibInspectorPluginApi", - "section": "def-common.Adapters", - "text": "Adapters" - } - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PhaseEvent", + "text": "PhaseEvent" }, + " | undefined>; unsavedChanges?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getFullAttributes", - "type": "Function", - "tags": [], - "label": "getFullAttributes", - "description": [], - "signature": [ - "() => ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSavedObjectAttributes", - "text": "LensSavedObjectAttributes" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + " | undefined; resetUnsavedChanges?: (() => void) | undefined; serializeState: () => ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.isTextBasedLanguage", - "type": "Function", - "tags": [], - "label": "isTextBasedLanguage", - "description": [], - "signature": [ - "() => boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.MaybePromise", + "text": "MaybePromise" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getTextBasedLanguage", - "type": "Function", - "tags": [], - "label": "getTextBasedLanguage", - "description": [], - "signature": [ - "() => string | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-containers", + "scope": "public", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-public.SerializedPanelState", + "text": "SerializedPanelState" }, + "<{ attributes?: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateVisualization", - "type": "Function", - "tags": [], - "label": "updateVisualization", - "description": [ - "\nGets the Lens embeddable's datasource and visualization states\nupdates the embeddable input" - ], - "signature": [ - "(datasourceState: unknown, visualizationState: unknown, visualizationType?: string | undefined) => Promise" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateVisualization.$1", - "type": "Unknown", - "tags": [], - "label": "datasourceState", - "description": [], - "signature": [ - "unknown" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateVisualization.$2", - "type": "Unknown", - "tags": [], - "label": "visualizationState", - "description": [], - "signature": [ - "unknown" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateVisualization.$3", - "type": "string", - "tags": [], - "label": "visualizationType", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateSuggestion", - "type": "Function", - "tags": [], - "label": "updateSuggestion", - "description": [], - "signature": [ - "(attrs: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSavedObjectAttributes", - "text": "LensSavedObjectAttributes" - }, - ") => Promise" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateSuggestion.$1", - "type": "Object", - "tags": [], - "label": "attrs", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSavedObjectAttributes", - "text": "LensSavedObjectAttributes" - } - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateByRefInput", - "type": "Function", - "tags": [], - "label": "updateByRefInput", - "description": [], - "signature": [ - "(savedObjectId: string) => void" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.updateByRefInput.$1", - "type": "string", - "tags": [], - "label": "savedObjectId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record void) | undefined) => Promise" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.openConfigPanel.$1", - "type": "Object", - "tags": [], - "label": "startDependencies", - "description": [], - "signature": [ - "LensPluginStartDependencies" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.openConfigPanel.$2", - "type": "CompoundType", - "tags": [], - "label": "isNewPanel", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.openConfigPanel.$3", - "type": "Function", - "tags": [], - "label": "deletePanel", - "description": [], - "signature": [ - "(() => void) | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.initializeSavedVis", - "type": "Function", - "tags": [], - "label": "initializeSavedVis", - "description": [], - "signature": [ - "(input: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableInput", - "text": "LensEmbeddableInput" - }, - ") => Promise" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.initializeSavedVis.$1", - "type": "CompoundType", - "tags": [], - "label": "input", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableInput", - "text": "LensEmbeddableInput" - } - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getExecutionContext", - "type": "Function", - "tags": [], - "label": "getExecutionContext", - "description": [], - "signature": [ - "() => ", - { - "pluginId": "@kbn/core-execution-context-common", - "scope": "common", - "docId": "kibKbnCoreExecutionContextCommonPluginApi", - "section": "def-common.KibanaExecutionContext", - "text": "KibanaExecutionContext" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string | null; } | undefined; savedObjectId?: string | undefined; references?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.render", - "type": "Function", - "tags": [], - "label": "render", - "description": [ - "\n" - ], - "signature": [ - "(domNode: HTMLElement | Element) => void" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.render.$1", - "type": "CompoundType", - "tags": [], - "label": "domNode", - "description": [], - "signature": [ - "HTMLElement | Element" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.handleEvent", - "type": "Function", - "tags": [], - "label": "handleEvent", - "description": [], - "signature": [ - "(event: ", - { - "pluginId": "expressions", - "scope": "public", - "docId": "kibExpressionsPluginApi", - "section": "def-public.ExpressionRendererEvent", - "text": "ExpressionRendererEvent" - }, - ") => Promise" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.handleEvent.$1", - "type": "Object", - "tags": [], - "label": "event", - "description": [], - "signature": [ - { - "pluginId": "expressions", - "scope": "public", - "docId": "kibExpressionsPluginApi", - "section": "def-public.ExpressionRendererEvent", - "text": "ExpressionRendererEvent" - } - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial void" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<{ duration: number; } | undefined>; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial ", - "ViewUnderlyingDataArgs", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "RecursivePartial", + "> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.canViewUnderlyingData$", - "type": "Object", - "tags": [], - "label": "canViewUnderlyingData$", - "description": [], - "signature": [ - "BehaviorSubject", - "" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.initializeOutput", - "type": "Function", - "tags": [], - "label": "initializeOutput", - "description": [], - "signature": [ - "() => Promise" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getIsEditable", - "type": "Function", - "tags": [], - "label": "getIsEditable", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.inputIsRefType", - "type": "Function", - "tags": [], - "label": "inputIsRefType", - "description": [], - "signature": [ - "(input: ", - "LensByValueInput", - " | ", - "LensByReferenceInput", - ") => input is ", - "LensByReferenceInput" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Embeddable.inputIsRefType.$1", - "type": "CompoundType", - "tags": [], - "label": "input", - "description": [], - "signature": [ - "LensByValueInput", - " | ", - "LensByReferenceInput" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getInputAsRefType", - "type": "Function", - "tags": [], - "label": "getInputAsRefType", - "description": [], - "signature": [ - "() => Promise<", - "LensByReferenceInput", - ">" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getInputAsValueType", - "type": "Function", - "tags": [], - "label": "getInputAsValueType", - "description": [], - "signature": [ - "() => Promise<", - "LensByValueInput", - ">" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined; timeslice?: [number, number] | undefined; searchSessionId?: string | undefined; lastReloadRequestTime?: number | undefined; id?: string | undefined; renderMode?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getFilters", - "type": "Function", - "tags": [], - "label": "getFilters", - "description": [ - "\nGets the Lens embeddable's local filters" - ], - "signature": [ - "() => ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - "[]" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [ - "Local/panel-level array of filters for Lens embeddable" - ] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; disableTriggers?: boolean | undefined; syncColors?: boolean | undefined; syncTooltips?: boolean | undefined; syncCursor?: boolean | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getQuery", - "type": "Function", - "tags": [], - "label": "getQuery", - "description": [ - "\nGets the Lens embeddable's local query" - ], - "signature": [ - "() => ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Query", - "text": "Query" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [ - "Local/panel-level query for Lens embeddable" - ] + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" }, + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getSavedVis", - "type": "Function", - "tags": [], - "label": "getSavedVis", - "description": [], - "signature": [ - "() => Readonly<", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSavedObjectAttributes", - "text": "LensSavedObjectAttributes" - }, - " | undefined>" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.destroy", - "type": "Function", - "tags": [], - "label": "destroy", - "description": [], - "signature": [ - "() => void" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" }, + " | undefined; enhancements?: { dynamicActions: ", { - "parentPluginId": "lens", - "id": "def-public.Embeddable.getSelfStyledOptions", - "type": "Function", - "tags": [], - "label": "getSelfStyledOptions", - "description": [], - "signature": [ - "() => { hideTitle: boolean | undefined; }" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - } - ], - "initialIsOpen": false - } - ], - "functions": [ - { - "parentPluginId": "lens", - "id": "def-public.isLensApi", - "type": "Function", - "tags": [], - "label": "isLensApi", - "description": [], - "signature": [ - "(api: unknown) => api is ", + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; isNewPanel?: boolean | undefined; }>>; snapshotRuntimeState: () => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensApi", - "text": "LensApi" - } - ], - "path": "x-pack/plugins/lens/public/embeddable/interfaces/lens_api.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.isLensApi.$1", - "type": "Unknown", - "tags": [], - "label": "api", - "description": [], - "signature": [ - "unknown" - ], - "path": "x-pack/plugins/lens/public/embeddable/interfaces/lens_api.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - } - ], - "interfaces": [ - { - "parentPluginId": "lens", - "id": "def-public.AxesSettingsConfig", - "type": "Interface", - "tags": [], - "label": "AxesSettingsConfig", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.AxesSettingsConfig.yLeft", - "type": "boolean", - "tags": [], - "label": "yLeft", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.AxesSettingsConfig.yRight", - "type": "boolean", - "tags": [], - "label": "yRight", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.AxisConfig", - "type": "Interface", - "tags": [], - "label": "AxisConfig", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.hide", - "type": "CompoundType", - "tags": [], - "label": "hide", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.id", - "type": "string", - "tags": [], - "label": "id", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.position", - "type": "CompoundType", - "tags": [], - "label": "position", - "description": [], - "signature": [ - "Position", - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.showOverlappingLabels", - "type": "CompoundType", - "tags": [], - "label": "showOverlappingLabels", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.truncate", - "type": "number", - "tags": [], - "label": "truncate", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.showLabels", - "type": "CompoundType", - "tags": [], - "label": "showLabels", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.showTitle", - "type": "CompoundType", - "tags": [], - "label": "showTitle", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" }, + " | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.showGridLines", - "type": "CompoundType", - "tags": [], - "label": "showGridLines", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", { - "parentPluginId": "lens", - "id": "def-public.AxisConfig.extent", - "type": "CompoundType", - "tags": [], - "label": "extent", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.AxisExtentConfigResult", - "text": "AxisExtentConfigResult" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.AxisExtentConfig", - "type": "Interface", - "tags": [], - "label": "AxisExtentConfig", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.AxisExtentConfig.mode", - "type": "CompoundType", - "tags": [], - "label": "mode", - "description": [], - "signature": [ - "\"custom\" | \"full\" | \"dataBounds\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", { - "parentPluginId": "lens", - "id": "def-public.AxisExtentConfig.lowerBound", - "type": "number", - "tags": [], - "label": "lowerBound", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.AxisExtentConfig.upperBound", - "type": "number", - "tags": [], - "label": "upperBound", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.AxisExtentConfig.enforce", - "type": "CompoundType", - "tags": [], - "label": "enforce", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.AxisExtentConfig.niceValues", - "type": "CompoundType", - "tags": [], - "label": "niceValues", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.CardinalityIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "CardinalityIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; onEdit: () => Promise; isEditingEnabled: () => boolean; getEditHref?: (() => Promise) | undefined; getTypeDisplayName: () => string; getTypeDisplayNameLowerCase?: (() => string) | undefined; timeRange$: ", + { + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.CardinalityIndexPatternColumn", - "text": "CardinalityIndexPatternColumn" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - " extends ", + "<", { - "pluginId": "lens", + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined>; timeRestore$?: ", + { + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/cardinality.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; timeslice$?: ", { - "parentPluginId": "lens", - "id": "def-public.CardinalityIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"unique_count\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/cardinality.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<[number, number] | undefined> | undefined; filters$: ", { - "parentPluginId": "lens", - "id": "def-public.CardinalityIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/cardinality.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.ChartInfo", - "type": "Interface", - "tags": [], - "label": "ChartInfo", - "description": [], - "path": "x-pack/plugins/lens/public/chart_info_api.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", { - "parentPluginId": "lens", - "id": "def-public.ChartInfo.layers", - "type": "Array", - "tags": [], - "label": "layers", - "description": [], - "signature": [ - "ChartLayerDescriptor", - "[]" - ], - "path": "x-pack/plugins/lens/public/chart_info_api.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined>; isCompatibleWithUnifiedSearch?: (() => boolean) | undefined; query$: ", { - "parentPluginId": "lens", - "id": "def-public.ChartInfo.visualizationType", - "type": "string", - "tags": [], - "label": "visualizationType", - "description": [], - "path": "x-pack/plugins/lens/public/chart_info_api.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.ChartInfo.filters", - "type": "Array", - "tags": [], - "label": "filters", - "description": [], - "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Filter", - "text": "Filter" - }, - "[]" - ], - "path": "x-pack/plugins/lens/public/chart_info_api.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.ChartInfo.query", - "type": "Object", - "tags": [], - "label": "query", - "description": [], - "signature": [ - "{ query: string | { [key: string]: any; }; language: string; }" - ], - "path": "x-pack/plugins/lens/public/chart_info_api.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs", - "type": "Interface", - "tags": [], - "label": "DataLayerArgs", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.accessors", - "type": "Array", - "tags": [], - "label": "accessors", - "description": [], - "signature": [ - "(string | ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.ExpressionValueVisDimension", - "text": "ExpressionValueVisDimension" - }, - ")[]" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.seriesType", - "type": "CompoundType", - "tags": [], - "label": "seriesType", - "description": [], - "signature": [ - "\"area\" | \"line\" | \"bar\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.xAccessor", - "type": "CompoundType", - "tags": [], - "label": "xAccessor", - "description": [], - "signature": [ - "string | ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.ExpressionValueVisDimension", - "text": "ExpressionValueVisDimension" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.simpleView", - "type": "CompoundType", - "tags": [], - "label": "simpleView", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined>; rendered$: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.splitAccessors", - "type": "Array", - "tags": [], - "label": "splitAccessors", - "description": [], - "signature": [ - "(string | ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.ExpressionValueVisDimension", - "text": "ExpressionValueVisDimension" - }, - ")[] | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; dataViews: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.markSizeAccessor", - "type": "CompoundType", - "tags": [], - "label": "markSizeAccessor", - "description": [], - "signature": [ - "string | ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.ExpressionValueVisDimension", - "text": "ExpressionValueVisDimension" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.lineWidth", - "type": "number", - "tags": [], - "label": "lineWidth", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" }, + "[] | undefined>; setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; setPanelDescription: (newTitle: string | undefined) => void; supportedTriggers: () => string[]; libraryId$: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.showPoints", - "type": "CompoundType", - "tags": [], - "label": "showPoints", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; saveToLibrary: ((title: string) => Promise) & ((title: string) => Promise); getByValueRuntimeSnapshot: () => object; unlinkFromLibrary: () => void; canLinkToLibrary: () => Promise; canUnlinkFromLibrary: () => Promise; checkForDuplicateTitle: (newTitle: string, isTitleDuplicateConfirmed: boolean, onTitleDuplicate: () => void) => Promise; getByReferenceState: (libraryId: string) => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.showLines", - "type": "CompoundType", - "tags": [], - "label": "showLines", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.pointsRadius", - "type": "number", - "tags": [], - "label": "pointsRadius", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.columnToLabel", - "type": "string", - "tags": [], - "label": "columnToLabel", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.xScaleType", - "type": "CompoundType", - "tags": [], - "label": "xScaleType", - "description": [], - "signature": [ - "\"time\" | \"linear\" | \"ordinal\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.isHistogram", - "type": "boolean", - "tags": [], - "label": "isHistogram", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.isStacked", - "type": "boolean", - "tags": [], - "label": "isStacked", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "RecursivePartial", + "> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.colorMapping", - "type": "string", - "tags": [], - "label": "colorMapping", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.decorations", - "type": "Array", - "tags": [], - "label": "decorations", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.DataDecorationConfigResult", - "text": "DataDecorationConfigResult" - }, - "[] | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.DataLayerArgs.curveType", - "type": "CompoundType", - "tags": [], - "label": "curveType", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XYCurveType", - "text": "XYCurveType" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI", - "type": "Interface", - "tags": [], - "label": "DatasourcePublicAPI", - "description": [ - "\nThis is an API provided to visualizations by the frame, which calls the publicAPI on the datasource" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.datasourceId", - "type": "string", - "tags": [], - "label": "datasourceId", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.datasourceAliasIds", - "type": "Array", - "tags": [], - "label": "datasourceAliasIds", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getTableSpec", - "type": "Function", - "tags": [], - "label": "getTableSpec", - "description": [], - "signature": [ - "() => { columnId: string; fields: string[]; }[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getOperationForColumnId", - "type": "Function", - "tags": [], - "label": "getOperationForColumnId", - "description": [], - "signature": [ - "(columnId: string) => ", - "OperationDescriptor", - " | null" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getOperationForColumnId.$1", - "type": "string", - "tags": [], - "label": "columnId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getVisualDefaults", - "type": "Function", - "tags": [], - "label": "getVisualDefaults", - "description": [ - "\nCollect all default visual values given the current state" - ], - "signature": [ - "() => Record>" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getSourceId", - "type": "Function", - "tags": [], - "label": "getSourceId", - "description": [ - "\nRetrieve the specific source id for the current state" - ], - "signature": [ - "() => string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record boolean" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getFilters", - "type": "Function", - "tags": [], - "label": "getFilters", - "description": [ - "\nCollect all defined filters from all the operations in the layer. If it returns undefined, this means that filters can't be constructed for the current layer" - ], - "signature": [ - "(activeData?: Record | undefined, timeRange?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.TimeRange", - "text": "TimeRange" - }, - " | undefined) => { error: string; } | Record<\"disabled\" | \"enabled\", { kuery: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Query", - "text": "Query" - }, - "[][]; lucene: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Query", - "text": "Query" - }, - "[][]; }>" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getFilters.$1", - "type": "Object", - "tags": [], - "label": "activeData", - "description": [], - "signature": [ - "Record | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getFilters.$2", - "type": "Object", - "tags": [], - "label": "timeRange", - "description": [], - "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.TimeRange", - "text": "TimeRange" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getMaxPossibleNumValues", - "type": "Function", - "tags": [], - "label": "getMaxPossibleNumValues", - "description": [ - "\nReturns the maximum possible number of values for this column when it can be known, otherwise null\n(e.g. with a top 5 values operation, we can be sure that there will never be more than 5 values returned\n or 6 if the \"Other\" bucket is enabled)" - ], - "signature": [ - "(columnId: string) => number | null" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.getMaxPossibleNumValues.$1", - "type": "string", - "tags": [], - "label": "columnId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; getByValueState: () => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "parentPluginId": "lens", - "id": "def-public.DatasourcePublicAPI.hasDefaultTimeField", - "type": "Function", - "tags": [], - "label": "hasDefaultTimeField", - "description": [], - "signature": [ - "() => boolean" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState", - "type": "Interface", - "tags": [], - "label": "DatatableVisualizationState", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState.columns", - "type": "Array", - "tags": [], - "label": "columns", - "description": [], - "signature": [ - "ColumnState", - "[]" - ], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState.layerType", - "type": "CompoundType", - "tags": [], - "label": "layerType", - "description": [], - "signature": [ - "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" - ], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState.sorting", - "type": "Object", - "tags": [], - "label": "sorting", - "description": [], - "signature": [ - "SortingState", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState.rowHeight", - "type": "CompoundType", - "tags": [], - "label": "rowHeight", - "description": [], - "signature": [ - "RowHeightMode", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.DatatableVisualizationState.rowHeightLines", - "type": "number", - "tags": [], - "label": "rowHeightLines", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DateHistogramIndexPatternColumn", - "text": "DateHistogramIndexPatternColumn" + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, - " extends ", + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/date_histogram.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.DateHistogramIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"date_histogram\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/date_histogram.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" }, + " | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.DateHistogramIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ interval: string; ignoreTimeRange?: boolean | undefined; includeEmptyRows?: boolean | undefined; dropPartials?: boolean | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/date_histogram.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FieldBasedIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "FieldBasedIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", { - "pluginId": "lens", + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, - " extends ", - "BaseIndexPatternColumn" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.FieldBasedIndexPatternColumn.sourceField", - "type": "string", - "tags": [], - "label": "sourceField", - "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FiltersIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "FiltersIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FiltersIndexPatternColumn", - "text": "FiltersIndexPatternColumn" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - " extends ", - "BaseIndexPatternColumn" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filters.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.FiltersIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"filters\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filters.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.columnOrder", - "type": "Array", - "tags": [], - "label": "columnOrder", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.columns", - "type": "Object", - "tags": [], - "label": "columns", - "description": [], - "signature": [ - "{ [x: string]: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GenericIndexPatternColumn", - "text": "GenericIndexPatternColumn" - }, - "; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; viewMode: ", { - "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.indexPatternId", - "type": "string", - "tags": [], - "label": "indexPatternId", - "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.linkToLayers", - "type": "Array", - "tags": [], - "label": "linkToLayers", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + ">; savedObjectId: ", { - "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.incompleteColumns", - "type": "Object", - "tags": [], - "label": "incompleteColumns", - "description": [], - "signature": [ - "Record | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; getInspectorAdapters: () => ", { - "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.sampling", - "type": "number", - "tags": [], - "label": "sampling", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + "; inspect: (options?: ", + { + "pluginId": "inspector", + "scope": "public", + "docId": "kibInspectorPluginApi", + "section": "def-public.InspectorOptions", + "text": "InspectorOptions" + }, + " | undefined) => ", + { + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.OverlayRef", + "text": "OverlayRef" + }, + "; closeInspector: () => Promise; adapters$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + ">; abortController?: AbortController | undefined; canViewUnderlyingData$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; loadViewUnderlyingData: () => void; getViewUnderlyingDataArgs: () => ", + "ViewUnderlyingDataArgs", + " | undefined; isTextBasedLanguage: () => boolean | undefined; getTextBasedLanguage: () => string | undefined; getSavedVis: () => Readonly<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensSavedObjectAttributes", + "text": "LensSavedObjectAttributes" + }, + " | undefined>; getFullAttributes: () => ", + "LensDocument", + " | undefined; updateAttributes: (newAttributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }) => void; updateSavedObjectId: (newSavedObjectId: string | undefined) => void; updateOverrides: (newOverrides: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined) => void; getTriggerCompatibleActions: (triggerId: string, context: object) => Promise<", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" }, + "[]>; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/type_guards.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "lens", - "id": "def-public.FormBasedLayer.ignoreGlobalFilters", - "type": "CompoundType", + "id": "def-public.isLensApi.$1", + "type": "Unknown", "tags": [], - "label": "ignoreGlobalFilters", + "label": "api", "description": [], "signature": [ - "boolean | undefined" + "unknown" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "path": "x-pack/plugins/lens/public/react_embeddable/type_guards.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "isRequired": true } ], + "returnComment": [], "initialIsOpen": false - }, + } + ], + "interfaces": [ { "parentPluginId": "lens", - "id": "def-public.FormBasedPersistedState", + "id": "def-public.AxesSettingsConfig", "type": "Interface", "tags": [], - "label": "FormBasedPersistedState", + "label": "AxesSettingsConfig", "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.FormBasedPersistedState.layers", - "type": "Object", + "id": "def-public.AxesSettingsConfig.yLeft", + "type": "boolean", "tags": [], - "label": "layers", + "label": "yLeft", "description": [], - "signature": [ - "{ [x: string]: Omit<", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FormBasedLayer", - "text": "FormBasedLayer" - }, - ", \"indexPatternId\">; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxesSettingsConfig.yRight", + "type": "boolean", + "tags": [], + "label": "yRight", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false } @@ -2584,51 +1500,202 @@ }, { "parentPluginId": "lens", - "id": "def-public.FormulaIndexPatternColumn", + "id": "def-public.AxisConfig", "type": "Interface", "tags": [], - "label": "FormulaIndexPatternColumn", + "label": "AxisConfig", "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FormulaIndexPatternColumn", - "text": "FormulaIndexPatternColumn" - }, - " extends ", - "ReferenceBasedIndexPatternColumn" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula.tsx", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.FormulaIndexPatternColumn.operationType", + "id": "def-public.AxisConfig.title", "type": "string", "tags": [], - "label": "operationType", + "label": "title", "description": [], "signature": [ - "\"formula\"" + "string | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula.tsx", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.FormulaIndexPatternColumn.params", - "type": "Object", + "id": "def-public.AxisConfig.hide", + "type": "CompoundType", "tags": [], - "label": "params", + "label": "hide", "description": [], "signature": [ - "{ formula?: string | undefined; isFormulaBroken?: boolean | undefined; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; }" + "boolean | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula.tsx", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.position", + "type": "CompoundType", + "tags": [], + "label": "position", + "description": [], + "signature": [ + "Position", + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.labelColor", + "type": "string", + "tags": [], + "label": "labelColor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.showOverlappingLabels", + "type": "CompoundType", + "tags": [], + "label": "showOverlappingLabels", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.showDuplicates", + "type": "CompoundType", + "tags": [], + "label": "showDuplicates", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.labelsOrientation", + "type": "number", + "tags": [], + "label": "labelsOrientation", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.truncate", + "type": "number", + "tags": [], + "label": "truncate", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.showLabels", + "type": "CompoundType", + "tags": [], + "label": "showLabels", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.showTitle", + "type": "CompoundType", + "tags": [], + "label": "showTitle", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.showGridLines", + "type": "CompoundType", + "tags": [], + "label": "showGridLines", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisConfig.extent", + "type": "CompoundType", + "tags": [], + "label": "extent", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.AxisExtentConfigResult", + "text": "AxisExtentConfigResult" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false } @@ -2637,290 +1704,82 @@ }, { "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi", + "id": "def-public.AxisExtentConfig", "type": "Interface", "tags": [], - "label": "FormulaPublicApi", + "label": "AxisExtentConfig", "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn", - "type": "Function", + "id": "def-public.AxisExtentConfig.mode", + "type": "CompoundType", "tags": [], - "label": "insertOrReplaceFormulaColumn", - "description": [ - "\nMethod which Lens consumer can import and given a formula string,\nreturn a parsed result as list of columns to use as Embeddable attributes.\n" + "label": "mode", + "description": [], + "signature": [ + "\"custom\" | \"full\" | \"dataBounds\"" ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisExtentConfig.lowerBound", + "type": "number", + "tags": [], + "label": "lowerBound", + "description": [], "signature": [ - "(id: string, column: { formula: string; label?: string | undefined; filter?: ", - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Query", - "text": "Query" - }, - " | undefined; reducedTimeRange?: string | undefined; timeScale?: ", - "TimeScaleUnit", - " | undefined; format?: { id: string; params?: { decimals: number; compact?: boolean | undefined; } | undefined; } | undefined; }, layer: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.PersistedIndexPatternLayer", - "text": "PersistedIndexPatternLayer" - }, - ", dataView: ", - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataView", - "text": "DataView" - }, - ", dateRange?: ", - "DateRange", - " | undefined) => ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.PersistedIndexPatternLayer", - "text": "PersistedIndexPatternLayer" - }, - " | undefined" + "number | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$1", - "type": "string", - "tags": [], - "label": "id", - "description": [ - "- Formula column id" - ], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2", - "type": "Object", - "tags": [], - "label": "column", - "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.formula", - "type": "string", - "tags": [], - "label": "formula", - "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.label", - "type": "string", - "tags": [], - "label": "label", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.filter", - "type": "Object", - "tags": [], - "label": "filter", - "description": [], - "signature": [ - { - "pluginId": "@kbn/es-query", - "scope": "common", - "docId": "kibKbnEsQueryPluginApi", - "section": "def-common.Query", - "text": "Query" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.reducedTimeRange", - "type": "string", - "tags": [], - "label": "reducedTimeRange", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.timeScale", - "type": "CompoundType", - "tags": [], - "label": "timeScale", - "description": [], - "signature": [ - "TimeScaleUnit", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.format", - "type": "Object", - "tags": [], - "label": "format", - "description": [], - "signature": [ - "{ id: string; params?: { decimals: number; compact?: boolean | undefined; } | undefined; } | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false - } - ] - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$3", - "type": "Object", - "tags": [], - "label": "layer", - "description": [ - "- The layer to which the formula columns will be added" - ], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.PersistedIndexPatternLayer", - "text": "PersistedIndexPatternLayer" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$4", - "type": "Object", - "tags": [], - "label": "dataView", - "description": [ - "- The dataView instance\n\nSee `x-pack/examples/embedded_lens_example` for exemplary usage." - ], - "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataView", - "text": "DataView" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$5", - "type": "Object", - "tags": [], - "label": "dateRange", - "description": [], - "signature": [ - "DateRange", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.IncompleteColumn", - "type": "Interface", - "tags": [], - "label": "IncompleteColumn", - "description": [], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "trackAdoption": false + }, { "parentPluginId": "lens", - "id": "def-public.IncompleteColumn.operationType", - "type": "string", + "id": "def-public.AxisExtentConfig.upperBound", + "type": "number", "tags": [], - "label": "operationType", + "label": "upperBound", "description": [], "signature": [ - "string | undefined" + "number | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.IncompleteColumn.sourceField", - "type": "string", + "id": "def-public.AxisExtentConfig.enforce", + "type": "CompoundType", "tags": [], - "label": "sourceField", + "label": "enforce", "description": [], "signature": [ - "string | undefined" + "boolean | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisExtentConfig.niceValues", + "type": "CompoundType", + "tags": [], + "label": "niceValues", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false } @@ -2929,539 +1788,412 @@ }, { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext", + "id": "def-public.CardinalityIndexPatternColumn", "type": "Interface", "tags": [], - "label": "InlineEditLensEmbeddableContext", + "label": "CardinalityIndexPatternColumn", "description": [], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.CardinalityIndexPatternColumn", + "text": "CardinalityIndexPatternColumn" + }, + " extends ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/cardinality.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.attributes", - "type": "CompoundType", + "id": "def-public.CardinalityIndexPatternColumn.operationType", + "type": "string", "tags": [], - "label": "attributes", + "label": "operationType", "description": [], "signature": [ - "LensAttributes<\"lnsXY\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" - }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" - }, - "> | LensAttributes<\"lnsGauge\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" - }, - "> | LensAttributes<\"lnsDatatable\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" - }, - "> | LensAttributes<\"lnsLegacyMetric\", ", - { - "pluginId": "lens", - "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" - }, - "> | LensAttributes<\"lnsMetric\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" - }, - "> | LensAttributes" + "\"unique_count\"" ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/cardinality.tsx", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.lensEvent", + "id": "def-public.CardinalityIndexPatternColumn.params", "type": "Object", "tags": [], - "label": "lensEvent", + "label": "params", "description": [], "signature": [ - "LensChartLoadEvent" + "{ emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined" ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/cardinality.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ChartInfo", + "type": "Interface", + "tags": [], + "label": "ChartInfo", + "description": [], + "path": "x-pack/plugins/lens/public/chart_info_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.ChartInfo.layers", + "type": "Array", + "tags": [], + "label": "layers", + "description": [], + "signature": [ + "ChartLayerDescriptor", + "[]" + ], + "path": "x-pack/plugins/lens/public/chart_info_api.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.onUpdate", - "type": "Function", + "id": "def-public.ChartInfo.visualizationType", + "type": "string", "tags": [], - "label": "onUpdate", + "label": "visualizationType", + "description": [], + "path": "x-pack/plugins/lens/public/chart_info_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ChartInfo.filters", + "type": "Array", + "tags": [], + "label": "filters", "description": [], "signature": [ - "(newAttributes: LensAttributes<\"lnsXY\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" - }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" - }, - "> | LensAttributes<\"lnsGauge\", ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, - "> | LensAttributes<\"lnsDatatable\", ", + "[]" + ], + "path": "x-pack/plugins/lens/public/chart_info_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ChartInfo.query", + "type": "CompoundType", + "tags": [], + "label": "query", + "description": [], + "signature": [ { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + " | ", { - "pluginId": "lens", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" - }, - "> | LensAttributes<\"lnsMetric\", ", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + } + ], + "path": "x-pack/plugins/lens/public/chart_info_api.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs", + "type": "Interface", + "tags": [], + "label": "DataLayerArgs", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.accessors", + "type": "Array", + "tags": [], + "label": "accessors", + "description": [], + "signature": [ + "(string | ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.ExpressionValueVisDimension", + "text": "ExpressionValueVisDimension" }, - "> | LensAttributes) => void" + ")[]" ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.onUpdate.$1", - "type": "CompoundType", - "tags": [], - "label": "newAttributes", - "description": [], - "signature": [ - "LensAttributes<\"lnsXY\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" - }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" - }, - "> | LensAttributes<\"lnsGauge\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" - }, - "> | LensAttributes<\"lnsDatatable\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" - }, - "> | LensAttributes<\"lnsLegacyMetric\", ", - { - "pluginId": "lens", - "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" - }, - "> | LensAttributes<\"lnsMetric\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" - }, - "> | LensAttributes" - ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.onApply", - "type": "Function", + "id": "def-public.DataLayerArgs.seriesType", + "type": "CompoundType", "tags": [], - "label": "onApply", + "label": "seriesType", "description": [], "signature": [ - "((newAttributes: LensAttributes<\"lnsXY\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" - }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" - }, - "> | LensAttributes<\"lnsGauge\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" - }, - "> | LensAttributes<\"lnsDatatable\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" - }, - "> | LensAttributes<\"lnsLegacyMetric\", ", - { - "pluginId": "lens", - "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" - }, - "> | LensAttributes<\"lnsMetric\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" - }, - "> | LensAttributes) => void) | undefined" + "\"area\" | \"line\" | \"bar\"" ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.onApply.$1", - "type": "CompoundType", - "tags": [], - "label": "newAttributes", - "description": [], - "signature": [ - "LensAttributes<\"lnsXY\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" - }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" - }, - "> | LensAttributes<\"lnsGauge\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" - }, - "> | LensAttributes<\"lnsDatatable\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" - }, - "> | LensAttributes<\"lnsLegacyMetric\", ", - { - "pluginId": "lens", - "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" - }, - "> | LensAttributes<\"lnsMetric\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" - }, - "> | LensAttributes" - ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.onCancel", - "type": "Function", + "id": "def-public.DataLayerArgs.xAccessor", + "type": "CompoundType", "tags": [], - "label": "onCancel", + "label": "xAccessor", "description": [], "signature": [ - "(() => void) | undefined" + "string | ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.ExpressionValueVisDimension", + "text": "ExpressionValueVisDimension" + }, + " | undefined" ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.InlineEditLensEmbeddableContext.container", + "id": "def-public.DataLayerArgs.simpleView", "type": "CompoundType", "tags": [], - "label": "container", + "label": "simpleView", "description": [], "signature": [ - "HTMLElement | null | undefined" + "boolean | undefined" ], - "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LastValueIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "LastValueIndexPatternColumn", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LastValueIndexPatternColumn", - "text": "LastValueIndexPatternColumn" }, - " extends ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ { "parentPluginId": "lens", - "id": "def-public.LastValueIndexPatternColumn.operationType", - "type": "string", + "id": "def-public.DataLayerArgs.splitAccessors", + "type": "Array", "tags": [], - "label": "operationType", + "label": "splitAccessors", "description": [], "signature": [ - "\"last_value\"" + "(string | ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.ExpressionValueVisDimension", + "text": "ExpressionValueVisDimension" + }, + ")[] | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LastValueIndexPatternColumn.params", - "type": "Object", + "id": "def-public.DataLayerArgs.markSizeAccessor", + "type": "CompoundType", "tags": [], - "label": "params", + "label": "markSizeAccessor", "description": [], "signature": [ - "{ sortField: string; showArrayValues: boolean; format?: ", - "ValueFormatConfig", - " | undefined; }" + "string | ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.ExpressionValueVisDimension", + "text": "ExpressionValueVisDimension" + }, + " | undefined" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LegacyMetricState", - "type": "Interface", - "tags": [], - "label": "LegacyMetricState", - "description": [], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.autoScaleMetricAlignment", + "id": "def-public.DataLayerArgs.lineWidth", + "type": "number", + "tags": [], + "label": "lineWidth", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.showPoints", "type": "CompoundType", "tags": [], - "label": "autoScaleMetricAlignment", + "label": "showPoints", "description": [], "signature": [ - "\"right\" | \"center\" | \"left\" | undefined" + "boolean | undefined" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.layerId", - "type": "string", + "id": "def-public.DataLayerArgs.showLines", + "type": "CompoundType", "tags": [], - "label": "layerId", + "label": "showLines", "description": [], - "path": "x-pack/plugins/lens/common/types.ts", + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.accessor", - "type": "string", + "id": "def-public.DataLayerArgs.pointsRadius", + "type": "number", "tags": [], - "label": "accessor", + "label": "pointsRadius", "description": [], "signature": [ - "string | undefined" + "number | undefined" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.layerType", - "type": "CompoundType", + "id": "def-public.DataLayerArgs.columnToLabel", + "type": "string", "tags": [], - "label": "layerType", + "label": "columnToLabel", "description": [], "signature": [ - "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + "string | undefined" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.colorMode", + "id": "def-public.DataLayerArgs.xScaleType", "type": "CompoundType", "tags": [], - "label": "colorMode", + "label": "xScaleType", "description": [], "signature": [ - { - "pluginId": "charts", - "scope": "common", - "docId": "kibChartsPluginApi", - "section": "def-common.ColorMode", - "text": "ColorMode" - }, - " | undefined" + "\"time\" | \"linear\" | \"ordinal\"" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.palette", + "id": "def-public.DataLayerArgs.isHistogram", + "type": "boolean", + "tags": [], + "label": "isHistogram", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.isPercentage", + "type": "boolean", + "tags": [], + "label": "isPercentage", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.isStacked", + "type": "boolean", + "tags": [], + "label": "isStacked", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.isHorizontal", + "type": "boolean", + "tags": [], + "label": "isHorizontal", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerArgs.palette", "type": "Object", "tags": [], "label": "palette", @@ -3474,59 +2206,65 @@ "section": "def-common.PaletteOutput", "text": "PaletteOutput" }, - "<", - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.CustomPaletteParams", - "text": "CustomPaletteParams" - }, - "> | undefined" + "<{ [key: string]: unknown; }>" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.titlePosition", - "type": "CompoundType", + "id": "def-public.DataLayerArgs.colorMapping", + "type": "string", "tags": [], - "label": "titlePosition", + "label": "colorMapping", "description": [], "signature": [ - "\"top\" | \"bottom\" | undefined" + "string | undefined" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.size", - "type": "string", + "id": "def-public.DataLayerArgs.decorations", + "type": "Array", "tags": [], - "label": "size", + "label": "decorations", "description": [], "signature": [ - "string | undefined" + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.DataDecorationConfigResult", + "text": "DataDecorationConfigResult" + }, + "[] | undefined" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegacyMetricState.textAlign", + "id": "def-public.DataLayerArgs.curveType", "type": "CompoundType", "tags": [], - "label": "textAlign", + "label": "curveType", "description": [], "signature": [ - "\"right\" | \"center\" | \"left\" | undefined" + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XYCurveType", + "text": "XYCurveType" + }, + " | undefined" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false } @@ -3535,248 +2273,431 @@ }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig", + "id": "def-public.DatasourcePublicAPI", "type": "Interface", "tags": [], - "label": "LegendConfig", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "label": "DatasourcePublicAPI", + "description": [ + "\nThis is an API provided to visualizations by the frame, which calls the publicAPI on the datasource" + ], + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.LegendConfig.isVisible", - "type": "boolean", + "id": "def-public.DatasourcePublicAPI.datasourceId", + "type": "string", "tags": [], - "label": "isVisible", - "description": [ - "\nFlag whether the legend should be shown. If there is just a single series, it will be hidden" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "label": "datasourceId", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.position", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.datasourceAliasIds", + "type": "Array", "tags": [], - "label": "position", - "description": [ - "\nPosition of the legend relative to the chart" - ], + "label": "datasourceAliasIds", + "description": [], "signature": [ - "\"right\" | \"top\" | \"bottom\" | \"left\"" + "string[] | undefined" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.showSingleSeries", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.getTableSpec", + "type": "Function", "tags": [], - "label": "showSingleSeries", - "description": [ - "\nFlag whether the legend should be shown even with just a single series" - ], + "label": "getTableSpec", + "description": [], "signature": [ - "boolean | undefined" + "() => { columnId: string; fields: string[]; }[]" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.isInside", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.getOperationForColumnId", + "type": "Function", "tags": [], - "label": "isInside", - "description": [ - "\nFlag whether the legend is inside the chart" - ], + "label": "getOperationForColumnId", + "description": [], "signature": [ - "boolean | undefined" + "(columnId: string) => ", + "OperationDescriptor", + " | null" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.DatasourcePublicAPI.getOperationForColumnId.$1", + "type": "string", + "tags": [], + "label": "columnId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.horizontalAlignment", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.getVisualDefaults", + "type": "Function", "tags": [], - "label": "horizontalAlignment", + "label": "getVisualDefaults", "description": [ - "\nHorizontal Alignment of the legend when it is set inside chart" + "\nCollect all default visual values given the current state" ], "signature": [ - "\"right\" | \"left\" | undefined" + "() => Record>" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.verticalAlignment", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.getSourceId", + "type": "Function", "tags": [], - "label": "verticalAlignment", + "label": "getSourceId", "description": [ - "\nVertical Alignment of the legend when it is set inside chart" + "\nRetrieve the specific source id for the current state" ], "signature": [ - "\"top\" | \"bottom\" | undefined" + "() => string | undefined" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.floatingColumns", - "type": "number", + "id": "def-public.DatasourcePublicAPI.isTextBasedLanguage", + "type": "Function", "tags": [], - "label": "floatingColumns", + "label": "isTextBasedLanguage", "description": [ - "\nNumber of columns when legend is set inside chart" + "\nReturns true if this is a text based language datasource" ], "signature": [ - "number | undefined" + "() => boolean" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.maxLines", - "type": "number", + "id": "def-public.DatasourcePublicAPI.getFilters", + "type": "Function", "tags": [], - "label": "maxLines", + "label": "getFilters", "description": [ - "\nMaximum number of lines per legend item" + "\nCollect all defined filters from all the operations in the layer. If it returns undefined, this means that filters can't be constructed for the current layer" ], "signature": [ - "number | undefined" + "(activeData?: Record | undefined, timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined) => { error: string; } | Record<\"disabled\" | \"enabled\", { kuery: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + "[][]; lucene: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + "[][]; }>" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.DatasourcePublicAPI.getFilters.$1", + "type": "Object", + "tags": [], + "label": "activeData", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatasourcePublicAPI.getFilters.$2", + "type": "Object", + "tags": [], + "label": "timeRange", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.shouldTruncate", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.getMaxPossibleNumValues", + "type": "Function", "tags": [], - "label": "shouldTruncate", + "label": "getMaxPossibleNumValues", "description": [ - "\nFlag whether the legend items are truncated or not" + "\nReturns the maximum possible number of values for this column when it can be known, otherwise null\n(e.g. with a top 5 values operation, we can be sure that there will never be more than 5 values returned\n or 6 if the \"Other\" bucket is enabled)" ], "signature": [ - "boolean | undefined" + "(columnId: string) => number | null" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.DatasourcePublicAPI.getMaxPossibleNumValues.$1", + "type": "string", + "tags": [], + "label": "columnId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.legendSize", - "type": "CompoundType", + "id": "def-public.DatasourcePublicAPI.hasDefaultTimeField", + "type": "Function", "tags": [], - "label": "legendSize", - "description": [ - "\nExact legend width (vertical) or height (horizontal)\nLimited to max of 70% of the chart container dimension Vertical legends limited to min of 30% of computed width" - ], + "label": "hasDefaultTimeField", + "description": [], "signature": [ - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.LegendSize", - "text": "LegendSize" - }, - " | undefined" + "() => boolean" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/types.ts", "deprecated": false, - "trackAdoption": false - }, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatatableVisualizationState", + "type": "Interface", + "tags": [], + "label": "DatatableVisualizationState", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "lens", - "id": "def-public.LegendConfig.legendStats", + "id": "def-public.DatatableVisualizationState.columns", "type": "Array", "tags": [], - "label": "legendStats", - "description": [ - "\nmetrics to display in the legend" - ], + "label": "columns", + "description": [], "signature": [ - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.XYLegendValue", - "text": "XYLegendValue" - }, - "[] | undefined" + "ColumnState", + "[]" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.layout", + "id": "def-public.DatatableVisualizationState.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatatableVisualizationState.layerType", "type": "CompoundType", "tags": [], - "label": "layout", + "label": "layerType", "description": [], "signature": [ - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.LegendLayout", - "text": "LegendLayout" - }, + "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatatableVisualizationState.sorting", + "type": "Object", + "tags": [], + "label": "sorting", + "description": [], + "signature": [ + "SortingState", " | undefined" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.title", - "type": "string", + "id": "def-public.DatatableVisualizationState.rowHeight", + "type": "CompoundType", "tags": [], - "label": "title", + "label": "rowHeight", "description": [], "signature": [ - "string | undefined" + "RowHeightMode", + " | undefined" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LegendConfig.isTitleVisible", + "id": "def-public.DatatableVisualizationState.headerRowHeight", "type": "CompoundType", "tags": [], - "label": "isTitleVisible", + "label": "headerRowHeight", "description": [], "signature": [ - "boolean | undefined" + "RowHeightMode", + " | undefined" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatatableVisualizationState.rowHeightLines", + "type": "number", + "tags": [], + "label": "rowHeightLines", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatatableVisualizationState.headerRowHeightLines", + "type": "number", + "tags": [], + "label": "headerRowHeightLines", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DatatableVisualizationState.paging", + "type": "Object", + "tags": [], + "label": "paging", + "description": [], + "signature": [ + "PagingState", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/datatable/visualization.tsx", "deprecated": false, "trackAdoption": false } @@ -3785,50 +2706,57 @@ }, { "parentPluginId": "lens", - "id": "def-public.LensEmbeddableOutput", + "id": "def-public.DateHistogramIndexPatternColumn", "type": "Interface", "tags": [], - "label": "LensEmbeddableOutput", + "label": "DateHistogramIndexPatternColumn", "description": [], "signature": [ { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableOutput", - "text": "LensEmbeddableOutput" + "section": "def-public.DateHistogramIndexPatternColumn", + "text": "DateHistogramIndexPatternColumn" }, " extends ", { - "pluginId": "embeddable", + "pluginId": "lens", "scope": "public", - "docId": "kibEmbeddablePluginApi", - "section": "def-public.EmbeddableOutput", - "text": "EmbeddableOutput" + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" } ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/date_histogram.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.LensEmbeddableOutput.indexPatterns", - "type": "Array", + "id": "def-public.DateHistogramIndexPatternColumn.operationType", + "type": "string", "tags": [], - "label": "indexPatterns", + "label": "operationType", "description": [], "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataView", - "text": "DataView" - }, - "[] | undefined" + "\"date_histogram\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/date_histogram.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DateHistogramIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ interval: string; ignoreTimeRange?: boolean | undefined; includeEmptyRows?: boolean | undefined; dropPartials?: boolean | undefined; }" ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/date_histogram.tsx", "deprecated": false, "trackAdoption": false } @@ -3837,460 +2765,303 @@ }, { "parentPluginId": "lens", - "id": "def-public.LensPublicSetup", + "id": "def-public.FieldBasedIndexPatternColumn", "type": "Interface", "tags": [], - "label": "LensPublicSetup", + "label": "FieldBasedIndexPatternColumn", "description": [], - "path": "x-pack/plugins/lens/public/plugin.ts", + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " extends ", + "BaseIndexPatternColumn" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.LensPublicSetup.registerVisualization", - "type": "Function", - "tags": [ - "experimental" - ], - "label": "registerVisualization", - "description": [ - "\nRegister 3rd party visualization type\nSee `x-pack/examples/3rd_party_lens_vis` for exemplary usage.\n\nIn case the visualization is a function returning a promise, it will only be called once Lens is actually requiring it.\nThis can be used to lazy-load parts of the code to keep the initial bundle as small as possible.\n\nThis API might undergo breaking changes even in minor versions.\n" + "id": "def-public.FieldBasedIndexPatternColumn.sourceField", + "type": "string", + "tags": [], + "label": "sourceField", + "description": [], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FiltersIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "FiltersIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FiltersIndexPatternColumn", + "text": "FiltersIndexPatternColumn" + }, + " extends ", + "BaseIndexPatternColumn" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filters.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.FiltersIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"filters\"" ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filters.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FiltersIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], "signature": [ - "(visualization: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Visualization", - "text": "Visualization" - }, - " | (() => Promise<", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Visualization", - "text": "Visualization" - }, - ">)) => void" + "{ filters: ", + "Filter", + "[]; }" ], - "path": "x-pack/plugins/lens/public/plugin.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/filters/filters.tsx", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.LensPublicSetup.registerVisualization.$1", - "type": "CompoundType", - "tags": [], - "label": "visualization", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Visualization", - "text": "Visualization" - }, - " | (() => Promise<", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Visualization", - "text": "Visualization" - }, - ">)" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicSetup.registerTopNavMenuEntryGenerator", - "type": "Function", - "tags": [ - "experimental" - ], - "label": "registerTopNavMenuEntryGenerator", - "description": [ - "\nRegister a generic menu entry shown in the top nav\nSee `x-pack/examples/3rd_party_lens_navigation_prompt` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" - ], - "signature": [ - "(navigationPromptGenerator: ", - "LensTopNavMenuEntryGenerator", - ") => void" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.LensPublicSetup.registerTopNavMenuEntryGenerator.$1", - "type": "Function", - "tags": [], - "label": "navigationPromptGenerator", - "description": [], - "signature": [ - "LensTopNavMenuEntryGenerator" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "trackAdoption": false } ], "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.LensPublicStart", + "id": "def-public.FormBasedLayer", "type": "Interface", "tags": [], - "label": "LensPublicStart", + "label": "FormBasedLayer", "description": [], - "path": "x-pack/plugins/lens/public/plugin.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.LensPublicStart.EmbeddableComponent", - "type": "CompoundType", - "tags": [ - "experimental" - ], - "label": "EmbeddableComponent", - "description": [ - "\nReact component which can be used to embed a Lens visualization into another application.\nSee `x-pack/examples/embedded_lens_example` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" + "id": "def-public.FormBasedLayer.columnOrder", + "type": "Array", + "tags": [], + "label": "columnOrder", + "description": [], + "signature": [ + "string[]" ], + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormBasedLayer.columns", + "type": "Object", + "tags": [], + "label": "columns", + "description": [], "signature": [ - "React.ComponentClass<", + "{ [x: string]: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.EmbeddableComponentProps", - "text": "EmbeddableComponentProps" + "section": "def-public.GenericIndexPatternColumn", + "text": "GenericIndexPatternColumn" }, - ", any> | React.FunctionComponent<", + "; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormBasedLayer.indexPatternId", + "type": "string", + "tags": [], + "label": "indexPatternId", + "description": [], + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormBasedLayer.linkToLayers", + "type": "Array", + "tags": [], + "label": "linkToLayers", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormBasedLayer.incompleteColumns", + "type": "Object", + "tags": [], + "label": "incompleteColumns", + "description": [], + "signature": [ + "Record" + " | undefined> | undefined" ], - "path": "x-pack/plugins/lens/public/plugin.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LensPublicStart.SaveModalComponent", - "type": "CompoundType", - "tags": [ - "experimental" - ], - "label": "SaveModalComponent", - "description": [ - "\nReact component which can be used to embed a Lens Visualization Save Modal Component.\nSee `x-pack/examples/embedded_lens_example` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" - ], + "id": "def-public.FormBasedLayer.sampling", + "type": "number", + "tags": [], + "label": "sampling", + "description": [], "signature": [ - "React.ComponentClass, any> | React.FunctionComponent>" + "number | undefined" ], - "path": "x-pack/plugins/lens/public/plugin.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.LensPublicStart.EditLensConfigPanelApi", - "type": "Function", - "tags": [ - "experimental" - ], - "label": "EditLensConfigPanelApi", - "description": [ - "\nReact component which can be used to embed a Lens Visualization Config Panel Component.\n\nThis API might undergo breaking changes even in minor versions.\n" - ], + "id": "def-public.FormBasedLayer.ignoreGlobalFilters", + "type": "CompoundType", + "tags": [], + "label": "ignoreGlobalFilters", + "description": [], "signature": [ - "() => Promise<", - "EditLensConfigPanelComponent", - ">" + "boolean | undefined" ], - "path": "x-pack/plugins/lens/public/plugin.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormBasedPersistedState", + "type": "Interface", + "tags": [], + "label": "FormBasedPersistedState", + "description": [], + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor", - "type": "Function", - "tags": [ - "experimental" - ], - "label": "navigateToPrefilledEditor", - "description": [ - "\nMethod which navigates to the Lens editor, loading the state specified by the `input` parameter.\nSee `x-pack/examples/embedded_lens_example` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" - ], + "id": "def-public.FormBasedPersistedState.layers", + "type": "Object", + "tags": [], + "label": "layers", + "description": [], "signature": [ - "(input: ", + "{ [x: string]: Omit<", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableInput", - "text": "LensEmbeddableInput" + "section": "def-public.FormBasedLayer", + "text": "FormBasedLayer" }, - " | undefined, options?: { openInNewTab?: boolean | undefined; originatingApp?: string | undefined; originatingPath?: string | undefined; skipAppLeave?: boolean | undefined; } | undefined) => void" + ", \"indexPatternId\">; }" ], - "path": "x-pack/plugins/lens/public/plugin.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$1", - "type": "CompoundType", - "tags": [], - "label": "input", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableInput", - "text": "LensEmbeddableInput" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2", - "type": "Object", - "tags": [], - "label": "options", - "description": [], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.openInNewTab", - "type": "CompoundType", - "tags": [], - "label": "openInNewTab", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.originatingApp", - "type": "string", - "tags": [], - "label": "originatingApp", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.originatingPath", - "type": "string", - "tags": [], - "label": "originatingPath", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.skipAppLeave", - "type": "CompoundType", - "tags": [], - "label": "skipAppLeave", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.canUseEditor", - "type": "Function", - "tags": [], - "label": "canUseEditor", - "description": [ - "\nMethod which returns true if the user has permission to use Lens as defined by application capabilities." - ], - "signature": [ - "() => boolean" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.getXyVisTypes", - "type": "Function", - "tags": [], - "label": "getXyVisTypes", - "description": [ - "\nMethod which returns xy VisualizationTypes array keeping this async as to not impact page load bundle" - ], - "signature": [ - "() => Promise<", - "VisualizationType", - "[]>" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] - }, - { - "parentPluginId": "lens", - "id": "def-public.LensPublicStart.stateHelperApi", - "type": "Function", - "tags": [], - "label": "stateHelperApi", - "description": [ - "\nAPI which returns state helpers keeping this async as to not impact page load bundle" - ], - "signature": [ - "() => Promise<{ formula: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FormulaPublicApi", - "text": "FormulaPublicApi" - }, - "; chartInfo: ", - "ChartInfoApi", - "; suggestions: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSuggestionsApi", - "text": "LensSuggestionsApi" - }, - "; }>" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "trackAdoption": false } ], "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.MathIndexPatternColumn", + "id": "def-public.FormulaIndexPatternColumn", "type": "Interface", "tags": [], - "label": "MathIndexPatternColumn", + "label": "FormulaIndexPatternColumn", "description": [], "signature": [ { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.MathIndexPatternColumn", - "text": "MathIndexPatternColumn" + "section": "def-public.FormulaIndexPatternColumn", + "text": "FormulaIndexPatternColumn" }, " extends ", "ReferenceBasedIndexPatternColumn" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/math.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.MathIndexPatternColumn.operationType", + "id": "def-public.FormulaIndexPatternColumn.operationType", "type": "string", "tags": [], "label": "operationType", "description": [], "signature": [ - "\"math\"" + "\"formula\"" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/math.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula.tsx", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.MathIndexPatternColumn.params", + "id": "def-public.FormulaIndexPatternColumn.params", "type": "Object", "tags": [], "label": "params", "description": [], "signature": [ - "{ tinymathAst: string | ", - "TinymathAST", - "; format?: ", - "ValueFormatConfig", - " | undefined; }" + "{ formula?: string | undefined; isFormulaBroken?: boolean | undefined; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; }" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/math.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula.tsx", "deprecated": false, "trackAdoption": false } @@ -4299,6691 +3070,21119 @@ }, { "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState", + "id": "def-public.FormulaPublicApi", "type": "Interface", "tags": [], - "label": "MetricVisualizationState", + "label": "FormulaPublicApi", "description": [], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.layerType", - "type": "CompoundType", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn", + "type": "Function", "tags": [], - "label": "layerType", - "description": [], - "signature": [ - "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + "label": "insertOrReplaceFormulaColumn", + "description": [ + "\nMethod which Lens consumer can import and given a formula string,\nreturn a parsed result as list of columns to use as Embeddable attributes.\n" ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.metricAccessor", - "type": "string", - "tags": [], - "label": "metricAccessor", - "description": [], "signature": [ - "string | undefined" + "(id: string, column: { formula: string; label?: string | undefined; filter?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | undefined; reducedTimeRange?: string | undefined; timeScale?: ", + "TimeScaleUnit", + " | undefined; format?: { id: string; params?: { decimals: number; compact?: boolean | undefined; } | undefined; } | undefined; }, layer: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PersistedIndexPatternLayer", + "text": "PersistedIndexPatternLayer" + }, + ", dataView: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", dateRange?: ", + "DateRange", + " | undefined) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PersistedIndexPatternLayer", + "text": "PersistedIndexPatternLayer" + }, + " | undefined" ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.secondaryMetricAccessor", - "type": "string", - "tags": [], - "label": "secondaryMetricAccessor", - "description": [], - "signature": [ - "string | undefined" + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$1", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "- Formula column id" + ], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2", + "type": "Object", + "tags": [], + "label": "column", + "description": [], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.formula", + "type": "string", + "tags": [], + "label": "formula", + "description": [], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.filter", + "type": "Object", + "tags": [], + "label": "filter", + "description": [], + "signature": [ + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.reducedTimeRange", + "type": "string", + "tags": [], + "label": "reducedTimeRange", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.timeScale", + "type": "CompoundType", + "tags": [], + "label": "timeScale", + "description": [], + "signature": [ + "TimeScaleUnit", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$2.format", + "type": "Object", + "tags": [], + "label": "format", + "description": [], + "signature": [ + "{ id: string; params?: { decimals: number; compact?: boolean | undefined; } | undefined; } | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$3", + "type": "Object", + "tags": [], + "label": "layer", + "description": [ + "- The layer to which the formula columns will be added" + ], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PersistedIndexPatternLayer", + "text": "PersistedIndexPatternLayer" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$4", + "type": "Object", + "tags": [], + "label": "dataView", + "description": [ + "- The dataView instance\n\nSee `x-pack/examples/embedded_lens_example` for exemplary usage." + ], + "signature": [ + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.FormulaPublicApi.insertOrReplaceFormulaColumn.$5", + "type": "Object", + "tags": [], + "label": "dateRange", + "description": [], + "signature": [ + "DateRange", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/formula_public_api.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.IncompleteColumn", + "type": "Interface", + "tags": [], + "label": "IncompleteColumn", + "description": [], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.maxAccessor", + "id": "def-public.IncompleteColumn.operationType", "type": "string", "tags": [], - "label": "maxAccessor", + "label": "operationType", "description": [], "signature": [ "string | undefined" ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.breakdownByAccessor", + "id": "def-public.IncompleteColumn.sourceField", "type": "string", "tags": [], - "label": "breakdownByAccessor", + "label": "sourceField", "description": [], "signature": [ "string | undefined" ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", "deprecated": false, "trackAdoption": false - }, + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext", + "type": "Interface", + "tags": [], + "label": "InlineEditLensEmbeddableContext", + "description": [], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.collapseFn", + "id": "def-public.InlineEditLensEmbeddableContext.attributes", "type": "CompoundType", "tags": [], - "label": "collapseFn", - "description": [], - "signature": [ - "\"min\" | \"max\" | \"sum\" | \"avg\" | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.subtitle", - "type": "string", - "tags": [], - "label": "subtitle", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.secondaryPrefix", - "type": "string", - "tags": [], - "label": "secondaryPrefix", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.progressDirection", - "type": "CompoundType", - "tags": [], - "label": "progressDirection", - "description": [], - "signature": [ - "LayoutDirection", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.showBar", - "type": "CompoundType", - "tags": [], - "label": "showBar", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.titlesTextAlign", - "type": "CompoundType", - "tags": [], - "label": "titlesTextAlign", - "description": [], - "signature": [ - "\"right\" | \"center\" | \"left\" | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.valuesTextAlign", - "type": "CompoundType", - "tags": [], - "label": "valuesTextAlign", - "description": [], - "signature": [ - "\"right\" | \"center\" | \"left\" | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.iconAlign", - "type": "CompoundType", - "tags": [], - "label": "iconAlign", - "description": [], - "signature": [ - "\"right\" | \"left\" | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.valueFontMode", - "type": "CompoundType", - "tags": [], - "label": "valueFontMode", - "description": [], - "signature": [ - "ValueFontMode", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.icon", - "type": "string", - "tags": [], - "label": "icon", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.palette", - "type": "Object", - "tags": [], - "label": "palette", + "label": "attributes", "description": [], "signature": [ + "{ title: string; description?: string | undefined; references: ", { - "pluginId": "@kbn/coloring", + "pluginId": "@kbn/core-saved-objects-common", "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "<", + "[]; visualizationType: \"lnsXY\"; state: { query: ", { - "pluginId": "@kbn/coloring", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.CustomPaletteParams", - "text": "CustomPaletteParams" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - "> | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.maxCols", - "type": "number", - "tags": [], - "label": "maxCols", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.trendlineLayerId", - "type": "string", - "tags": [], - "label": "trendlineLayerId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.trendlineLayerType", - "type": "CompoundType", - "tags": [], - "label": "trendlineLayerType", - "description": [], - "signature": [ - "LayerType", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.trendlineTimeAccessor", - "type": "string", - "tags": [], - "label": "trendlineTimeAccessor", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.trendlineMetricAccessor", - "type": "string", - "tags": [], - "label": "trendlineMetricAccessor", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.trendlineSecondaryMetricAccessor", - "type": "string", - "tags": [], - "label": "trendlineSecondaryMetricAccessor", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MetricVisualizationState.trendlineBreakdownByAccessor", - "type": "string", - "tags": [], - "label": "trendlineBreakdownByAccessor", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.lensEvent", + "type": "Object", + "tags": [], + "label": "lensEvent", + "description": [], + "signature": [ + "LensChartLoadEvent" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.onUpdate", + "type": "Function", + "tags": [], + "label": "onUpdate", + "description": [], + "signature": [ + "(newAttributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }) => void" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.onUpdate.$1", + "type": "CompoundType", + "tags": [], + "label": "newAttributes", + "description": [], + "signature": [ + "{ title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.onApply", + "type": "Function", + "tags": [], + "label": "onApply", + "description": [], + "signature": [ + "((newAttributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }) => void) | undefined" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.onApply.$1", + "type": "CompoundType", + "tags": [], + "label": "newAttributes", + "description": [], + "signature": [ + "{ title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.onCancel", + "type": "Function", + "tags": [], + "label": "onCancel", + "description": [], + "signature": [ + "(() => void) | undefined" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.InlineEditLensEmbeddableContext.container", + "type": "CompoundType", + "tags": [], + "label": "container", + "description": [], + "signature": [ + "HTMLElement | null | undefined" + ], + "path": "x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LastValueIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "LastValueIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LastValueIndexPatternColumn", + "text": "LastValueIndexPatternColumn" + }, + " extends ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LastValueIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"last_value\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LastValueIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ sortField: string; showArrayValues: boolean; format?: ", + "ValueFormatConfig", + " | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/last_value.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState", + "type": "Interface", + "tags": [], + "label": "LegacyMetricState", + "description": [], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.autoScaleMetricAlignment", + "type": "CompoundType", + "tags": [], + "label": "autoScaleMetricAlignment", + "description": [], + "signature": [ + "\"right\" | \"center\" | \"left\" | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.accessor", + "type": "string", + "tags": [], + "label": "accessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.layerType", + "type": "CompoundType", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.colorMode", + "type": "CompoundType", + "tags": [], + "label": "colorMode", + "description": [], + "signature": [ + { + "pluginId": "charts", + "scope": "common", + "docId": "kibChartsPluginApi", + "section": "def-common.ColorMode", + "text": "ColorMode" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.palette", + "type": "Object", + "tags": [], + "label": "palette", + "description": [], + "signature": [ + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.CustomPaletteParams", + "text": "CustomPaletteParams" + }, + "> | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.titlePosition", + "type": "CompoundType", + "tags": [], + "label": "titlePosition", + "description": [], + "signature": [ + "\"top\" | \"bottom\" | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.size", + "type": "string", + "tags": [], + "label": "size", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegacyMetricState.textAlign", + "type": "CompoundType", + "tags": [], + "label": "textAlign", + "description": [], + "signature": [ + "\"right\" | \"center\" | \"left\" | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig", + "type": "Interface", + "tags": [], + "label": "LegendConfig", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.isVisible", + "type": "boolean", + "tags": [], + "label": "isVisible", + "description": [ + "\nFlag whether the legend should be shown. If there is just a single series, it will be hidden" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.position", + "type": "CompoundType", + "tags": [], + "label": "position", + "description": [ + "\nPosition of the legend relative to the chart" + ], + "signature": [ + "\"right\" | \"top\" | \"bottom\" | \"left\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.showSingleSeries", + "type": "CompoundType", + "tags": [], + "label": "showSingleSeries", + "description": [ + "\nFlag whether the legend should be shown even with just a single series" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.isInside", + "type": "CompoundType", + "tags": [], + "label": "isInside", + "description": [ + "\nFlag whether the legend is inside the chart" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.horizontalAlignment", + "type": "CompoundType", + "tags": [], + "label": "horizontalAlignment", + "description": [ + "\nHorizontal Alignment of the legend when it is set inside chart" + ], + "signature": [ + "\"right\" | \"left\" | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.verticalAlignment", + "type": "CompoundType", + "tags": [], + "label": "verticalAlignment", + "description": [ + "\nVertical Alignment of the legend when it is set inside chart" + ], + "signature": [ + "\"top\" | \"bottom\" | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.floatingColumns", + "type": "number", + "tags": [], + "label": "floatingColumns", + "description": [ + "\nNumber of columns when legend is set inside chart" + ], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.maxLines", + "type": "number", + "tags": [], + "label": "maxLines", + "description": [ + "\nMaximum number of lines per legend item" + ], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.shouldTruncate", + "type": "CompoundType", + "tags": [], + "label": "shouldTruncate", + "description": [ + "\nFlag whether the legend items are truncated or not" + ], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.legendSize", + "type": "CompoundType", + "tags": [], + "label": "legendSize", + "description": [ + "\nExact legend width (vertical) or height (horizontal)\nLimited to max of 70% of the chart container dimension Vertical legends limited to min of 30% of computed width" + ], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.LegendSize", + "text": "LegendSize" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.legendStats", + "type": "Array", + "tags": [], + "label": "legendStats", + "description": [ + "\nmetrics to display in the legend" + ], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.XYLegendValue", + "text": "XYLegendValue" + }, + "[] | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.layout", + "type": "CompoundType", + "tags": [], + "label": "layout", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.LegendLayout", + "text": "LegendLayout" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfig.isTitleVisible", + "type": "CompoundType", + "tags": [], + "label": "isTitleVisible", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicSetup", + "type": "Interface", + "tags": [], + "label": "LensPublicSetup", + "description": [], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicSetup.registerVisualization", + "type": "Function", + "tags": [ + "experimental" + ], + "label": "registerVisualization", + "description": [ + "\nRegister 3rd party visualization type\nSee `x-pack/examples/3rd_party_lens_vis` for exemplary usage.\n\nIn case the visualization is a function returning a promise, it will only be called once Lens is actually requiring it.\nThis can be used to lazy-load parts of the code to keep the initial bundle as small as possible.\n\nThis API might undergo breaking changes even in minor versions.\n" + ], + "signature": [ + "(visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Visualization", + "text": "Visualization" + }, + " | (() => Promise<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Visualization", + "text": "Visualization" + }, + ">)) => void" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicSetup.registerVisualization.$1", + "type": "CompoundType", + "tags": [], + "label": "visualization", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Visualization", + "text": "Visualization" + }, + " | (() => Promise<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Visualization", + "text": "Visualization" + }, + ">)" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicSetup.registerTopNavMenuEntryGenerator", + "type": "Function", + "tags": [ + "experimental" + ], + "label": "registerTopNavMenuEntryGenerator", + "description": [ + "\nRegister a generic menu entry shown in the top nav\nSee `x-pack/examples/3rd_party_lens_navigation_prompt` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" + ], + "signature": [ + "(navigationPromptGenerator: ", + "LensTopNavMenuEntryGenerator", + ") => void" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicSetup.registerTopNavMenuEntryGenerator.$1", + "type": "Function", + "tags": [], + "label": "navigationPromptGenerator", + "description": [], + "signature": [ + "LensTopNavMenuEntryGenerator" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart", + "type": "Interface", + "tags": [], + "label": "LensPublicStart", + "description": [], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.EmbeddableComponent", + "type": "Function", + "tags": [ + "experimental" + ], + "label": "EmbeddableComponent", + "description": [ + "\nReact component which can be used to embed a Lens visualization into another application.\nSee `x-pack/examples/embedded_lens_example` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" + ], + "signature": [ + "({ title, withDefaultActions, extraActions, showInspector, syncColors, syncCursor, syncTooltips, viewMode, id, query, filters, timeRange, disabledActions, ...props }: { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; disabledActions?: string[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" + }, + "> | undefined, dataLoading$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined) => void) | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }) => React.JSX.Element" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.EmbeddableComponent.$1", + "type": "Object", + "tags": [], + "label": "__0", + "description": [], + "signature": [ + "{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; disabledActions?: string[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" + }, + "> | undefined, dataLoading$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined) => void) | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx", + "deprecated": false, + "trackAdoption": false + } + ] + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.SaveModalComponent", + "type": "CompoundType", + "tags": [ + "experimental" + ], + "label": "SaveModalComponent", + "description": [ + "\nReact component which can be used to embed a Lens Visualization Save Modal Component.\nSee `x-pack/examples/embedded_lens_example` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" + ], + "signature": [ + "React.ComponentClass, any> | React.FunctionComponent>" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.EditLensConfigPanelApi", + "type": "Function", + "tags": [ + "experimental" + ], + "label": "EditLensConfigPanelApi", + "description": [ + "\nReact component which can be used to embed a Lens Visualization Config Panel Component.\n\nThis API might undergo breaking changes even in minor versions.\n" + ], + "signature": [ + "() => Promise<", + "EditLensConfigPanelComponent", + ">" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor", + "type": "Function", + "tags": [ + "experimental" + ], + "label": "navigateToPrefilledEditor", + "description": [ + "\nMethod which navigates to the Lens editor, loading the state specified by the `input` parameter.\nSee `x-pack/examples/embedded_lens_example` for exemplary usage.\n\nThis API might undergo breaking changes even in minor versions.\n" + ], + "signature": [ + "(input: { attributes?: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; } | undefined; savedObjectId?: string | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; timeslice?: [number, number] | undefined; searchSessionId?: string | undefined; lastReloadRequestTime?: number | undefined; id?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; disableTriggers?: boolean | undefined; syncColors?: boolean | undefined; syncTooltips?: boolean | undefined; syncCursor?: boolean | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; isNewPanel?: boolean | undefined; } | undefined, options?: { openInNewTab?: boolean | undefined; originatingApp?: string | undefined; originatingPath?: string | undefined; skipAppLeave?: boolean | undefined; } | undefined) => void" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$1", + "type": "Object", + "tags": [], + "label": "input", + "description": [], + "signature": [ + "{ attributes?: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; } | undefined; savedObjectId?: string | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; timeslice?: [number, number] | undefined; searchSessionId?: string | undefined; lastReloadRequestTime?: number | undefined; id?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; disableTriggers?: boolean | undefined; syncColors?: boolean | undefined; syncTooltips?: boolean | undefined; syncCursor?: boolean | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; isNewPanel?: boolean | undefined; } | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2", + "type": "Object", + "tags": [], + "label": "options", + "description": [], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.openInNewTab", + "type": "CompoundType", + "tags": [], + "label": "openInNewTab", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.originatingApp", + "type": "string", + "tags": [], + "label": "originatingApp", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.originatingPath", + "type": "string", + "tags": [], + "label": "originatingPath", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.navigateToPrefilledEditor.$2.skipAppLeave", + "type": "CompoundType", + "tags": [], + "label": "skipAppLeave", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.canUseEditor", + "type": "Function", + "tags": [], + "label": "canUseEditor", + "description": [ + "\nMethod which returns true if the user has permission to use Lens as defined by application capabilities." + ], + "signature": [ + "() => boolean" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.getXyVisTypes", + "type": "Function", + "tags": [], + "label": "getXyVisTypes", + "description": [ + "\nMethod which returns xy VisualizationTypes array keeping this async as to not impact page load bundle" + ], + "signature": [ + "() => Promise<", + "VisualizationType", + "[]>" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.LensPublicStart.stateHelperApi", + "type": "Function", + "tags": [], + "label": "stateHelperApi", + "description": [ + "\nAPI which returns state helpers keeping this async as to not impact page load bundle" + ], + "signature": [ + "() => Promise<{ formula: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormulaPublicApi", + "text": "FormulaPublicApi" + }, + "; chartInfo: ", + "ChartInfoApi", + "; suggestions: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensSuggestionsApi", + "text": "LensSuggestionsApi" + }, + "; }>" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MathIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "MathIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MathIndexPatternColumn", + "text": "MathIndexPatternColumn" + }, + " extends ", + "ReferenceBasedIndexPatternColumn" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/math.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.MathIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"math\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/math.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MathIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ tinymathAst: string | ", + "TinymathAST", + "; format?: ", + "ValueFormatConfig", + " | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/formula/math.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState", + "type": "Interface", + "tags": [], + "label": "MetricVisualizationState", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.layerType", + "type": "CompoundType", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.metricAccessor", + "type": "string", + "tags": [], + "label": "metricAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.secondaryMetricAccessor", + "type": "string", + "tags": [], + "label": "secondaryMetricAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.maxAccessor", + "type": "string", + "tags": [], + "label": "maxAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.breakdownByAccessor", + "type": "string", + "tags": [], + "label": "breakdownByAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.collapseFn", + "type": "CompoundType", + "tags": [], + "label": "collapseFn", + "description": [], + "signature": [ + "\"min\" | \"max\" | \"sum\" | \"avg\" | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.subtitle", + "type": "string", + "tags": [], + "label": "subtitle", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.secondaryPrefix", + "type": "string", + "tags": [], + "label": "secondaryPrefix", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.progressDirection", + "type": "CompoundType", + "tags": [], + "label": "progressDirection", + "description": [], + "signature": [ + "LayoutDirection", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.showBar", + "type": "CompoundType", + "tags": [], + "label": "showBar", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.titlesTextAlign", + "type": "CompoundType", + "tags": [], + "label": "titlesTextAlign", + "description": [], + "signature": [ + "\"right\" | \"center\" | \"left\" | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.valuesTextAlign", + "type": "CompoundType", + "tags": [], + "label": "valuesTextAlign", + "description": [], + "signature": [ + "\"right\" | \"center\" | \"left\" | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.iconAlign", + "type": "CompoundType", + "tags": [], + "label": "iconAlign", + "description": [], + "signature": [ + "\"right\" | \"left\" | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.valueFontMode", + "type": "CompoundType", + "tags": [], + "label": "valueFontMode", + "description": [], + "signature": [ + "ValueFontMode", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.color", + "type": "string", + "tags": [], + "label": "color", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.icon", + "type": "string", + "tags": [], + "label": "icon", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.palette", + "type": "Object", + "tags": [], + "label": "palette", + "description": [], + "signature": [ + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.CustomPaletteParams", + "text": "CustomPaletteParams" + }, + "> | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.maxCols", + "type": "number", + "tags": [], + "label": "maxCols", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.trendlineLayerId", + "type": "string", + "tags": [], + "label": "trendlineLayerId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.trendlineLayerType", + "type": "CompoundType", + "tags": [], + "label": "trendlineLayerType", + "description": [], + "signature": [ + "LayerType", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.trendlineTimeAccessor", + "type": "string", + "tags": [], + "label": "trendlineTimeAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.trendlineMetricAccessor", + "type": "string", + "tags": [], + "label": "trendlineMetricAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.trendlineSecondaryMetricAccessor", + "type": "string", + "tags": [], + "label": "trendlineSecondaryMetricAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.MetricVisualizationState.trendlineBreakdownByAccessor", + "type": "string", + "tags": [], + "label": "trendlineBreakdownByAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/metric/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.OperationMetadata", + "type": "Interface", + "tags": [], + "label": "OperationMetadata", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.OperationMetadata.interval", + "type": "string", + "tags": [], + "label": "interval", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.OperationMetadata.dataType", + "type": "CompoundType", + "tags": [], + "label": "dataType", + "description": [], + "signature": [ + "\"string\" | \"number\" | \"boolean\" | \"date\" | ", + "FieldOnlyDataType" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.OperationMetadata.isBucketed", + "type": "boolean", + "tags": [], + "label": "isBucketed", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.OperationMetadata.scale", + "type": "CompoundType", + "tags": [], + "label": "scale", + "description": [ + "\nordinal: Each name is a unique value, but the names are in sorted order, like \"Top values\"\ninterval: Histogram data, like date or number histograms\nratio: Most number data is rendered as a ratio that includes 0" + ], + "signature": [ + "\"interval\" | \"ratio\" | \"ordinal\" | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.OperationMetadata.isStaticValue", + "type": "CompoundType", + "tags": [], + "label": "isStaticValue", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PercentileIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "PercentileIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PercentileIndexPatternColumn", + "text": "PercentileIndexPatternColumn" + }, + " extends ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.PercentileIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"percentile\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PercentileIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ percentile: number; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PercentileRanksIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "PercentileRanksIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.PercentileRanksIndexPatternColumn", + "text": "PercentileRanksIndexPatternColumn" + }, + " extends ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile_ranks.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.PercentileRanksIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"percentile_rank\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile_ranks.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PercentileRanksIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ value: number; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile_ranks.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PieVisualizationState", + "type": "Interface", + "tags": [], + "label": "PieVisualizationState", + "description": [], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.PieVisualizationState.shape", + "type": "CompoundType", + "tags": [], + "label": "shape", + "description": [], + "signature": [ + "\"treemap\" | \"mosaic\" | \"waffle\" | \"pie\" | \"donut\"" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PieVisualizationState.layers", + "type": "Array", + "tags": [], + "label": "layers", + "description": [], + "signature": [ + "PieLayerState", + "[]" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.PieVisualizationState.palette", + "type": "Object", + "tags": [], + "label": "palette", + "description": [], + "signature": [ + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.RangeIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "RangeIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.RangeIndexPatternColumn", + "text": "RangeIndexPatternColumn" + }, + " extends ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.RangeIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"range\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.RangeIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ type: ", + "MODES_TYPES", + "; maxBars: number | \"auto\"; ranges: ", + "RangeTypeLens", + "[]; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; includeEmptyRows?: boolean | undefined; parentFormat?: { id: string; params?: { id?: string | undefined; template?: string | undefined; replaceInfinity?: boolean | undefined; } | undefined; } | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ReferenceLineLayerArgs", + "type": "Interface", + "tags": [], + "label": "ReferenceLineLayerArgs", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.ReferenceLineLayerArgs.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ReferenceLineLayerArgs.accessors", + "type": "Array", + "tags": [], + "label": "accessors", + "description": [], + "signature": [ + "string[]" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ReferenceLineLayerArgs.columnToLabel", + "type": "string", + "tags": [], + "label": "columnToLabel", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ReferenceLineLayerArgs.decorations", + "type": "Array", + "tags": [], + "label": "decorations", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.ReferenceLineDecorationConfigResult", + "text": "ReferenceLineDecorationConfigResult" + }, + "[] | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.ReferenceLineLayerArgs.table", + "type": "Object", + "tags": [], + "label": "table", + "description": [], + "signature": [ + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState", + "type": "Interface", + "tags": [], + "label": "SharedPieLayerState", + "description": [], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.metrics", + "type": "Array", + "tags": [], + "label": "metrics", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.primaryGroups", + "type": "Array", + "tags": [], + "label": "primaryGroups", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.secondaryGroups", + "type": "Array", + "tags": [], + "label": "secondaryGroups", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.allowMultipleMetrics", + "type": "CompoundType", + "tags": [], + "label": "allowMultipleMetrics", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.colorsByDimension", + "type": "Object", + "tags": [], + "label": "colorsByDimension", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.collapseFns", + "type": "Object", + "tags": [], + "label": "collapseFns", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.numberDisplay", + "type": "CompoundType", + "tags": [], + "label": "numberDisplay", + "description": [], + "signature": [ + "\"value\" | \"hidden\" | \"percent\"" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.categoryDisplay", + "type": "CompoundType", + "tags": [], + "label": "categoryDisplay", + "description": [], + "signature": [ + "\"default\" | \"inside\" | \"hide\"" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.legendDisplay", + "type": "CompoundType", + "tags": [], + "label": "legendDisplay", + "description": [], + "signature": [ + "\"default\" | \"hide\" | \"show\"" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.legendPosition", + "type": "CompoundType", + "tags": [], + "label": "legendPosition", + "description": [], + "signature": [ + "Position", + " | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.legendStats", + "type": "Array", + "tags": [], + "label": "legendStats", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.PartitionLegendValue", + "text": "PartitionLegendValue" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.nestedLegend", + "type": "CompoundType", + "tags": [], + "label": "nestedLegend", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.percentDecimals", + "type": "number", + "tags": [], + "label": "percentDecimals", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.emptySizeRatio", + "type": "number", + "tags": [], + "label": "emptySizeRatio", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.legendMaxLines", + "type": "number", + "tags": [], + "label": "legendMaxLines", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.legendSize", + "type": "CompoundType", + "tags": [], + "label": "legendSize", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.LegendSize", + "text": "LegendSize" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.truncateLegend", + "type": "CompoundType", + "tags": [], + "label": "truncateLegend", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SharedPieLayerState.colorMapping", + "type": "Object", + "tags": [], + "label": "colorMapping", + "description": [], + "signature": [ + "Config", + " | undefined" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.StaticValueIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "StaticValueIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.StaticValueIndexPatternColumn", + "text": "StaticValueIndexPatternColumn" + }, + " extends ", + "ReferenceBasedIndexPatternColumn" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.StaticValueIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"static_value\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.StaticValueIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ value?: string | undefined; format?: ", + "ValueFormatConfig", + " | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion", + "type": "Interface", + "tags": [], + "label": "Suggestion", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Suggestion", + "text": "Suggestion" + }, + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.visualizationId", + "type": "string", + "tags": [], + "label": "visualizationId", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.datasourceState", + "type": "Uncategorized", + "tags": [], + "label": "datasourceState", + "description": [], + "signature": [ + "V | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.datasourceId", + "type": "string", + "tags": [], + "label": "datasourceId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.columns", + "type": "number", + "tags": [], + "label": "columns", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.score", + "type": "number", + "tags": [], + "label": "score", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.title", + "type": "string", + "tags": [], + "label": "title", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.visualizationState", + "type": "Uncategorized", + "tags": [], + "label": "visualizationState", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.previewExpression", + "type": "CompoundType", + "tags": [], + "label": "previewExpression", + "description": [], + "signature": [ + "string | ", + { + "pluginId": "@kbn/interpreter", + "scope": "common", + "docId": "kibKbnInterpreterPluginApi", + "section": "def-common.Ast", + "text": "Ast" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.previewIcon", + "type": "CompoundType", + "tags": [], + "label": "previewIcon", + "description": [], + "signature": [ + "string | React.ComponentType<{}>" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.hide", + "type": "CompoundType", + "tags": [], + "label": "hide", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.incomplete", + "type": "CompoundType", + "tags": [], + "label": "incomplete", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.changeType", + "type": "CompoundType", + "tags": [], + "label": "changeType", + "description": [], + "signature": [ + "\"extended\" | \"layers\" | \"initial\" | \"unchanged\" | \"reduced\" | \"reorder\"" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Suggestion.keptLayerIds", + "type": "Array", + "tags": [], + "label": "keptLayerIds", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest", + "type": "Interface", + "tags": [], + "label": "SuggestionRequest", + "description": [ + "\nObject passed to `getSuggestions` of a visualization.\nIt contains a possible table the current datasource could\nprovide and the state of the visualization if it is currently active.\n\nIf the current datasource suggests multiple tables, `getSuggestions`\nis called multiple times with separate `SuggestionRequest` objects." + ], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.SuggestionRequest", + "text": "SuggestionRequest" + }, + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.table", + "type": "Object", + "tags": [], + "label": "table", + "description": [ + "\nA table configuration the datasource could provide." + ], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.TableSuggestion", + "text": "TableSuggestion" + } + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.state", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [ + "\nState is only passed if the visualization is active." + ], + "signature": [ + "T | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.mainPalette", + "type": "CompoundType", + "tags": [], + "label": "mainPalette", + "description": [ + "\nPassing the legacy palette or the new color mapping if available" + ], + "signature": [ + "{ type: \"legacyPalette\"; value: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", + "Config", + "; } | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.isFromContext", + "type": "CompoundType", + "tags": [], + "label": "isFromContext", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.keptLayerIds", + "type": "Array", + "tags": [], + "label": "keptLayerIds", + "description": [ + "\nThe visualization needs to know which table is being suggested" + ], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.subVisualizationId", + "type": "string", + "tags": [], + "label": "subVisualizationId", + "description": [ + "\nDifferent suggestions can be generated for each subtype of the visualization" + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.activeData", + "type": "Object", + "tags": [], + "label": "activeData", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.allowMixed", + "type": "CompoundType", + "tags": [], + "label": "allowMixed", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.SuggestionRequest.datasourceId", + "type": "string", + "tags": [], + "label": "datasourceId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion", + "type": "Interface", + "tags": [], + "label": "TableSuggestion", + "description": [ + "\nA possible table a datasource can create. This object is passed to the visualization\nwhich tries to build a meaningful visualization given the shape of the table. If this\nis possible, the visualization returns a `VisualizationSuggestion` object" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.isMultiRow", + "type": "boolean", + "tags": [], + "label": "isMultiRow", + "description": [ + "\nFlag indicating whether the table will include more than one column.\nThis is not the case for example for a single metric aggregation" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.columns", + "type": "Array", + "tags": [], + "label": "columns", + "description": [ + "\nThe columns of the table. Each column has to be mapped to a dimension in a chart. If a visualization\ncan't use all columns of a suggestion, it should not return a `VisualizationSuggestion` based on it\nbecause there would be unreferenced columns" + ], + "signature": [ + "TableSuggestionColumn", + "[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [ + "\nThe layer this table will replace. This is only relevant if the visualization this suggestion is passed\nis currently active and has multiple layers configured. If this suggestion is applied, the table of this\nlayer will be replaced by the columns specified in this suggestion" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.label", + "type": "string", + "tags": [], + "label": "label", + "description": [ + "\nA label describing the table. This can be used to provide a title for the `VisualizationSuggestion`,\nbut the visualization can also decide to overwrite it." + ], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.changeType", + "type": "CompoundType", + "tags": [], + "label": "changeType", + "description": [ + "\nThe change type indicates what was changed in this table compared to the currently active table of this layer." + ], + "signature": [ + "\"extended\" | \"layers\" | \"initial\" | \"unchanged\" | \"reduced\" | \"reorder\"" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TableSuggestion.notAssignedMetrics", + "type": "CompoundType", + "tags": [], + "label": "notAssignedMetrics", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState", + "type": "Interface", + "tags": [], + "label": "TagcloudState", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.tagAccessor", + "type": "string", + "tags": [], + "label": "tagAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.valueAccessor", + "type": "string", + "tags": [], + "label": "valueAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.maxFontSize", + "type": "number", + "tags": [], + "label": "maxFontSize", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.minFontSize", + "type": "number", + "tags": [], + "label": "minFontSize", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.orientation", + "type": "CompoundType", + "tags": [], + "label": "orientation", + "description": [], + "signature": [ + "\"single\" | \"right angled\" | \"multiple\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.palette", + "type": "Object", + "tags": [], + "label": "palette", + "description": [], + "signature": [ + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.showLabel", + "type": "boolean", + "tags": [], + "label": "showLabel", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TagcloudState.colorMapping", + "type": "Object", + "tags": [], + "label": "colorMapping", + "description": [], + "signature": [ + "Config", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TermsIndexPatternColumn", + "type": "Interface", + "tags": [], + "label": "TermsIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.TermsIndexPatternColumn", + "text": "TermsIndexPatternColumn" + }, + " extends ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + } + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.TermsIndexPatternColumn.operationType", + "type": "string", + "tags": [], + "label": "operationType", + "description": [], + "signature": [ + "\"terms\"" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.TermsIndexPatternColumn.params", + "type": "Object", + "tags": [], + "label": "params", + "description": [], + "signature": [ + "{ size: number; accuracyMode?: boolean | undefined; include?: string[] | number[] | undefined; exclude?: string[] | number[] | undefined; includeIsRegex?: boolean | undefined; excludeIsRegex?: boolean | undefined; orderBy: { type: \"alphabetical\"; fallback?: boolean | undefined; } | { type: \"rare\"; maxDocCount: number; } | { type: \"significant\"; } | { type: \"column\"; columnId: string; } | { type: \"custom\"; }; orderAgg?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " | undefined; orderDirection: \"asc\" | \"desc\"; otherBucket?: boolean | undefined; missingBucket?: boolean | undefined; secondaryFields?: string[] | undefined; format?: ", + "ValueFormatConfig", + " | undefined; parentFormat?: { id: string; } | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage", + "type": "Interface", + "tags": [], + "label": "UserMessage", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.uniqueId", + "type": "string", + "tags": [], + "label": "uniqueId", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.severity", + "type": "CompoundType", + "tags": [], + "label": "severity", + "description": [], + "signature": [ + "\"error\" | \"info\" | \"warning\"" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.hidePopoverIcon", + "type": "CompoundType", + "tags": [], + "label": "hidePopoverIcon", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.shortMessage", + "type": "string", + "tags": [], + "label": "shortMessage", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.longMessage", + "type": "CompoundType", + "tags": [], + "label": "longMessage", + "description": [], + "signature": [ + "React.ReactNode | ((closePopover?: (() => void) | undefined) => React.ReactNode)" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.fixableInEditor", + "type": "boolean", + "tags": [], + "label": "fixableInEditor", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.UserMessage.displayLocations", + "type": "Array", + "tags": [], + "label": "displayLocations", + "description": [], + "signature": [ + "UserMessageDisplayLocation[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization", + "type": "Interface", + "tags": [], + "label": "Visualization", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Visualization", + "text": "Visualization" + }, + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.id", + "type": "string", + "tags": [], + "label": "id", + "description": [ + "Plugin ID, such as \"lnsXY\"" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.alias", + "type": "Array", + "tags": [], + "label": "alias", + "description": [], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.initialize", + "type": "Function", + "tags": [], + "label": "initialize", + "description": [ + "\nInitialize is allowed to modify the state stored in memory. The initialize function\nis called with a previous state in two cases:\n- Loading from a saved visualization\n- When using suggestions, the suggested state is passed in" + ], + "signature": [ + "{ (addNewLayer: () => string, nonPersistedState?: T | undefined, mainPalette?: { type: \"legacyPalette\"; value: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", + "Config", + "; } | undefined): T; (addNewLayer: () => string, persistedState: P, mainPalette?: { type: \"legacyPalette\"; value: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", + "Config", + "; } | undefined, annotationGroups?: ", + "AnnotationGroups", + " | undefined, references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined): T; }" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUsedDataView", + "type": "Function", + "tags": [], + "label": "getUsedDataView", + "description": [], + "signature": [ + "((state: T, layerId: string) => string | undefined) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUsedDataView.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUsedDataView.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUsedDataViews", + "type": "Function", + "tags": [], + "label": "getUsedDataViews", + "description": [ + "\nRetrieve the used DataViews in the visualization" + ], + "signature": [ + "((state?: T | undefined) => string[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUsedDataViews.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getMainPalette", + "type": "Function", + "tags": [], + "label": "getMainPalette", + "description": [], + "signature": [ + "((state: T) => { type: \"legacyPalette\"; value: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", + "Config", + "; } | undefined) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getMainPalette.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.triggers", + "type": "Array", + "tags": [], + "label": "triggers", + "description": [ + "\nSupported triggers of this visualization type when embedded somewhere" + ], + "signature": [ + "string[] | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.visualizationTypes", + "type": "Array", + "tags": [], + "label": "visualizationTypes", + "description": [ + "\nVisualizations must provide at least one type for the chart switcher,\nbut can register multiple subtypes" + ], + "signature": [ + "VisualizationType", + "[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getVisualizationTypeId", + "type": "Function", + "tags": [], + "label": "getVisualizationTypeId", + "description": [ + "\nReturn the ID of the current visualization. Used to highlight\nthe active subtype of the visualization." + ], + "signature": [ + "(state: T, layerId?: string | undefined) => string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getVisualizationTypeId.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getVisualizationTypeId.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.hideFromChartSwitch", + "type": "Function", + "tags": [], + "label": "hideFromChartSwitch", + "description": [], + "signature": [ + "((frame: ", + "FramePublicAPI", + ") => boolean) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.hideFromChartSwitch.$1", + "type": "Object", + "tags": [], + "label": "frame", + "description": [], + "signature": [ + "FramePublicAPI" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.switchVisualizationType", + "type": "Function", + "tags": [], + "label": "switchVisualizationType", + "description": [ + "\nIf the visualization has subtypes, update the subtype in state." + ], + "signature": [ + "((visualizationTypeId: string, state: T, layerId?: string | undefined) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.switchVisualizationType.$1", + "type": "string", + "tags": [], + "label": "visualizationTypeId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.switchVisualizationType.$2", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.switchVisualizationType.$3", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getDescription", + "type": "Function", + "tags": [], + "label": "getDescription", + "description": [ + "Description is displayed as the clickable text in the chart switcher" + ], + "signature": [ + "(state: T, layerId?: string | undefined) => { icon?: ", + "IconType", + " | undefined; label: string; }" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getDescription.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getDescription.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getPersistableState", + "type": "Function", + "tags": [], + "label": "getPersistableState", + "description": [ + "Visualizations can have references as well" + ], + "signature": [ + "((state: T) => { state: P; savedObjectReferences: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; }) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getPersistableState.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayerIds", + "type": "Function", + "tags": [], + "label": "getLayerIds", + "description": [ + "Frame needs to know which layers the visualization is currently using" + ], + "signature": [ + "(state: T) => string[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayerIds.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.clearLayer", + "type": "Function", + "tags": [], + "label": "clearLayer", + "description": [ + "Reset button on each layer triggers this" + ], + "signature": [ + "(state: T, layerId: string, indexPatternId: string) => T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.clearLayer.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.clearLayer.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.clearLayer.$3", + "type": "string", + "tags": [], + "label": "indexPatternId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.cloneLayer", + "type": "Function", + "tags": [], + "label": "cloneLayer", + "description": [ + "Reset button on each layer triggers this" + ], + "signature": [ + "((state: T, layerId: string, newLayerId: string, clonedIDsMap: Map) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.cloneLayer.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.cloneLayer.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.cloneLayer.$3", + "type": "string", + "tags": [], + "label": "newLayerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.cloneLayer.$4", + "type": "Object", + "tags": [], + "label": "clonedIDsMap", + "description": [], + "signature": [ + "Map" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.removeLayer", + "type": "Function", + "tags": [], + "label": "removeLayer", + "description": [ + "Optional, if the visualization supports multiple layers" + ], + "signature": [ + "((state: T, layerId: string) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.removeLayer.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.removeLayer.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer", + "type": "Function", + "tags": [], + "label": "appendLayer", + "description": [ + "Track added layers in internal state" + ], + "signature": [ + "((state: T, layerId: string, type: ", + "LayerType", + ", indexPatternId: string, extraArg?: ExtraAppendLayerArg | undefined, seriesType?: ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.SeriesType", + "text": "SeriesType" + }, + " | undefined) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer.$3", + "type": "CompoundType", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "LayerType" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer.$4", + "type": "string", + "tags": [], + "label": "indexPatternId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer.$5", + "type": "Uncategorized", + "tags": [], + "label": "extraArg", + "description": [], + "signature": [ + "ExtraAppendLayerArg | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.appendLayer.$6", + "type": "CompoundType", + "tags": [], + "label": "seriesType", + "description": [], + "signature": [ + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.SeriesType", + "text": "SeriesType" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedLayers", + "type": "Function", + "tags": [], + "label": "getSupportedLayers", + "description": [ + "Retrieve a list of supported layer types with initialization data" + ], + "signature": [ + "(state?: T | undefined, frame?: Pick<", + "FramePublicAPI", + ", \"activeData\" | \"datasourceLayers\"> | undefined) => ", + "VisualizationLayerDescription", + "[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedLayers.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedLayers.$2", + "type": "Object", + "tags": [], + "label": "frame", + "description": [], + "signature": [ + "Pick<", + "FramePublicAPI", + ", \"activeData\" | \"datasourceLayers\"> | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedActionsForLayer", + "type": "Function", + "tags": [], + "label": "getSupportedActionsForLayer", + "description": [ + "\nreturns a list of custom actions supported by the visualization layer.\nDefault actions like delete/clear are not included in this list and are managed by the editor frame" + ], + "signature": [ + "((layerId: string, state: T, setState: ", + "StateSetter", + ", registerLibraryAnnotationGroup: ", + "RegisterLibraryAnnotationGroupFunction", + ", isSaveable?: boolean | undefined) => ", + "LayerAction", + "[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedActionsForLayer.$1", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedActionsForLayer.$2", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedActionsForLayer.$3", + "type": "Function", + "tags": [], + "label": "setState", + "description": [], + "signature": [ + "StateSetter", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedActionsForLayer.$4", + "type": "Function", + "tags": [], + "label": "registerLibraryAnnotationGroup", + "description": [], + "signature": [ + "RegisterLibraryAnnotationGroupFunction" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSupportedActionsForLayer.$5", + "type": "CompoundType", + "tags": [], + "label": "isSaveable", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getCustomRemoveLayerText", + "type": "Function", + "tags": [], + "label": "getCustomRemoveLayerText", + "description": [ + "\nThis method is a clunky solution to the problem, but I'm banking on the confirm modal being removed\nwith undo/redo anyways" + ], + "signature": [ + "((layerId: string, state: T) => { title?: string | undefined; description?: string | undefined; } | undefined) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getCustomRemoveLayerText.$1", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getCustomRemoveLayerText.$2", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayerType", + "type": "Function", + "tags": [], + "label": "getLayerType", + "description": [ + "returns the type string of the given layer" + ], + "signature": [ + "(layerId: string, state?: T | undefined) => ", + "LayerType", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayerType.$1", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayerType.$2", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayersToLinkTo", + "type": "Function", + "tags": [], + "label": "getLayersToLinkTo", + "description": [ + "\nGet the layers this one should be linked to (currently that means just keeping the data view in sync)" + ], + "signature": [ + "((state: T, newLayerId: string) => string[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayersToLinkTo.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayersToLinkTo.$2", + "type": "string", + "tags": [], + "label": "newLayerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLinkedDimensions", + "type": "Function", + "tags": [], + "label": "getLinkedDimensions", + "description": [ + "\nReturns a set of dimensions that should be kept in sync" + ], + "signature": [ + "((state: T) => DimensionLink[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLinkedDimensions.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getRemoveOperation", + "type": "Function", + "tags": [], + "label": "getRemoveOperation", + "description": [], + "signature": [ + "((state: T, layerId: string) => \"clear\" | \"remove\") | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getRemoveOperation.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getRemoveOperation.$2", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getConfiguration", + "type": "Function", + "tags": [], + "label": "getConfiguration", + "description": [ + "\nFor consistency across different visualizations, the dimension configuration UI is standardized" + ], + "signature": [ + "(props: ", + "VisualizationConfigProps", + ") => { hidden?: boolean | undefined; groups: ", + "VisualizationDimensionGroupConfig", + "[]; }" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getConfiguration.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationConfigProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isSubtypeCompatible", + "type": "Function", + "tags": [], + "label": "isSubtypeCompatible", + "description": [], + "signature": [ + "((subtype1?: string | undefined, subtype2?: string | undefined) => boolean) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isSubtypeCompatible.$1", + "type": "string", + "tags": [], + "label": "subtype1", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isSubtypeCompatible.$2", + "type": "string", + "tags": [], + "label": "subtype2", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getCustomLayerHeader", + "type": "Function", + "tags": [], + "label": "getCustomLayerHeader", + "description": [ + "\nHeader rendered as layer title. This can be used for both static and dynamic content like\nfor extra configurability, such as for switch chart type" + ], + "signature": [ + "((props: ", + "VisualizationLayerWidgetProps", + ") => React.ReactElement<", + "VisualizationLayerWidgetProps", + ", string | React.JSXElementConstructor> | undefined) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getCustomLayerHeader.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationLayerWidgetProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSubtypeSwitch", + "type": "Function", + "tags": [], + "label": "getSubtypeSwitch", + "description": [], + "signature": [ + "((props: ", + "VisualizationLayerWidgetProps", + ") => (() => JSX.Element) | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSubtypeSwitch.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationLayerWidgetProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.LayerPanelComponent", + "type": "Function", + "tags": [], + "label": "LayerPanelComponent", + "description": [ + "\nLayer panel content rendered. This can be used to render a custom content below the title,\nlike a custom dataview switch" + ], + "signature": [ + "((props: ", + "VisualizationLayerWidgetProps", + ") => React.ReactElement<", + "VisualizationLayerWidgetProps", + ", string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.LayerPanelComponent.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationLayerWidgetProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.ToolbarComponent", + "type": "Function", + "tags": [], + "label": "ToolbarComponent", + "description": [ + "\nToolbar rendered above the visualization. This is meant to be used to provide chart-level\nsettings for the visualization." + ], + "signature": [ + "((props: ", + "VisualizationToolbarProps", + ") => React.ReactElement<", + "VisualizationToolbarProps", + ", string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.ToolbarComponent.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationToolbarProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.setDimension", + "type": "Function", + "tags": [], + "label": "setDimension", + "description": [ + "\nThe frame is telling the visualization to update or set a dimension based on user interaction\ngroupId is coming from the groupId provided in getConfiguration" + ], + "signature": [ + "(props: ", + "VisualizationDimensionChangeProps", + " & { groupId: string; previousColumn?: string | undefined; }) => T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.setDimension.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationDimensionChangeProps", + " & { groupId: string; previousColumn?: string | undefined; }" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.removeDimension", + "type": "Function", + "tags": [], + "label": "removeDimension", + "description": [ + "\nThe frame is telling the visualization to remove a dimension. The visualization needs to\nlook at its internal state to determine which dimension is being affected." + ], + "signature": [ + "(props: ", + "VisualizationDimensionChangeProps", + ") => T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.removeDimension.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationDimensionChangeProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop", + "type": "Function", + "tags": [], + "label": "onDrop", + "description": [ + "\nAllow defining custom behavior for the visualization when the drop action occurs." + ], + "signature": [ + "((props: { prevState: T; target: ", + "DragDropOperation", + "; source: ", + { + "pluginId": "@kbn/dom-drag-drop", + "scope": "common", + "docId": "kibKbnDomDragDropPluginApi", + "section": "def-common.DragDropIdentifier", + "text": "DragDropIdentifier" + }, + "; frame: ", + "FramePublicAPI", + "; dropType: ", + { + "pluginId": "@kbn/dom-drag-drop", + "scope": "common", + "docId": "kibKbnDomDragDropPluginApi", + "section": "def-common.DropType", + "text": "DropType" + }, + "; group?: ", + "VisualizationDimensionGroupConfig", + " | undefined; }) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1.prevState", + "type": "Uncategorized", + "tags": [], + "label": "prevState", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1.target", + "type": "Object", + "tags": [], + "label": "target", + "description": [], + "signature": [ + "DragDropOperation" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1.source", + "type": "CompoundType", + "tags": [], + "label": "source", + "description": [], + "signature": [ + "Record & { id: string; humanData: ", + "HumanData", + "; }" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1.frame", + "type": "Object", + "tags": [], + "label": "frame", + "description": [], + "signature": [ + "FramePublicAPI" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1.dropType", + "type": "CompoundType", + "tags": [], + "label": "dropType", + "description": [], + "signature": [ + "\"reorder\" | \"field_add\" | \"field_replace\" | \"move_compatible\" | \"replace_compatible\" | \"move_incompatible\" | \"replace_incompatible\" | \"replace_duplicate_compatible\" | \"duplicate_compatible\" | \"swap_compatible\" | \"replace_duplicate_incompatible\" | \"duplicate_incompatible\" | \"swap_incompatible\" | \"field_combine\" | \"combine_compatible\" | \"combine_incompatible\"" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDrop.$1.group", + "type": "CompoundType", + "tags": [], + "label": "group", + "description": [], + "signature": [ + "VisualizationDimensionGroupConfig", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getDropProps", + "type": "Function", + "tags": [], + "label": "getDropProps", + "description": [], + "signature": [ + "((dropProps: ", + "GetDropPropsArgs", + ") => { dropTypes: ", + { + "pluginId": "@kbn/dom-drag-drop", + "scope": "common", + "docId": "kibKbnDomDragDropPluginApi", + "section": "def-common.DropType", + "text": "DropType" + }, + "[]; nextLabel?: string | undefined; } | undefined) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getDropProps.$1", + "type": "Object", + "tags": [], + "label": "dropProps", + "description": [], + "signature": [ + "GetDropPropsArgs", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.hasLayerSettings", + "type": "Function", + "tags": [], + "label": "hasLayerSettings", + "description": [ + "\nAllows the visualization to announce whether or not it has any settings to show" + ], + "signature": [ + "((props: ", + "VisualizationConfigProps", + ") => Record<\"data\" | \"appearance\", boolean>) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.hasLayerSettings.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationConfigProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.LayerSettingsComponent", + "type": "Function", + "tags": [], + "label": "LayerSettingsComponent", + "description": [], + "signature": [ + "((props: ", + "VisualizationConfigProps", + " & { setState(newState: T | ((currState: T) => T)): void; panelRef: React.MutableRefObject; } & { section: \"data\" | \"appearance\"; }) => React.ReactElement<", + "VisualizationLayerSettingsProps", + ", string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.LayerSettingsComponent.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationConfigProps", + " & { setState(newState: T | ((currState: T) => T)): void; panelRef: React.MutableRefObject; } & { section: \"data\" | \"appearance\"; }" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionEditorComponent", + "type": "Function", + "tags": [], + "label": "DimensionEditorComponent", + "description": [ + "\nAdditional editor that gets rendered inside the dimension popover in the \"appearance\" section.\nThis can be used to configure dimension-specific options" + ], + "signature": [ + "((props: ", + "VisualizationDimensionEditorProps", + ") => React.ReactElement<", + "VisualizationDimensionEditorProps", + ", string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionEditorComponent.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationDimensionEditorProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionEditorAdditionalSectionComponent", + "type": "Function", + "tags": [], + "label": "DimensionEditorAdditionalSectionComponent", + "description": [ + "\nAdditional editor that gets rendered inside the dimension popover in an additional section below \"appearance\".\nThis can be used to configure dimension-specific options" + ], + "signature": [ + "((props: ", + "VisualizationDimensionEditorProps", + ") => React.ReactElement<", + "VisualizationDimensionEditorProps", + ", string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionEditorAdditionalSectionComponent.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationDimensionEditorProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionEditorDataExtraComponent", + "type": "Function", + "tags": [], + "label": "DimensionEditorDataExtraComponent", + "description": [ + "\nAdditional editor that gets rendered inside the data section.\nThis can be used to configure dimension-specific options" + ], + "signature": [ + "((props: ", + "VisualizationDimensionEditorProps", + ") => React.ReactElement<", + "VisualizationDimensionEditorProps", + ", string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionEditorDataExtraComponent.$1", + "type": "CompoundType", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationDimensionEditorProps", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionTriggerComponent", + "type": "Function", + "tags": [], + "label": "DimensionTriggerComponent", + "description": [ + "\nRenders dimension trigger. Used only for noDatasource layers" + ], + "signature": [ + "((props: { columnId: string; label: string; }) => React.ReactElement<{ columnId: string; label: string; }, string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionTriggerComponent.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionTriggerComponent.$1.columnId", + "type": "string", + "tags": [], + "label": "columnId", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.DimensionTriggerComponent.$1.label", + "type": "string", + "tags": [], + "label": "label", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getAddLayerButtonComponent", + "type": "Function", + "tags": [], + "label": "getAddLayerButtonComponent", + "description": [], + "signature": [ + "((props: AddLayerButtonProps) => React.ReactElement, string | React.JSXElementConstructor> | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getAddLayerButtonComponent.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "AddLayerButtonProps" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUniqueLabels", + "type": "Function", + "tags": [], + "label": "getUniqueLabels", + "description": [ + "\nCreates map of columns ids and unique lables. Used only for noDatasource layers" + ], + "signature": [ + "((state: T) => Record) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUniqueLabels.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSuggestions", + "type": "Function", + "tags": [], + "label": "getSuggestions", + "description": [ + "\nThe frame will call this function on all visualizations at different times. The\nmain use cases where visualization suggestions are requested are:\n- When dragging a field\n- When opening the chart switcher\nIf the state is provided when requesting suggestions, the visualization is active.\nMost visualizations will apply stricter filtering to suggestions when they are active,\nbecause suggestions have the potential to remove the users's work in progress." + ], + "signature": [ + "(context: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.SuggestionRequest", + "text": "SuggestionRequest" + }, + ") => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.VisualizationSuggestion", + "text": "VisualizationSuggestion" + }, + "[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSuggestions.$1", + "type": "Object", + "tags": [], + "label": "context", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.SuggestionRequest", + "text": "SuggestionRequest" + }, + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toExpression", + "type": "Function", + "tags": [], + "label": "toExpression", + "description": [], + "signature": [ + "(state: T, datasourceLayers: Partial>, attributes?: Partial<{ title: string; description: string; }> | undefined, datasourceExpressionsByLayers?: Record | undefined) => string | ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionAstExpression", + "text": "ExpressionAstExpression" + }, + " | null" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toExpression.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toExpression.$2", + "type": "Object", + "tags": [], + "label": "datasourceLayers", + "description": [], + "signature": [ + "Partial>" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toExpression.$3", + "type": "Object", + "tags": [], + "label": "attributes", + "description": [], + "signature": [ + "Partial<{ title: string; description: string; }> | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toExpression.$4", + "type": "Object", + "tags": [], + "label": "datasourceExpressionsByLayers", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toPreviewExpression", + "type": "Function", + "tags": [], + "label": "toPreviewExpression", + "description": [ + "\nExpression to render a preview version of the chart in very constrained space.\nIf there is no expression provided, the preview icon is used." + ], + "signature": [ + "((state: T, datasourceLayers: Partial>, datasourceExpressionsByLayers?: Record | undefined) => string | ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.ExpressionAstExpression", + "text": "ExpressionAstExpression" + }, + " | null) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toPreviewExpression.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toPreviewExpression.$2", + "type": "Object", + "tags": [], + "label": "datasourceLayers", + "description": [], + "signature": [ + "Partial>" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.toPreviewExpression.$3", + "type": "Object", + "tags": [], + "label": "datasourceExpressionsByLayers", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUserMessages", + "type": "Function", + "tags": [], + "label": "getUserMessages", + "description": [ + "\nThe frame will call this function on all visualizations at few stages (pre-build/build error) in order\nto provide more context to the error and show it to the user" + ], + "signature": [ + "((state: T, deps: { frame: ", + "FramePublicAPI", + "; }) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUserMessages.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUserMessages.$2", + "type": "Object", + "tags": [], + "label": "deps", + "description": [], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getUserMessages.$2.frame", + "type": "Object", + "tags": [], + "label": "frame", + "description": [], + "signature": [ + "FramePublicAPI" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ] + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onEditAction", + "type": "Function", + "tags": [], + "label": "onEditAction", + "description": [ + "\nOn Edit events the frame will call this to know what's going to be the next visualization state" + ], + "signature": [ + "((state: T, event: ", + "LensEditEvent", + ") => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onEditAction.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onEditAction.$2", + "type": "Object", + "tags": [], + "label": "event", + "description": [], + "signature": [ + "LensEditEvent", + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDatasourceUpdate", + "type": "Function", + "tags": [], + "label": "onDatasourceUpdate", + "description": [], + "signature": [ + "((state: T, frame?: ", + "FramePublicAPI", + " | undefined) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDatasourceUpdate.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onDatasourceUpdate.$2", + "type": "Object", + "tags": [], + "label": "frame", + "description": [], + "signature": [ + "FramePublicAPI", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternChange", + "type": "Function", + "tags": [], + "label": "onIndexPatternChange", + "description": [ + "\nSome visualization track indexPattern changes (i.e. annotations)\nThis method makes it aware of the change and produces a new updated state" + ], + "signature": [ + "((state: T, indexPatternId: string, layerId?: string | undefined) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternChange.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternChange.$2", + "type": "string", + "tags": [], + "label": "indexPatternId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternChange.$3", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternRename", + "type": "Function", + "tags": [], + "label": "onIndexPatternRename", + "description": [], + "signature": [ + "((state: T, oldIndexPatternId: string, newIndexPatternId: string) => T) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternRename.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternRename.$2", + "type": "string", + "tags": [], + "label": "oldIndexPatternId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.onIndexPatternRename.$3", + "type": "string", + "tags": [], + "label": "newIndexPatternId", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayersToRemoveOnIndexPatternChange", + "type": "Function", + "tags": [], + "label": "getLayersToRemoveOnIndexPatternChange", + "description": [], + "signature": [ + "((state: T) => string[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getLayersToRemoveOnIndexPatternChange.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getDisplayOptions", + "type": "Function", + "tags": [], + "label": "getDisplayOptions", + "description": [ + "\nGets custom display options for showing the visualization." + ], + "signature": [ + "(() => ", + "VisualizationDisplayOptions", + ") | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getRenderEventCounters", + "type": "Function", + "tags": [], + "label": "getRenderEventCounters", + "description": [ + "\nGet RenderEventCounters events for telemetry" + ], + "signature": [ + "((state: T) => string[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getRenderEventCounters.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSuggestionFromConvertToLensContext", + "type": "Function", + "tags": [], + "label": "getSuggestionFromConvertToLensContext", + "description": [], + "signature": [ + "((props: VisualizationStateFromContextChangeProps) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Suggestion", + "text": "Suggestion" + }, + " | undefined) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getSuggestionFromConvertToLensContext.$1", + "type": "Object", + "tags": [], + "label": "props", + "description": [], + "signature": [ + "VisualizationStateFromContextChangeProps" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isEqual", + "type": "Function", + "tags": [], + "label": "isEqual", + "description": [], + "signature": [ + "((state1: P, references1: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[], state2: P, references2: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[], annotationGroups: ", + "AnnotationGroups", + ") => boolean) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isEqual.$1", + "type": "Uncategorized", + "tags": [], + "label": "state1", + "description": [], + "signature": [ + "P" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isEqual.$2", + "type": "Array", + "tags": [], + "label": "references1", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isEqual.$3", + "type": "Uncategorized", + "tags": [], + "label": "state2", + "description": [], + "signature": [ + "P" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isEqual.$4", + "type": "Array", + "tags": [], + "label": "references2", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.isEqual.$5", + "type": "Object", + "tags": [], + "label": "annotationGroups", + "description": [], + "signature": [ + "AnnotationGroups" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getVisualizationInfo", + "type": "Function", + "tags": [], + "label": "getVisualizationInfo", + "description": [], + "signature": [ + "((state: T, frame?: ", + "FramePublicAPI", + " | undefined) => ", + "VisualizationInfo", + ") | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getVisualizationInfo.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getVisualizationInfo.$2", + "type": "Object", + "tags": [], + "label": "frame", + "description": [], + "signature": [ + "FramePublicAPI", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getReportingLayout", + "type": "Function", + "tags": [], + "label": "getReportingLayout", + "description": [ + "\nA visualization can return custom dimensions for the reporting tool" + ], + "signature": [ + "((state: T) => { height: number; width: number; }) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getReportingLayout.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getExportDatatables", + "type": "Function", + "tags": [], + "label": "getExportDatatables", + "description": [ + "\nGet all datatables to be exported as csv" + ], + "signature": [ + "((state: T, datasourceLayers?: Partial> | undefined, activeData?: ", + "TableInspectorAdapter", + " | undefined) => ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getExportDatatables.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getExportDatatables.$2", + "type": "Object", + "tags": [], + "label": "datasourceLayers", + "description": [], + "signature": [ + "Partial> | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getExportDatatables.$3", + "type": "Object", + "tags": [], + "label": "activeData", + "description": [], + "signature": [ + "TableInspectorAdapter", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getTelemetryEventsOnSave", + "type": "Function", + "tags": [], + "label": "getTelemetryEventsOnSave", + "description": [ + "\nreturns array of telemetry events for the visualization on save" + ], + "signature": [ + "((state: T, prevState?: T | undefined) => string[]) | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getTelemetryEventsOnSave.$1", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "lens", + "id": "def-public.Visualization.getTelemetryEventsOnSave.$2", + "type": "Uncategorized", + "tags": [], + "label": "prevState", + "description": [], + "signature": [ + "T | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [] + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion", + "type": "Interface", + "tags": [], + "label": "VisualizationSuggestion", + "description": [ + "\nA possible configuration of a given visualization. It is based on a `TableSuggestion`.\nSuggestion might be shown in the UI to be chosen by the user directly, but they are\nalso applied directly under some circumstances (dragging in the first field from the data\npanel or switching to another visualization in the chart switcher)." + ], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.VisualizationSuggestion", + "text": "VisualizationSuggestion" + }, + "" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion.score", + "type": "number", + "tags": [], + "label": "score", + "description": [ + "\nThe score of a suggestion should indicate how valuable the suggestion is. It is used\nto rank multiple suggestions of multiple visualizations. The number should be between 0 and 1" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion.hide", + "type": "CompoundType", + "tags": [], + "label": "hide", + "description": [ + "\nFlag indicating whether this suggestion should not be advertised to the user. It is still\nconsidered in scenarios where the available suggestion with the highest suggestion is applied\ndirectly." + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion.incomplete", + "type": "CompoundType", + "tags": [], + "label": "incomplete", + "description": [ + "\nFlag indicating whether this suggestion is incomplete" + ], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion.title", + "type": "string", + "tags": [], + "label": "title", + "description": [ + "\nDescriptive title of the suggestion. Should be as short as possible. This title is shown if\nthe suggestion is advertised to the user and will also show either the `previewExpression` or\nthe `previewIcon`" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion.state", + "type": "Uncategorized", + "tags": [], + "label": "state", + "description": [ + "\nThe new state of the visualization if this suggestion is applied." + ], + "signature": [ + "T" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.VisualizationSuggestion.previewIcon", + "type": "CompoundType", + "tags": [], + "label": "previewIcon", + "description": [ + "\nAn EUI icon type shown instead of the preview expression." + ], + "signature": [ + "string | React.ComponentType<{}>" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs", + "type": "Interface", + "tags": [], + "label": "XYArgs", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XYArgs", + "text": "XYArgs" + }, + " extends ", + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.DataLayerArgs", + "text": "DataLayerArgs" + } + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.legend", + "type": "CompoundType", + "tags": [], + "label": "legend", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.LegendConfig", + "text": "LegendConfig" + }, + " & { type: \"legendConfig\"; }" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.endValue", + "type": "CompoundType", + "tags": [], + "label": "endValue", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.EndValue", + "text": "EndValue" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.emphasizeFitting", + "type": "CompoundType", + "tags": [], + "label": "emphasizeFitting", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.valueLabels", + "type": "CompoundType", + "tags": [], + "label": "valueLabels", + "description": [], + "signature": [ + "\"hide\" | \"show\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.referenceLines", + "type": "Array", + "tags": [], + "label": "referenceLines", + "description": [], + "signature": [ + "ReferenceLineConfigResult", + "[]" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.fittingFunction", + "type": "CompoundType", + "tags": [], + "label": "fittingFunction", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.FittingFunction", + "text": "FittingFunction" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.fillOpacity", + "type": "number", + "tags": [], + "label": "fillOpacity", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.hideEndzones", + "type": "CompoundType", + "tags": [], + "label": "hideEndzones", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.ariaLabel", + "type": "string", + "tags": [], + "label": "ariaLabel", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.yAxisConfigs", + "type": "Array", + "tags": [], + "label": "yAxisConfigs", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.YAxisConfigResult", + "text": "YAxisConfigResult" + }, + "[] | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.xAxisConfig", + "type": "CompoundType", + "tags": [], + "label": "xAxisConfig", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XAxisConfigResult", + "text": "XAxisConfigResult" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.addTimeMarker", + "type": "CompoundType", + "tags": [], + "label": "addTimeMarker", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.markSizeRatio", + "type": "number", + "tags": [], + "label": "markSizeRatio", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.minTimeBarInterval", + "type": "string", + "tags": [], + "label": "minTimeBarInterval", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.minBarHeight", + "type": "number", + "tags": [], + "label": "minBarHeight", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.splitRowAccessor", + "type": "CompoundType", + "tags": [], + "label": "splitRowAccessor", + "description": [], + "signature": [ + "string | ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.ExpressionValueVisDimension", + "text": "ExpressionValueVisDimension" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.splitColumnAccessor", + "type": "CompoundType", + "tags": [], + "label": "splitColumnAccessor", + "description": [], + "signature": [ + "string | ", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.ExpressionValueVisDimension", + "text": "ExpressionValueVisDimension" + }, + " | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.detailedTooltip", + "type": "CompoundType", + "tags": [], + "label": "detailedTooltip", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.orderBucketsBySum", + "type": "CompoundType", + "tags": [], + "label": "orderBucketsBySum", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYArgs.showTooltip", + "type": "boolean", + "tags": [], + "label": "showTooltip", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps", + "type": "Interface", + "tags": [], + "label": "XYChartProps", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps.args", + "type": "Object", + "tags": [], + "label": "args", + "description": [], + "signature": [ + "XYProps" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps.syncTooltips", + "type": "boolean", + "tags": [], + "label": "syncTooltips", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps.syncCursor", + "type": "boolean", + "tags": [], + "label": "syncCursor", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps.syncColors", + "type": "boolean", + "tags": [], + "label": "syncColors", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps.canNavigateToLens", + "type": "CompoundType", + "tags": [], + "label": "canNavigateToLens", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYChartProps.overrides", + "type": "CompoundType", + "tags": [], + "label": "overrides", + "description": [], + "signature": [ + "(Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> & Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> & Partial>) | undefined" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig", + "type": "Interface", + "tags": [], + "label": "XYDataLayerConfig", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.accessors", + "type": "Array", + "tags": [], + "label": "accessors", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.layerType", + "type": "string", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"data\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.seriesType", + "type": "CompoundType", + "tags": [], + "label": "seriesType", + "description": [], + "signature": [ + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.xAccessor", + "type": "string", + "tags": [], + "label": "xAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.simpleView", + "type": "CompoundType", + "tags": [], + "label": "simpleView", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.yConfig", + "type": "Array", + "tags": [], + "label": "yConfig", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.YConfig", + "text": "YConfig" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.splitAccessor", + "type": "string", + "tags": [], + "label": "splitAccessor", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.palette", + "type": "Object", + "tags": [], + "label": "palette", + "description": [], + "signature": [ + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.collapseFn", + "type": "CompoundType", + "tags": [], + "label": "collapseFn", + "description": [], + "signature": [ + "CollapseFunction", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.xScaleType", + "type": "CompoundType", + "tags": [], + "label": "xScaleType", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XScaleType", + "text": "XScaleType" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.isHistogram", + "type": "CompoundType", + "tags": [], + "label": "isHistogram", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.columnToLabel", + "type": "string", + "tags": [], + "label": "columnToLabel", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYDataLayerConfig.colorMapping", + "type": "Object", + "tags": [], + "label": "colorMapping", + "description": [], + "signature": [ + "Config", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYReferenceLineLayerConfig", + "type": "Interface", + "tags": [], + "label": "XYReferenceLineLayerConfig", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.XYReferenceLineLayerConfig.layerId", + "type": "string", + "tags": [], + "label": "layerId", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYReferenceLineLayerConfig.accessors", + "type": "Array", + "tags": [], + "label": "accessors", + "description": [], + "signature": [ + "string[]" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYReferenceLineLayerConfig.yConfig", + "type": "Array", + "tags": [], + "label": "yConfig", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.YConfig", + "text": "YConfig" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYReferenceLineLayerConfig.layerType", + "type": "string", + "tags": [], + "label": "layerType", + "description": [], + "signature": [ + "\"referenceLine\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYRender", + "type": "Interface", + "tags": [], + "label": "XYRender", + "description": [], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.XYRender.type", + "type": "string", + "tags": [], + "label": "type", + "description": [], + "signature": [ + "\"render\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYRender.as", + "type": "string", + "tags": [], + "label": "as", + "description": [], + "signature": [ + "\"xyVis\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYRender.value", + "type": "Object", + "tags": [], + "label": "value", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XYChartProps", + "text": "XYChartProps" + } + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState", + "type": "Interface", + "tags": [], + "label": "XYState", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.XYState.preferredSeriesType", + "type": "CompoundType", + "tags": [], + "label": "preferredSeriesType", + "description": [], + "signature": [ + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.legend", + "type": "Object", + "tags": [], + "label": "legend", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.LegendConfig", + "text": "LegendConfig" + } + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.valueLabels", + "type": "CompoundType", + "tags": [], + "label": "valueLabels", + "description": [], + "signature": [ + "ValueLabelConfig", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.fittingFunction", + "type": "CompoundType", + "tags": [], + "label": "fittingFunction", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.FittingFunction", + "text": "FittingFunction" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.emphasizeFitting", + "type": "CompoundType", + "tags": [], + "label": "emphasizeFitting", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.endValue", + "type": "CompoundType", + "tags": [], + "label": "endValue", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.EndValue", + "text": "EndValue" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.xExtent", + "type": "Object", + "tags": [], + "label": "xExtent", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.AxisExtentConfig", + "text": "AxisExtentConfig" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.yLeftExtent", + "type": "Object", + "tags": [], + "label": "yLeftExtent", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.AxisExtentConfig", + "text": "AxisExtentConfig" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.yRightExtent", + "type": "Object", + "tags": [], + "label": "yRightExtent", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.AxisExtentConfig", + "text": "AxisExtentConfig" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.layers", + "type": "Array", + "tags": [], + "label": "layers", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYLayerConfig", + "text": "XYLayerConfig" + }, + "[]" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.xTitle", + "type": "string", + "tags": [], + "label": "xTitle", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.yTitle", + "type": "string", + "tags": [], + "label": "yTitle", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.yRightTitle", + "type": "string", + "tags": [], + "label": "yRightTitle", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.yLeftScale", + "type": "CompoundType", + "tags": [], + "label": "yLeftScale", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.YScaleType", + "text": "YScaleType" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.yRightScale", + "type": "CompoundType", + "tags": [], + "label": "yRightScale", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.YScaleType", + "text": "YScaleType" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.axisTitlesVisibilitySettings", + "type": "Object", + "tags": [], + "label": "axisTitlesVisibilitySettings", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.AxesSettingsConfig", + "text": "AxesSettingsConfig" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.tickLabelsVisibilitySettings", + "type": "Object", + "tags": [], + "label": "tickLabelsVisibilitySettings", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.AxesSettingsConfig", + "text": "AxesSettingsConfig" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.gridlinesVisibilitySettings", + "type": "Object", + "tags": [], + "label": "gridlinesVisibilitySettings", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.AxesSettingsConfig", + "text": "AxesSettingsConfig" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.labelsOrientation", + "type": "Object", + "tags": [], + "label": "labelsOrientation", + "description": [], + "signature": [ + "LabelsOrientationConfig", + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.curveType", + "type": "CompoundType", + "tags": [], + "label": "curveType", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.XYCurveType", + "text": "XYCurveType" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.fillOpacity", + "type": "number", + "tags": [], + "label": "fillOpacity", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.minBarHeight", + "type": "number", + "tags": [], + "label": "minBarHeight", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.hideEndzones", + "type": "CompoundType", + "tags": [], + "label": "hideEndzones", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.XYState.showCurrentTimeMarker", + "type": "CompoundType", + "tags": [], + "label": "showCurrentTimeMarker", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig", + "type": "Interface", + "tags": [], + "label": "YConfig", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "lens", + "id": "def-public.YConfig.forAccessor", + "type": "string", + "tags": [], + "label": "forAccessor", + "description": [], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.color", + "type": "string", + "tags": [], + "label": "color", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.icon", + "type": "string", + "tags": [], + "label": "icon", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.lineWidth", + "type": "number", + "tags": [], + "label": "lineWidth", + "description": [], + "signature": [ + "number | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.lineStyle", + "type": "CompoundType", + "tags": [], + "label": "lineStyle", + "description": [], + "signature": [ + "\"dashed\" | \"solid\" | \"dotted\" | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.fill", + "type": "CompoundType", + "tags": [], + "label": "fill", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.FillStyle", + "text": "FillStyle" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.iconPosition", + "type": "CompoundType", + "tags": [], + "label": "iconPosition", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.IconPosition", + "text": "IconPosition" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.textVisibility", + "type": "CompoundType", + "tags": [], + "label": "textVisibility", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "lens", + "id": "def-public.YConfig.axisMode", + "type": "CompoundType", + "tags": [], + "label": "axisMode", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.YAxisMode", + "text": "YAxisMode" + }, + " | undefined" + ], + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", "deprecated": false, "trackAdoption": false } ], "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "lens", + "id": "def-public.AvgIndexPatternColumn", + "type": "Type", + "tags": [], + "label": "AvgIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " & { operationType: \"average\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisExtentConfigResult", + "type": "Type", + "tags": [], + "label": "AxisExtentConfigResult", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.AxisExtentConfig", + "text": "AxisExtentConfig" + }, + " & { type: \"axisExtentConfig\"; }" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.AxisExtentMode", + "type": "Type", + "tags": [], + "label": "AxisExtentMode", + "description": [], + "signature": [ + "\"custom\" | \"full\" | \"dataBounds\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.CounterRateIndexPatternColumn", + "type": "Type", + "tags": [], + "label": "CounterRateIndexPatternColumn", + "description": [], + "signature": [ + "FormattedIndexPatternColumn", + " & ", + "ReferenceBasedIndexPatternColumn", + " & { operationType: \"counter_rate\"; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/counter_rate.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.CountIndexPatternColumn", + "type": "Type", + "tags": [], + "label": "CountIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " & { operationType: \"count\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/count.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.CumulativeSumIndexPatternColumn", + "type": "Type", + "tags": [], + "label": "CumulativeSumIndexPatternColumn", + "description": [], + "signature": [ + "FormattedIndexPatternColumn", + " & ", + "ReferenceBasedIndexPatternColumn", + " & { operationType: \"cumulative_sum\"; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/cumulative_sum.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataLayerConfig", + "type": "Type", + "tags": [], + "label": "DataLayerConfig", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.DataLayerArgs", + "text": "DataLayerArgs" + }, + ", \"palette\"> & { type: \"dataLayer\"; layerType: \"data\"; palette: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }>; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; } & ", + "WithLayerId" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DataType", + "type": "Type", + "tags": [], + "label": "DataType", + "description": [], + "signature": [ + "\"string\" | \"number\" | \"boolean\" | \"date\" | ", + "FieldOnlyDataType" + ], + "path": "x-pack/plugins/lens/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.DerivativeIndexPatternColumn", + "type": "Type", + "tags": [], + "label": "DerivativeIndexPatternColumn", + "description": [], + "signature": [ + "FormattedIndexPatternColumn", + " & ", + "ReferenceBasedIndexPatternColumn", + " & { operationType: \"differences\"; }" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/differences.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.EmbeddableComponent", + "type": "Type", + "tags": [], + "label": "EmbeddableComponent", + "description": [], + "signature": [ + "React.ComponentClass<{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; disabledActions?: string[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" + }, + "> | undefined, dataLoading$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined) => void) | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }, any> | React.FunctionComponent<{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; disabledActions?: string[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" + }, + "> | undefined, dataLoading$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined) => void) | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }>" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FillStyle", + "type": "Type", + "tags": [], + "label": "FillStyle", + "description": [], + "signature": [ + "\"none\" | \"above\" | \"below\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.FittingFunction", + "type": "Type", + "tags": [], + "label": "FittingFunction", + "description": [], + "signature": [ + "\"None\" | \"Average\" | \"Zero\" | \"Linear\" | \"Carry\" | \"Lookahead\" | \"Nearest\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.GaugeVisualizationState", + "type": "Type", + "tags": [], + "label": "GaugeVisualizationState", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "expressionGauge", + "scope": "common", + "docId": "kibExpressionGaugePluginApi", + "section": "def-common.GaugeState", + "text": "GaugeState" + }, + ", \"min\" | \"max\" | \"metric\" | \"goal\"> & { metricAccessor?: string | undefined; minAccessor?: string | undefined; maxAccessor?: string | undefined; goalAccessor?: string | undefined; } & { layerId: string; layerType: ", + "LayerType", + "; }" + ], + "path": "x-pack/plugins/lens/public/visualizations/gauge/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.GenericIndexPatternColumn", + "type": "Type", + "tags": [], + "label": "GenericIndexPatternColumn", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " | ", + "BaseIndexPatternColumn", + " | ", + "ReferenceBasedIndexPatternColumn" + ], + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.HeatmapVisualizationState", + "type": "Type", + "tags": [], + "label": "HeatmapVisualizationState", + "description": [], + "signature": [ + "Omit<", + { + "pluginId": "expressionHeatmap", + "scope": "common", + "docId": "kibExpressionHeatmapPluginApi", + "section": "def-common.HeatmapArguments", + "text": "HeatmapArguments" + }, + ", \"palette\"> & { layerId: string; layerType: ", + "LayerType", + "; valueAccessor?: string | undefined; xAccessor?: string | undefined; yAccessor?: string | undefined; shape: \"heatmap\"; } & { palette?: ", + "Palette", + " | undefined; }" + ], + "path": "x-pack/plugins/lens/public/visualizations/heatmap/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.IconPosition", + "type": "Type", + "tags": [], + "label": "IconPosition", + "description": [], + "signature": [ + "\"right\" | \"left\" | \"auto\" | \"above\" | \"below\"" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LayerType", + "type": "Type", + "tags": [], + "label": "LayerType", + "description": [], + "signature": [ + "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + ], + "path": "x-pack/plugins/lens/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LegendConfigResult", + "type": "Type", + "tags": [], + "label": "LegendConfigResult", + "description": [], + "signature": [ + { + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.LegendConfig", + "text": "LegendConfig" + }, + " & { type: \"legendConfig\"; }" + ], + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LENS_EMBEDDABLE_TYPE", + "type": "string", + "tags": [], + "label": "LENS_EMBEDDABLE_TYPE", + "description": [], + "signature": [ + "\"lens\"" + ], + "path": "x-pack/plugins/lens/common/constants.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensApi", + "type": "Type", + "tags": [], + "label": "LensApi", + "description": [], + "signature": [ + "{ uuid: string; panelTitle: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; hidePanelTitle: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; defaultPanelTitle?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; dataLoading: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; blockingError: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; panelDescription: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; defaultPanelDescription?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; disabledActionIds: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; setDisabledActionIds: (ids: string[] | undefined) => void; getAllTriggersDisabled?: (() => boolean) | undefined; parentApi?: (", + { + "pluginId": "@kbn/presentation-containers", + "scope": "public", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-public.PresentationContainer", + "text": "PresentationContainer" + }, + " & Partial & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesViewMode", + "text": "PublishesViewMode" + }, + ">) | undefined; hasLockedHoverActions$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; lockHoverActions?: ((lock: boolean) => void) | undefined; type: string; phase$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PhaseEvent", + "text": "PhaseEvent" + }, + " | undefined>; unsavedChanges?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; resetUnsavedChanges?: (() => void) | undefined; serializeState: () => ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.MaybePromise", + "text": "MaybePromise" + }, + "<", + { + "pluginId": "@kbn/presentation-containers", + "scope": "public", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-public.SerializedPanelState", + "text": "SerializedPanelState" + }, + "<{ attributes?: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; } | undefined; savedObjectId?: string | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; timeslice?: [number, number] | undefined; searchSessionId?: string | undefined; lastReloadRequestTime?: number | undefined; id?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; disableTriggers?: boolean | undefined; syncColors?: boolean | undefined; syncTooltips?: boolean | undefined; syncCursor?: boolean | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; isNewPanel?: boolean | undefined; }>>; snapshotRuntimeState: () => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; onEdit: () => Promise; isEditingEnabled: () => boolean; getEditHref?: (() => Promise) | undefined; getTypeDisplayName: () => string; getTypeDisplayNameLowerCase?: (() => string) | undefined; timeRange$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined>; timeRestore$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; timeslice$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<[number, number] | undefined> | undefined; filters$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined>; isCompatibleWithUnifiedSearch?: (() => boolean) | undefined; query$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined>; rendered$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; dataViews: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[] | undefined>; setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; setPanelDescription: (newTitle: string | undefined) => void; supportedTriggers: () => string[]; libraryId$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; saveToLibrary: ((title: string) => Promise) & ((title: string) => Promise); getByValueRuntimeSnapshot: () => object; unlinkFromLibrary: () => void; canLinkToLibrary: () => Promise; canUnlinkFromLibrary: () => Promise; checkForDuplicateTitle: (newTitle: string, isTitleDuplicateConfirmed: boolean, onTitleDuplicate: () => void) => Promise; getByReferenceState: (libraryId: string) => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; getByValueState: () => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; viewMode: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + ">; savedObjectId: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; getInspectorAdapters: () => ", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + "; inspect: (options?: ", + { + "pluginId": "inspector", + "scope": "public", + "docId": "kibInspectorPluginApi", + "section": "def-public.InspectorOptions", + "text": "InspectorOptions" + }, + " | undefined) => ", + { + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.OverlayRef", + "text": "OverlayRef" + }, + "; closeInspector: () => Promise; adapters$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + ">; abortController?: AbortController | undefined; canViewUnderlyingData$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; loadViewUnderlyingData: () => void; getViewUnderlyingDataArgs: () => ", + "ViewUnderlyingDataArgs", + " | undefined; isTextBasedLanguage: () => boolean | undefined; getTextBasedLanguage: () => string | undefined; getSavedVis: () => Readonly<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensSavedObjectAttributes", + "text": "LensSavedObjectAttributes" + }, + " | undefined>; getFullAttributes: () => ", + "LensDocument", + " | undefined; updateAttributes: (newAttributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }) => void; updateSavedObjectId: (newSavedObjectId: string | undefined) => void; updateOverrides: (newOverrides: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined) => void; getTriggerCompatibleActions: (triggerId: string, context: object) => Promise<", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[]>; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensByReferenceInput", + "type": "Type", + "tags": [], + "label": "LensByReferenceInput", + "description": [], + "signature": [ + "{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" + }, + "> | undefined, dataLoading$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined) => void) | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disabledActions?: string[] | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; withDefaultActions?: boolean | undefined; abortController?: AbortController | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensByValueInput", + "type": "Type", + "tags": [], + "label": "LensByValueInput", + "description": [ + "\nBackward compatibility types" + ], + "signature": [ + "{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" + }, + "> | undefined, dataLoading$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined) => void) | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; attributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disabledActions?: string[] | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; withDefaultActions?: boolean | undefined; abortController?: AbortController | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensEmbeddableInput", + "type": "Type", + "tags": [], + "label": "LensEmbeddableInput", + "description": [], + "signature": [ + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensByValueInput", + "text": "LensByValueInput" + }, + " | ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensByReferenceInput", + "text": "LensByReferenceInput" + } + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.OperationMetadata", - "type": "Interface", + "id": "def-public.LensEmbeddableOutput", + "type": "Type", "tags": [], - "label": "OperationMetadata", + "label": "LensEmbeddableOutput", "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "signature": [ + "{ uuid: string; panelTitle: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; hidePanelTitle: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; defaultPanelTitle?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; dataLoading: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; blockingError: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; panelDescription: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; defaultPanelDescription?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; disabledActionIds: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; setDisabledActionIds: (ids: string[] | undefined) => void; getAllTriggersDisabled?: (() => boolean) | undefined; parentApi?: (", + { + "pluginId": "@kbn/presentation-containers", + "scope": "public", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-public.PresentationContainer", + "text": "PresentationContainer" + }, + " & Partial & ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishesViewMode", + "text": "PublishesViewMode" + }, + ">) | undefined; hasLockedHoverActions$?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; lockHoverActions?: ((lock: boolean) => void) | undefined; type: string; phase$: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PhaseEvent", + "text": "PhaseEvent" + }, + " | undefined>; unsavedChanges?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; resetUnsavedChanges?: (() => void) | undefined; serializeState: () => ", + { + "pluginId": "@kbn/utility-types", + "scope": "common", + "docId": "kibKbnUtilityTypesPluginApi", + "section": "def-common.MaybePromise", + "text": "MaybePromise" + }, + "<", + { + "pluginId": "@kbn/presentation-containers", + "scope": "public", + "docId": "kibKbnPresentationContainersPluginApi", + "section": "def-public.SerializedPanelState", + "text": "SerializedPanelState" + }, + "<{ attributes?: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; } | undefined; savedObjectId?: string | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.OperationMetadata.interval", - "type": "string", - "tags": [], - "label": "interval", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.OperationMetadata.dataType", - "type": "CompoundType", - "tags": [], - "label": "dataType", - "description": [], - "signature": [ - "\"string\" | \"number\" | \"boolean\" | \"date\" | ", - "FieldOnlyDataType" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.OperationMetadata.isBucketed", - "type": "boolean", - "tags": [], - "label": "isBucketed", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.OperationMetadata.scale", - "type": "CompoundType", - "tags": [], - "label": "scale", - "description": [ - "\nordinal: Each name is a unique value, but the names are in sorted order, like \"Top values\"\ninterval: Histogram data, like date or number histograms\nratio: Most number data is rendered as a ratio that includes 0" - ], - "signature": [ - "\"interval\" | \"ratio\" | \"ordinal\" | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; timeslice?: [number, number] | undefined; searchSessionId?: string | undefined; lastReloadRequestTime?: number | undefined; id?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; disableTriggers?: boolean | undefined; syncColors?: boolean | undefined; syncTooltips?: boolean | undefined; syncCursor?: boolean | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; isNewPanel?: boolean | undefined; }>>; snapshotRuntimeState: () => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.OperationMetadata.isStaticValue", - "type": "CompoundType", - "tags": [], - "label": "isStaticValue", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.PercentileIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "PercentileIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.PercentileIndexPatternColumn", - "text": "PercentileIndexPatternColumn" + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" }, - " extends ", + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", { - "pluginId": "lens", + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.PercentileIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"percentile\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.PercentileIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ percentile: number; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.PercentileRanksIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "PercentileRanksIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.PercentileRanksIndexPatternColumn", - "text": "PercentileRanksIndexPatternColumn" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, - " extends ", + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.PercentileRanksIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"percentile_rank\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile_ranks.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.PercentileRanksIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ value: number; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/percentile_ranks.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.PieVisualizationState", - "type": "Interface", - "tags": [], - "label": "PieVisualizationState", - "description": [], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; onEdit: () => Promise; isEditingEnabled: () => boolean; getEditHref?: (() => Promise) | undefined; getTypeDisplayName: () => string; getTypeDisplayNameLowerCase?: (() => string) | undefined; timeRange$: ", { - "parentPluginId": "lens", - "id": "def-public.PieVisualizationState.shape", - "type": "CompoundType", - "tags": [], - "label": "shape", - "description": [], - "signature": [ - "\"treemap\" | \"mosaic\" | \"waffle\" | \"pie\" | \"donut\"" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.PieVisualizationState.layers", - "type": "Array", - "tags": [], - "label": "layers", - "description": [], - "signature": [ - "PieLayerState", - "[]" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined>; timeRestore$?: ", { - "parentPluginId": "lens", - "id": "def-public.PieVisualizationState.palette", - "type": "Object", - "tags": [], - "label": "palette", - "description": [], - "signature": [ - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }> | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.RangeIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "RangeIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + " | undefined; timeslice$?: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.RangeIndexPatternColumn", - "text": "RangeIndexPatternColumn" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - " extends ", + "<[number, number] | undefined> | undefined; filters$: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - } - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", { - "parentPluginId": "lens", - "id": "def-public.RangeIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"range\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined>; isCompatibleWithUnifiedSearch?: (() => boolean) | undefined; query$: ", { - "parentPluginId": "lens", - "id": "def-public.RangeIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ type: ", - "MODES_TYPES", - "; maxBars: number | \"auto\"; ranges: ", - "RangeTypeLens", - "[]; format?: { id: string; params?: { decimals: number; } | undefined; } | undefined; includeEmptyRows?: boolean | undefined; parentFormat?: { id: string; params?: { id?: string | undefined; template?: string | undefined; replaceInfinity?: boolean | undefined; } | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/ranges/ranges.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerArgs", - "type": "Interface", - "tags": [], - "label": "ReferenceLineLayerArgs", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "<", { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerArgs.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerArgs.accessors", - "type": "Array", - "tags": [], - "label": "accessors", - "description": [], - "signature": [ - "string[]" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined>; rendered$: ", { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerArgs.columnToLabel", - "type": "string", - "tags": [], - "label": "columnToLabel", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; dataViews: ", { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerArgs.decorations", - "type": "Array", - "tags": [], - "label": "decorations", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.ReferenceLineDecorationConfigResult", - "text": "ReferenceLineDecorationConfigResult" - }, - "[] | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerArgs.table", - "type": "Object", - "tags": [], - "label": "table", - "description": [], - "signature": [ - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.Datatable", - "text": "Datatable" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState", - "type": "Interface", - "tags": [], - "label": "SharedPieLayerState", - "description": [], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + "[] | undefined>; setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; setPanelDescription: (newTitle: string | undefined) => void; supportedTriggers: () => string[]; libraryId$: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.metrics", - "type": "Array", - "tags": [], - "label": "metrics", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; saveToLibrary: ((title: string) => Promise) & ((title: string) => Promise); getByValueRuntimeSnapshot: () => object; unlinkFromLibrary: () => void; canLinkToLibrary: () => Promise; canUnlinkFromLibrary: () => Promise; checkForDuplicateTitle: (newTitle: string, isTitleDuplicateConfirmed: boolean, onTitleDuplicate: () => void) => Promise; getByReferenceState: (libraryId: string) => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.primaryGroups", - "type": "Array", - "tags": [], - "label": "primaryGroups", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.allowMultipleMetrics", - "type": "CompoundType", - "tags": [], - "label": "allowMultipleMetrics", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<{ duration: number; } | undefined>; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "RecursivePartial", + "> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.numberDisplay", - "type": "CompoundType", - "tags": [], - "label": "numberDisplay", - "description": [], - "signature": [ - "\"value\" | \"hidden\" | \"percent\"" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.categoryDisplay", - "type": "CompoundType", - "tags": [], - "label": "categoryDisplay", - "description": [], - "signature": [ - "\"default\" | \"inside\" | \"hide\"" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.legendDisplay", - "type": "CompoundType", - "tags": [], - "label": "legendDisplay", - "description": [], - "signature": [ - "\"default\" | \"hide\" | \"show\"" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" }, + " | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.legendPosition", - "type": "CompoundType", - "tags": [], - "label": "legendPosition", - "description": [], - "signature": [ - "Position", - " | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.legendStats", - "type": "Array", - "tags": [], - "label": "legendStats", - "description": [], - "signature": [ - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.PartitionLegendValue", - "text": "PartitionLegendValue" - }, - "[] | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.nestedLegend", - "type": "CompoundType", - "tags": [], - "label": "nestedLegend", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.percentDecimals", - "type": "number", - "tags": [], - "label": "percentDecimals", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.emptySizeRatio", - "type": "number", - "tags": [], - "label": "emptySizeRatio", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.legendMaxLines", - "type": "number", - "tags": [], - "label": "legendMaxLines", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.truncateLegend", - "type": "CompoundType", - "tags": [], - "label": "truncateLegend", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.SharedPieLayerState.colorMapping", - "type": "Object", - "tags": [], - "label": "colorMapping", - "description": [], - "signature": [ - "Config", - " | undefined" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.StaticValueIndexPatternColumn", - "type": "Interface", - "tags": [], - "label": "StaticValueIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; getByValueState: () => { id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.StaticValueIndexPatternColumn", - "text": "StaticValueIndexPatternColumn" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, - " extends ", - "ReferenceBasedIndexPatternColumn" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx", - "deprecated": false, - "trackAdoption": false, - "children": [ + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.StaticValueIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"static_value\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.StaticValueIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ value?: string | undefined; format?: ", - "ValueFormatConfig", - " | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/static_value.tsx", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Suggestion", - "type": "Interface", - "tags": [], - "label": "Suggestion", - "description": [], - "signature": [ + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Suggestion", - "text": "Suggestion" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + " | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.visualizationId", - "type": "string", - "tags": [], - "label": "visualizationId", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.datasourceId", - "type": "string", - "tags": [], - "label": "datasourceId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.title", - "type": "string", - "tags": [], - "label": "title", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.visualizationState", - "type": "Uncategorized", - "tags": [], - "label": "visualizationState", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.previewExpression", - "type": "CompoundType", - "tags": [], - "label": "previewExpression", - "description": [], - "signature": [ - "string | ", - { - "pluginId": "@kbn/interpreter", - "scope": "common", - "docId": "kibKbnInterpreterPluginApi", - "section": "def-common.Ast", - "text": "Ast" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" }, + " | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.previewIcon", - "type": "CompoundType", - "tags": [], - "label": "previewIcon", - "description": [], - "signature": [ - "string | React.ComponentType<{}>" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.hide", - "type": "CompoundType", - "tags": [], - "label": "hide", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.incomplete", - "type": "CompoundType", - "tags": [], - "label": "incomplete", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.changeType", - "type": "CompoundType", - "tags": [], - "label": "changeType", - "description": [], - "signature": [ - "\"extended\" | \"layers\" | \"initial\" | \"unchanged\" | \"reduced\" | \"reorder\"" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Suggestion.keptLayerIds", - "type": "Array", - "tags": [], - "label": "keptLayerIds", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest", - "type": "Interface", - "tags": [], - "label": "SuggestionRequest", - "description": [ - "\nObject passed to `getSuggestions` of a visualization.\nIt contains a possible table the current datasource could\nprovide and the state of the visualization if it is currently active.\n\nIf the current datasource suggests multiple tables, `getSuggestions`\nis called multiple times with separate `SuggestionRequest` objects." - ], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.SuggestionRequest", - "text": "SuggestionRequest" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.table", - "type": "Object", - "tags": [], - "label": "table", - "description": [ - "\nA table configuration the datasource could provide." - ], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.TableSuggestion", - "text": "TableSuggestion" - } - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.mainPalette", - "type": "CompoundType", - "tags": [], - "label": "mainPalette", - "description": [ - "\nPassing the legacy palette or the new color mapping if available" - ], - "signature": [ - "{ type: \"legacyPalette\"; value: ", - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", - "Config", - "; } | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.isFromContext", - "type": "CompoundType", - "tags": [], - "label": "isFromContext", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }; viewMode: ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.keptLayerIds", - "type": "Array", - "tags": [], - "label": "keptLayerIds", - "description": [ - "\nThe visualization needs to know which table is being suggested" - ], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.subVisualizationId", - "type": "string", - "tags": [], - "label": "subVisualizationId", - "description": [ - "\nDifferent suggestions can be generated for each subtype of the visualization" - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + ">; savedObjectId: ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.activeData", - "type": "Object", - "tags": [], - "label": "activeData", - "description": [], - "signature": [ - "Record | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "; getInspectorAdapters: () => ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.allowMixed", - "type": "CompoundType", - "tags": [], - "label": "allowMixed", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" }, + "; inspect: (options?: ", { - "parentPluginId": "lens", - "id": "def-public.SuggestionRequest.datasourceId", - "type": "string", - "tags": [], - "label": "datasourceId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion", - "type": "Interface", - "tags": [], - "label": "TableSuggestion", - "description": [ - "\nA possible table a datasource can create. This object is passed to the visualization\nwhich tries to build a meaningful visualization given the shape of the table. If this\nis possible, the visualization returns a `VisualizationSuggestion` object" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion.isMultiRow", - "type": "boolean", - "tags": [], - "label": "isMultiRow", - "description": [ - "\nFlag indicating whether the table will include more than one column.\nThis is not the case for example for a single metric aggregation" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "inspector", + "scope": "public", + "docId": "kibInspectorPluginApi", + "section": "def-public.InspectorOptions", + "text": "InspectorOptions" }, + " | undefined) => ", { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion.columns", - "type": "Array", - "tags": [], - "label": "columns", - "description": [ - "\nThe columns of the table. Each column has to be mapped to a dimension in a chart. If a visualization\ncan't use all columns of a suggestion, it should not return a `VisualizationSuggestion` based on it\nbecause there would be unreferenced columns" - ], - "signature": [ - "TableSuggestionColumn", - "[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-mount-utils-browser", + "scope": "public", + "docId": "kibKbnCoreMountUtilsBrowserPluginApi", + "section": "def-public.OverlayRef", + "text": "OverlayRef" }, + "; closeInspector: () => Promise; adapters$: ", { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [ - "\nThe layer this table will replace. This is only relevant if the visualization this suggestion is passed\nis currently active and has multiple layers configured. If this suggestion is applied, the table of this\nlayer will be replaced by the columns specified in this suggestion" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + "<", { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion.label", - "type": "string", - "tags": [], - "label": "label", - "description": [ - "\nA label describing the table. This can be used to provide a title for the `VisualizationSuggestion`,\nbut the visualization can also decide to overwrite it." - ], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" }, + ">; abortController?: AbortController | undefined; canViewUnderlyingData$: ", { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion.changeType", - "type": "CompoundType", - "tags": [], - "label": "changeType", - "description": [ - "\nThe change type indicates what was changed in this table compared to the currently active table of this layer." - ], - "signature": [ - "\"extended\" | \"layers\" | \"initial\" | \"unchanged\" | \"reduced\" | \"reorder\"" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" + }, + "; loadViewUnderlyingData: () => void; getViewUnderlyingDataArgs: () => ", + "ViewUnderlyingDataArgs", + " | undefined; isTextBasedLanguage: () => boolean | undefined; getTextBasedLanguage: () => string | undefined; getSavedVis: () => Readonly<", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.LensSavedObjectAttributes", + "text": "LensSavedObjectAttributes" }, + " | undefined>; getFullAttributes: () => ", + "LensDocument", + " | undefined; updateAttributes: (newAttributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.TableSuggestion.notAssignedMetrics", - "type": "CompoundType", - "tags": [], - "label": "notAssignedMetrics", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.TagcloudState", - "type": "Interface", - "tags": [], - "label": "TagcloudState", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.TagcloudState.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.TagcloudState.tagAccessor", - "type": "string", - "tags": [], - "label": "tagAccessor", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.TagcloudState.maxFontSize", - "type": "number", - "tags": [], - "label": "maxFontSize", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; }; references: ", { - "parentPluginId": "lens", - "id": "def-public.TagcloudState.minFontSize", - "type": "number", - "tags": [], - "label": "minFontSize", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string | null; }) => void; updateSavedObjectId: (newSavedObjectId: string | undefined) => void; updateOverrides: (newOverrides: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.TagcloudState.palette", - "type": "Object", - "tags": [], - "label": "palette", - "description": [], - "signature": [ - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }> | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/tagcloud/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.TermsIndexPatternColumn", - "text": "TermsIndexPatternColumn" + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, - " extends ", + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "pluginId": "lens", + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined) => void; getTriggerCompatibleActions: (triggerId: string, context: object) => Promise<", + { + "pluginId": "uiActions", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - } + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[]>; }" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/types.ts", + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", "deprecated": false, "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.TermsIndexPatternColumn.operationType", - "type": "string", - "tags": [], - "label": "operationType", - "description": [], - "signature": [ - "\"terms\"" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.TermsIndexPatternColumn.params", - "type": "Object", - "tags": [], - "label": "params", - "description": [], - "signature": [ - "{ size: number; accuracyMode?: boolean | undefined; include?: string[] | number[] | undefined; exclude?: string[] | number[] | undefined; includeIsRegex?: boolean | undefined; excludeIsRegex?: boolean | undefined; orderBy: { type: \"alphabetical\"; fallback?: boolean | undefined; } | { type: \"rare\"; maxDocCount: number; } | { type: \"significant\"; } | { type: \"column\"; columnId: string; } | { type: \"custom\"; }; orderAgg?: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - }, - " | undefined; orderDirection: \"asc\" | \"desc\"; otherBucket?: boolean | undefined; missingBucket?: boolean | undefined; secondaryFields?: string[] | undefined; format?: ", - "ValueFormatConfig", - " | undefined; parentFormat?: { id: string; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/terms/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.UserMessage", - "type": "Interface", + "id": "def-public.LensRendererProps", + "type": "Type", "tags": [], - "label": "UserMessage", + "label": "LensRendererProps", "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "signature": [ + "{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "parentPluginId": "lens", - "id": "def-public.UserMessage.uniqueId", - "type": "string", - "tags": [], - "label": "uniqueId", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.UserMessage.severity", - "type": "CompoundType", - "tags": [], - "label": "severity", - "description": [], - "signature": [ - "\"error\" | \"info\" | \"warning\"" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, + " | undefined; query?: ", { - "parentPluginId": "lens", - "id": "def-public.UserMessage.hidePopoverIcon", - "type": "CompoundType", - "tags": [], - "label": "hidePopoverIcon", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.UserMessage.shortMessage", - "type": "string", - "tags": [], - "label": "shortMessage", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + " | undefined; filters?: ", { - "parentPluginId": "lens", - "id": "def-public.UserMessage.longMessage", - "type": "CompoundType", - "tags": [], - "label": "longMessage", - "description": [], - "signature": [ - "React.ReactNode | ((closePopover?: (() => void) | undefined) => React.ReactNode)" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[] | undefined; references?: ", { - "parentPluginId": "lens", - "id": "def-public.UserMessage.fixableInEditor", - "type": "boolean", - "tags": [], - "label": "fixableInEditor", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Visualization", - "text": "Visualization" + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.initialize", - "type": "Function", - "tags": [], - "label": "initialize", - "description": [ - "\nInitialize is allowed to modify the state stored in memory. The initialize function\nis called with a previous state in two cases:\n- Loading from a saved visualization\n- When using suggestions, the suggested state is passed in" - ], - "signature": [ - "{ (addNewLayer: () => string, nonPersistedState?: T | undefined, mainPalette?: { type: \"legacyPalette\"; value: ", - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", - "Config", - "; } | undefined): T; (addNewLayer: () => string, persistedState: P, mainPalette?: { type: \"legacyPalette\"; value: ", - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", - "Config", - "; } | undefined, annotationGroups?: ", - "AnnotationGroups", - " | undefined, references?: ", - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[] | undefined): T; }" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUsedDataView", - "type": "Function", - "tags": [], - "label": "getUsedDataView", - "description": [], - "signature": [ - "((state: T, layerId: string) => string | undefined) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUsedDataView.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUsedDataView.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUsedDataViews", - "type": "Function", - "tags": [], - "label": "getUsedDataViews", - "description": [ - "\nRetrieve the used DataViews in the visualization" - ], - "signature": [ - "((state?: T | undefined) => string[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUsedDataViews.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" }, + " | undefined; palette?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getMainPalette", - "type": "Function", - "tags": [], - "label": "getMainPalette", - "description": [], - "signature": [ - "((state: T) => { type: \"legacyPalette\"; value: ", - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }>; } | { type: \"colorMapping\"; value: ", - "Config", - "; } | undefined) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getMainPalette.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.triggers", - "type": "Array", - "tags": [], - "label": "triggers", - "description": [ - "\nSupported triggers of this visualization type when embedded somewhere" - ], - "signature": [ - "string[] | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.visualizationTypes", - "type": "Array", - "tags": [], - "label": "visualizationTypes", - "description": [ - "\nVisualizations must provide at least one type for the chart switcher,\nbut can register multiple subtypes" - ], - "signature": [ - "VisualizationType", - "[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getVisualizationTypeId", - "type": "Function", - "tags": [], - "label": "getVisualizationTypeId", - "description": [ - "\nReturn the ID of the current visualization. Used to highlight\nthe active subtype of the visualization." - ], - "signature": [ - "(state: T, layerId?: string | undefined) => string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getVisualizationTypeId.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getVisualizationTypeId.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.hideFromChartSwitch", - "type": "Function", - "tags": [], - "label": "hideFromChartSwitch", - "description": [], - "signature": [ - "((frame: ", - "FramePublicAPI", - ") => boolean) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.hideFromChartSwitch.$1", - "type": "Object", - "tags": [], - "label": "frame", - "description": [], - "signature": [ - "FramePublicAPI" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.switchVisualizationType", - "type": "Function", - "tags": [], - "label": "switchVisualizationType", - "description": [ - "\nIf the visualization has subtypes, update the subtype in state." - ], - "signature": [ - "((visualizationTypeId: string, state: T, layerId?: string | undefined) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.switchVisualizationType.$1", - "type": "string", - "tags": [], - "label": "visualizationTypeId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.switchVisualizationType.$2", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.switchVisualizationType.$3", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record { icon?: ", - "IconType", - " | undefined; label: string; }" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getDescription.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getDescription.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" + }, + "> | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getPersistableState", - "type": "Function", - "tags": [], - "label": "getPersistableState", - "description": [ - "Visualizations can have references as well" - ], - "signature": [ - "((state: T) => { state: P; savedObjectReferences: ", - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[]; }) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getPersistableState.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayerIds", - "type": "Function", - "tags": [], - "label": "getLayerIds", - "description": [ - "Frame needs to know which layers the visualization is currently using" - ], - "signature": [ - "(state: T) => string[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayerIds.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.clearLayer", - "type": "Function", - "tags": [], - "label": "clearLayer", - "description": [ - "Reset button on each layer triggers this" - ], - "signature": [ - "(state: T, layerId: string, indexPatternId: string) => T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.clearLayer.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.clearLayer.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.clearLayer.$3", - "type": "string", - "tags": [], - "label": "indexPatternId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.cloneLayer", - "type": "Function", - "tags": [], - "label": "cloneLayer", - "description": [ - "Reset button on each layer triggers this" - ], - "signature": [ - "((state: T, layerId: string, newLayerId: string, clonedIDsMap: Map) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.cloneLayer.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.cloneLayer.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.cloneLayer.$3", - "type": "string", - "tags": [], - "label": "newLayerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.cloneLayer.$4", - "type": "Object", - "tags": [], - "label": "clonedIDsMap", - "description": [], - "signature": [ - "Map" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.removeLayer", - "type": "Function", - "tags": [], - "label": "removeLayer", - "description": [ - "Optional, if the visualization supports multiple layers" - ], - "signature": [ - "((state: T, layerId: string) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.removeLayer.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.removeLayer.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer", - "type": "Function", - "tags": [], - "label": "appendLayer", - "description": [ - "Track added layers in internal state" - ], - "signature": [ - "((state: T, layerId: string, type: ", - "LayerType", - ", indexPatternId: string, extraArg?: ExtraAppendLayerArg | undefined, seriesType?: ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.SeriesType", - "text": "SeriesType" - }, - " | undefined) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer.$3", - "type": "CompoundType", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "LayerType" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer.$4", - "type": "string", - "tags": [], - "label": "indexPatternId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer.$5", - "type": "Uncategorized", - "tags": [], - "label": "extraArg", - "description": [], - "signature": [ - "ExtraAppendLayerArg | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.appendLayer.$6", - "type": "CompoundType", - "tags": [], - "label": "seriesType", - "description": [], - "signature": [ - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.SeriesType", - "text": "SeriesType" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined) => ", - "VisualizationLayerDescription", - "[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedLayers.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedLayers.$2", - "type": "Object", - "tags": [], - "label": "frame", - "description": [], - "signature": [ - "Pick<", - "FramePublicAPI", - ", \"activeData\" | \"datasourceLayers\"> | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedActionsForLayer", - "type": "Function", - "tags": [], - "label": "getSupportedActionsForLayer", - "description": [ - "\nreturns a list of custom actions supported by the visualization layer.\nDefault actions like delete/clear are not included in this list and are managed by the editor frame" - ], - "signature": [ - "((layerId: string, state: T, setState: ", - "StateSetter", - ", registerLibraryAnnotationGroup: ", - "RegisterLibraryAnnotationGroupFunction", - ", isSaveable?: boolean | undefined) => ", - "LayerAction", - "[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedActionsForLayer.$1", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedActionsForLayer.$2", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedActionsForLayer.$3", - "type": "Function", - "tags": [], - "label": "setState", - "description": [], - "signature": [ - "StateSetter", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedActionsForLayer.$4", - "type": "Function", - "tags": [], - "label": "registerLibraryAnnotationGroup", - "description": [], - "signature": [ - "RegisterLibraryAnnotationGroupFunction" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSupportedActionsForLayer.$5", - "type": "CompoundType", - "tags": [], - "label": "isSaveable", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getCustomRemoveLayerText", - "type": "Function", - "tags": [], - "label": "getCustomRemoveLayerText", - "description": [ - "\nThis method is a clunky solution to the problem, but I'm banking on the confirm modal being removed\nwith undo/redo anyways" - ], - "signature": [ - "((layerId: string, state: T) => { title?: string | undefined; description?: string | undefined; } | undefined) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getCustomRemoveLayerText.$1", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getCustomRemoveLayerText.$2", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record ", - "LayerType", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayerType.$1", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayerType.$2", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayersToLinkTo", - "type": "Function", - "tags": [], - "label": "getLayersToLinkTo", - "description": [ - "\nGet the layers this one should be linked to (currently that means just keeping the data view in sync)" - ], - "signature": [ - "((state: T, newLayerId: string) => string[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayersToLinkTo.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayersToLinkTo.$2", - "type": "string", - "tags": [], - "label": "newLayerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLinkedDimensions", - "type": "Function", - "tags": [], - "label": "getLinkedDimensions", - "description": [ - "\nReturns a set of dimensions that should be kept in sync" - ], - "signature": [ - "((state: T) => DimensionLink[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLinkedDimensions.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getRemoveOperation", - "type": "Function", - "tags": [], - "label": "getRemoveOperation", - "description": [], - "signature": [ - "((state: T, layerId: string) => \"clear\" | \"remove\") | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getRemoveOperation.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getRemoveOperation.$2", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getConfiguration", - "type": "Function", - "tags": [], - "label": "getConfiguration", - "description": [ - "\nFor consistency across different visualizations, the dimension configuration UI is standardized" - ], - "signature": [ - "(props: ", - "VisualizationConfigProps", - ") => { hidden?: boolean | undefined; groups: ", - "VisualizationDimensionGroupConfig", - "[]; }" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getConfiguration.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationConfigProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.isSubtypeCompatible", - "type": "Function", - "tags": [], - "label": "isSubtypeCompatible", - "description": [], - "signature": [ - "((subtype1?: string | undefined, subtype2?: string | undefined) => boolean) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isSubtypeCompatible.$1", - "type": "string", - "tags": [], - "label": "subtype1", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isSubtypeCompatible.$2", - "type": "string", - "tags": [], - "label": "subtype2", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record) => React.ReactElement<", - "VisualizationLayerWidgetProps", - ", string | React.JSXElementConstructor> | undefined) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getCustomLayerHeader.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationLayerWidgetProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSubtypeSwitch", - "type": "Function", - "tags": [], - "label": "getSubtypeSwitch", - "description": [], - "signature": [ - "((props: ", - "VisualizationLayerWidgetProps", - ") => (() => JSX.Element) | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSubtypeSwitch.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationLayerWidgetProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.LayerPanelComponent", - "type": "Function", - "tags": [], - "label": "LayerPanelComponent", - "description": [ - "\nLayer panel content rendered. This can be used to render a custom content below the title,\nlike a custom dataview switch" - ], - "signature": [ - "((props: ", - "VisualizationLayerWidgetProps", - ") => React.ReactElement<", - "VisualizationLayerWidgetProps", - ", string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.LayerPanelComponent.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationLayerWidgetProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.ToolbarComponent", - "type": "Function", - "tags": [], - "label": "ToolbarComponent", - "description": [ - "\nToolbar rendered above the visualization. This is meant to be used to provide chart-level\nsettings for the visualization." - ], - "signature": [ - "((props: ", - "VisualizationToolbarProps", - ") => React.ReactElement<", - "VisualizationToolbarProps", - ", string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.ToolbarComponent.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationToolbarProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.setDimension", - "type": "Function", - "tags": [], - "label": "setDimension", - "description": [ - "\nThe frame is telling the visualization to update or set a dimension based on user interaction\ngroupId is coming from the groupId provided in getConfiguration" - ], - "signature": [ - "(props: ", - "VisualizationDimensionChangeProps", - " & { groupId: string; previousColumn?: string | undefined; }) => T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.setDimension.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationDimensionChangeProps", - " & { groupId: string; previousColumn?: string | undefined; }" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.removeDimension", - "type": "Function", - "tags": [], - "label": "removeDimension", - "description": [ - "\nThe frame is telling the visualization to remove a dimension. The visualization needs to\nlook at its internal state to determine which dimension is being affected." - ], - "signature": [ - "(props: ", - "VisualizationDimensionChangeProps", - ") => T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.removeDimension.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationDimensionChangeProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop", - "type": "Function", - "tags": [], - "label": "onDrop", - "description": [ - "\nAllow defining custom behavior for the visualization when the drop action occurs." - ], - "signature": [ - "((props: { prevState: T; target: ", - "DragDropOperation", - "; source: ", - { - "pluginId": "@kbn/dom-drag-drop", - "scope": "common", - "docId": "kibKbnDomDragDropPluginApi", - "section": "def-common.DragDropIdentifier", - "text": "DragDropIdentifier" - }, - "; frame: ", - "FramePublicAPI", - "; dropType: ", - { - "pluginId": "@kbn/dom-drag-drop", - "scope": "common", - "docId": "kibKbnDomDragDropPluginApi", - "section": "def-common.DropType", - "text": "DropType" - }, - "; group?: ", - "VisualizationDimensionGroupConfig", - " | undefined; }) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1.prevState", - "type": "Uncategorized", - "tags": [], - "label": "prevState", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1.target", - "type": "Object", - "tags": [], - "label": "target", - "description": [], - "signature": [ - "DragDropOperation" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1.source", - "type": "CompoundType", - "tags": [], - "label": "source", - "description": [], - "signature": [ - "Record & { id: string; humanData: ", - "HumanData", - "; }" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1.frame", - "type": "Object", - "tags": [], - "label": "frame", - "description": [], - "signature": [ - "FramePublicAPI" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1.dropType", - "type": "CompoundType", - "tags": [], - "label": "dropType", - "description": [], - "signature": [ - "\"reorder\" | \"field_add\" | \"field_replace\" | \"move_compatible\" | \"replace_compatible\" | \"move_incompatible\" | \"replace_incompatible\" | \"replace_duplicate_compatible\" | \"duplicate_compatible\" | \"swap_compatible\" | \"replace_duplicate_incompatible\" | \"duplicate_incompatible\" | \"swap_incompatible\" | \"field_combine\" | \"combine_compatible\" | \"combine_incompatible\"" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDrop.$1.group", - "type": "CompoundType", - "tags": [], - "label": "group", - "description": [], - "signature": [ - "VisualizationDimensionGroupConfig", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; abortController?: AbortController | undefined; noPadding?: boolean | undefined; withDefaultActions?: boolean | undefined; extraActions?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getDropProps", - "type": "Function", - "tags": [], - "label": "getDropProps", - "description": [], - "signature": [ - "((dropProps: ", - "GetDropPropsArgs", - ") => { dropTypes: ", - { - "pluginId": "@kbn/dom-drag-drop", - "scope": "common", - "docId": "kibKbnDomDragDropPluginApi", - "section": "def-common.DropType", - "text": "DropType" - }, - "[]; nextLabel?: string | undefined; } | undefined) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getDropProps.$1", - "type": "Object", - "tags": [], - "label": "dropProps", - "description": [], - "signature": [ - "GetDropPropsArgs", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" }, + "[] | undefined; disabledActions?: string[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onBrushEnd?: ((data: { table: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.hasLayerSettings", - "type": "Function", - "tags": [], - "label": "hasLayerSettings", - "description": [ - "\nAllows the visualization to announce whether or not it has any settings to show" - ], - "signature": [ - "((props: ", - "VisualizationConfigProps", - ") => Record<\"data\" | \"appearance\", boolean>) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.hasLayerSettings.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationConfigProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", { - "parentPluginId": "lens", - "id": "def-public.Visualization.LayerSettingsComponent", - "type": "Function", - "tags": [], - "label": "LayerSettingsComponent", - "description": [], - "signature": [ - "((props: ", - "VisualizationConfigProps", - " & { setState(newState: T | ((currState: T) => T)): void; panelRef: React.MutableRefObject; } & { section: \"data\" | \"appearance\"; }) => React.ReactElement<", - "VisualizationLayerSettingsProps", - ", string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.LayerSettingsComponent.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationConfigProps", - " & { setState(newState: T | ((currState: T) => T)): void; panelRef: React.MutableRefObject; } & { section: \"data\" | \"appearance\"; }" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" }, + "> | undefined, dataLoading$?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionEditorComponent", - "type": "Function", - "tags": [], - "label": "DimensionEditorComponent", - "description": [ - "\nAdditional editor that gets rendered inside the dimension popover in the \"appearance\" section.\nThis can be used to configure dimension-specific options" - ], - "signature": [ - "((props: ", - "VisualizationDimensionEditorProps", - ") => React.ReactElement<", - "VisualizationDimensionEditorProps", - ", string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionEditorComponent.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationDimensionEditorProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, + " | undefined) => void) | undefined; onFilter?: ((data: { data: { table: Pick<", { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionEditorAdditionalSectionComponent", - "type": "Function", - "tags": [], - "label": "DimensionEditorAdditionalSectionComponent", - "description": [ - "\nAdditional editor that gets rendered inside the dimension popover in an additional section below \"appearance\".\nThis can be used to configure dimension-specific options" - ], - "signature": [ - "((props: ", - "VisualizationDimensionEditorProps", - ") => React.ReactElement<", - "VisualizationDimensionEditorProps", - ", string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionEditorAdditionalSectionComponent.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationDimensionEditorProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionEditorDataExtraComponent", - "type": "Function", - "tags": [], - "label": "DimensionEditorDataExtraComponent", - "description": [ - "\nAdditional editor that gets rendered inside the data section.\nThis can be used to configure dimension-specific options" - ], - "signature": [ - "((props: ", - "VisualizationDimensionEditorProps", - ") => React.ReactElement<", - "VisualizationDimensionEditorProps", - ", string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionEditorDataExtraComponent.$1", - "type": "CompoundType", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationDimensionEditorProps", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionTriggerComponent", - "type": "Function", - "tags": [], - "label": "DimensionTriggerComponent", - "description": [ - "\nRenders dimension trigger. Used only for noDatasource layers" - ], - "signature": [ - "((props: { columnId: string; label: string; }) => React.ReactElement<{ columnId: string; label: string; }, string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionTriggerComponent.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionTriggerComponent.$1.columnId", - "type": "string", - "tags": [], - "label": "columnId", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.DimensionTriggerComponent.$1.label", - "type": "string", - "tags": [], - "label": "label", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" }, + "[]) => ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getAddLayerButtonComponent", - "type": "Function", - "tags": [], - "label": "getAddLayerButtonComponent", - "description": [], - "signature": [ - "((props: AddLayerButtonProps) => React.ReactElement, string | React.JSXElementConstructor> | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getAddLayerButtonComponent.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "AddLayerButtonProps" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" }, + "[]) | undefined; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensRuntimeState", + "type": "Type", + "tags": [], + "label": "LensRuntimeState", + "description": [ + "\nThe LensRuntimeState is the state stored for a dashboard panel\nthat contains:\n* Lens document state\n* Panel settings\n* other props from the embeddable" + ], + "signature": [ + "{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; description?: string | undefined; viewMode?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUniqueLabels", - "type": "Function", - "tags": [], - "label": "getUniqueLabels", - "description": [ - "\nCreates map of columns ids and unique lables. Used only for noDatasource layers" - ], - "signature": [ - "((state: T) => Record) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUniqueLabels.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" }, + " | undefined; timeRange?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSuggestions", - "type": "Function", - "tags": [], - "label": "getSuggestions", - "description": [ - "\nThe frame will call this function on all visualizations at different times. The\nmain use cases where visualization suggestions are requested are:\n- When dragging a field\n- When opening the chart switcher\nIf the state is provided when requesting suggestions, the visualization is active.\nMost visualizations will apply stricter filtering to suggestions when they are active,\nbecause suggestions have the potential to remove the users's work in progress." - ], - "signature": [ - "(context: ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.SuggestionRequest", - "text": "SuggestionRequest" - }, - ") => ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.VisualizationSuggestion", - "text": "VisualizationSuggestion" - }, - "[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSuggestions.$1", - "type": "Object", - "tags": [], - "label": "context", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.SuggestionRequest", - "text": "SuggestionRequest" - }, - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.toExpression", - "type": "Function", - "tags": [], - "label": "toExpression", - "description": [], - "signature": [ - "(state: T, datasourceLayers: Partial>, attributes?: Partial<{ title: string; description: string; }> | undefined, datasourceExpressionsByLayers?: Record | undefined) => string | ", - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.ExpressionAstExpression", - "text": "ExpressionAstExpression" - }, - " | null" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toExpression.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toExpression.$2", - "type": "Object", - "tags": [], - "label": "datasourceLayers", - "description": [], - "signature": [ - "Partial>" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toExpression.$3", - "type": "Object", - "tags": [], - "label": "attributes", - "description": [], - "signature": [ - "Partial<{ title: string; description: string; }> | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toExpression.$4", - "type": "Object", - "tags": [], - "label": "datasourceExpressionsByLayers", - "description": [], - "signature": [ - "Record | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial>, datasourceExpressionsByLayers?: Record | undefined) => string | ", - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.ExpressionAstExpression", - "text": "ExpressionAstExpression" - }, - " | null) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toPreviewExpression.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toPreviewExpression.$2", - "type": "Object", - "tags": [], - "label": "datasourceLayers", - "description": [], - "signature": [ - "Partial>" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.toPreviewExpression.$3", - "type": "Object", - "tags": [], - "label": "datasourceExpressionsByLayers", - "description": [], - "signature": [ - "Record | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<{ duration: number; } | undefined>; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined>; title?: string | undefined; gridLine?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUserMessages", - "type": "Function", - "tags": [], - "label": "getUserMessages", - "description": [ - "\nThe frame will call this function on all visualizations at few stages (pre-build/build error) in order\nto provide more context to the error and show it to the user" - ], - "signature": [ - "((state: T, deps: { frame: ", - "FramePublicAPI", - "; }) => ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.UserMessage", - "text": "UserMessage" - }, - "[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUserMessages.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUserMessages.$2", - "type": "Object", - "tags": [], - "label": "deps", - "description": [], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getUserMessages.$2.frame", - "type": "Object", - "tags": [], - "label": "frame", - "description": [], - "signature": [ - "FramePublicAPI" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ] - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.onEditAction", - "type": "Function", - "tags": [], - "label": "onEditAction", - "description": [ - "\nOn Edit events the frame will call this to know what's going to be the next visualization state" - ], - "signature": [ - "((state: T, event: ", - "LensEditEvent", - ") => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onEditAction.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onEditAction.$2", - "type": "Object", - "tags": [], - "label": "event", - "description": [], - "signature": [ - "LensEditEvent", - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDatasourceUpdate", - "type": "Function", - "tags": [], - "label": "onDatasourceUpdate", - "description": [], - "signature": [ - "((state: T, frame?: ", - "FramePublicAPI", - " | undefined) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDatasourceUpdate.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onDatasourceUpdate.$2", - "type": "Object", - "tags": [], - "label": "frame", - "description": [], - "signature": [ - "FramePublicAPI", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; savedObjectId?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; isNewPanel?: boolean | undefined; attributes: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string | null; }; abortController?: AbortController | undefined; sharingSavedObjectProps?: ", + "SharingSavedObjectProps", + " | undefined; managed?: boolean | undefined; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensSavedObjectAttributes", + "type": "Type", + "tags": [], + "label": "LensSavedObjectAttributes", + "description": [], + "signature": [ + "{ title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternChange", - "type": "Function", - "tags": [], - "label": "onIndexPatternChange", - "description": [ - "\nSome visualization track indexPattern changes (i.e. annotations)\nThis method makes it aware of the change and produces a new updated state" - ], - "signature": [ - "((state: T, indexPatternId: string, layerId?: string | undefined) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternChange.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternChange.$2", - "type": "string", - "tags": [], - "label": "indexPatternId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternChange.$3", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternRename", - "type": "Function", - "tags": [], - "label": "onIndexPatternRename", - "description": [], - "signature": [ - "((state: T, oldIndexPatternId: string, newIndexPatternId: string) => T) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternRename.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternRename.$2", - "type": "string", - "tags": [], - "label": "oldIndexPatternId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.onIndexPatternRename.$3", - "type": "string", - "tags": [], - "label": "newIndexPatternId", - "description": [], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayersToRemoveOnIndexPatternChange", - "type": "Function", - "tags": [], - "label": "getLayersToRemoveOnIndexPatternChange", - "description": [], - "signature": [ - "((state: T) => string[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getLayersToRemoveOnIndexPatternChange.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record ", - "VisualizationDisplayOptions", - ") | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" + }, + "> | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; }" + ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "lens", + "id": "def-public.LensSerializedState", + "type": "Type", + "tags": [], + "label": "LensSerializedState", + "description": [ + "\nCompose together all the props and make them inspectable via Simplify\n\nThe LensSerializedState is the state stored for a dashboard panel\nthat contains:\n* Lens document state\n* Panel settings\n* other props from the embeddable" + ], + "signature": [ + "{ attributes?: { title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getRenderEventCounters", - "type": "Function", - "tags": [], - "label": "getRenderEventCounters", - "description": [ - "\nGet RenderEventCounters events for telemetry" - ], - "signature": [ - "((state: T) => string[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getRenderEventCounters.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; adHocDataViews?: Record ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Suggestion", - "text": "Suggestion" - }, - " | undefined) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getSuggestionFromConvertToLensContext.$1", - "type": "Object", - "tags": [], - "label": "props", - "description": [], - "signature": [ - "VisualizationStateFromContextChangeProps" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.isEqual", - "type": "Function", - "tags": [], - "label": "isEqual", - "description": [], - "signature": [ - "((state1: P, references1: ", - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[], state2: P, references2: ", - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[], annotationGroups: ", - "AnnotationGroups", - ") => boolean) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isEqual.$1", - "type": "Uncategorized", - "tags": [], - "label": "state1", - "description": [], - "signature": [ - "P" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isEqual.$2", - "type": "Array", - "tags": [], - "label": "references1", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isEqual.$3", - "type": "Uncategorized", - "tags": [], - "label": "state2", - "description": [], - "signature": [ - "P" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isEqual.$4", - "type": "Array", - "tags": [], - "label": "references2", - "description": [], - "signature": [ - { - "pluginId": "@kbn/core-saved-objects-common", - "scope": "common", - "docId": "kibKbnCoreSavedObjectsCommonPluginApi", - "section": "def-common.SavedObjectReference", - "text": "SavedObjectReference" - }, - "[]" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.isEqual.$5", - "type": "Object", - "tags": [], - "label": "annotationGroups", - "description": [], - "signature": [ - "AnnotationGroups" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; }; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string | null; } | undefined; savedObjectId?: string | undefined; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; overrides?: Partial> | Partial | ", + "RecursivePartial", + "<", + "Theme", + ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", + "Position", + " | ", + "LegendPositionConfig", + " | undefined; rotation?: ", + "Rotation", + " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", + "Rendering", + " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", + "MakeOverridesSerializable", + "<", + "ExternalPointerEventsSettings", + " | undefined>; pointBuffer?: ", + "MarkBuffer", + " | undefined; pointerUpdateTrigger?: ", + "PointerUpdateTrigger", + " | undefined; brushAxis?: ", + "BrushAxis", + " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", + "MakeOverridesSerializable", + "<", + "LegendValue", + "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", + "MakeOverridesSerializable", + "<", + "CustomXDomain", + " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", + "LegendStrategy", + " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> | Partial; actual?: number | undefined; base?: number | undefined; bandFillColor?: \"ignore\" | undefined; tickValueFormatter?: \"ignore\" | undefined; labelMajor?: string | ", + "GoalLabelAccessor", + " | undefined; labelMinor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMajor?: string | ", + "GoalLabelAccessor", + " | undefined; centralMinor?: string | ", + "GoalLabelAccessor", + " | undefined; angleStart?: number | undefined; angleEnd?: number | undefined; bandLabels?: ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getVisualizationInfo", - "type": "Function", - "tags": [], - "label": "getVisualizationInfo", - "description": [], - "signature": [ - "((state: T, frame?: ", - "FramePublicAPI", - " | undefined) => ", - "VisualizationInfo", - ") | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getVisualizationInfo.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getVisualizationInfo.$2", - "type": "Object", - "tags": [], - "label": "frame", - "description": [], - "signature": [ - "FramePublicAPI", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "; tooltipValueFormatter?: \"ignore\" | undefined; }>> | Partial { height: number; width: number; }) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getReportingLayout.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" }, + "<{ duration: number; } | undefined>; valueGetter?: ", + "ValueGetter", + " | undefined; fillOutside?: boolean | undefined; radiusOutside?: number | undefined; fillRectangleWidth?: number | undefined; fillRectangleHeight?: number | undefined; topGroove?: number | undefined; percentFormatter?: \"ignore\" | undefined; clockwiseSectors?: boolean | undefined; maxRowCount?: number | undefined; specialFirstInnermostSector?: boolean | undefined; smallMultiples?: string | undefined; drilldown?: boolean | undefined; }>> | Partial> | undefined, activeData?: ", - "TableInspectorAdapter", - " | undefined) => ", - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.Datatable", - "text": "Datatable" - }, - "[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getExportDatatables.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getExportDatatables.$2", - "type": "Object", - "tags": [], - "label": "datasourceLayers", - "description": [], - "signature": [ - "Partial> | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getExportDatatables.$3", - "type": "Object", - "tags": [], - "label": "activeData", - "description": [], - "signature": [ - "TableInspectorAdapter", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "RecursivePartial", + "> | undefined>; title?: string | undefined; gridLine?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + " | undefined>; position?: ", + "Position", + " | undefined; ticks?: number | undefined; domain?: ", + { + "pluginId": "@kbn/chart-expressions-common", + "scope": "common", + "docId": "kibKbnChartExpressionsCommonPluginApi", + "section": "def-common.MakeOverridesSerializable", + "text": "MakeOverridesSerializable" + }, + "<", + "YDomainRange", + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; query?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.Visualization.getTelemetryEventsOnSave", - "type": "Function", - "tags": [], - "label": "getTelemetryEventsOnSave", - "description": [ - "\nreturns array of telemetry events for the visualization on save" - ], - "signature": [ - "((state: T, prevState?: T | undefined) => string[]) | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getTelemetryEventsOnSave.$1", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - }, - { - "parentPluginId": "lens", - "id": "def-public.Visualization.getTelemetryEventsOnSave.$2", - "type": "Uncategorized", - "tags": [], - "label": "prevState", - "description": [], - "signature": [ - "T | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": false - } - ], - "returnComment": [] - } + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + " | undefined; timeRange?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" + }, + " | undefined; timeslice?: [number, number] | undefined; searchSessionId?: string | undefined; lastReloadRequestTime?: number | undefined; id?: string | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; disableTriggers?: boolean | undefined; syncColors?: boolean | undefined; syncTooltips?: boolean | undefined; syncCursor?: boolean | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; title?: string | undefined; description?: string | undefined; hidePanelTitles?: boolean | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; viewMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; isNewPanel?: boolean | undefined; }" ], + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", + "deprecated": false, + "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.VisualizationSuggestion", - "type": "Interface", + "id": "def-public.LensSuggestionsApi", + "type": "Type", "tags": [], - "label": "VisualizationSuggestion", - "description": [ - "\nA possible configuration of a given visualization. It is based on a `TableSuggestion`.\nSuggestion might be shown in the UI to be chosen by the user directly, but they are\nalso applied directly under some circumstances (dragging in the first field from the data\npanel or switching to another visualization in the chart switcher)." - ], + "label": "LensSuggestionsApi", + "description": [], "signature": [ + "(context: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.VisualizeFieldContext", + "text": "VisualizeFieldContext" + }, + " | ", + "VisualizeEditorContext", + "<", + { + "pluginId": "visualizations", + "scope": "common", + "docId": "kibVisualizationsPluginApi", + "section": "def-common.Configuration", + "text": "Configuration" + }, + ">, dataViews: ", + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + }, + ", excludedVisualizations?: string[] | undefined, preferredChartType?: ", + { + "pluginId": "@kbn/visualization-utils", + "scope": "common", + "docId": "kibKbnVisualizationUtilsPluginApi", + "section": "def-common.ChartType", + "text": "ChartType" + }, + " | undefined, preferredVisAttributes?: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.VisualizationSuggestion", - "text": "VisualizationSuggestion" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, - "" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.VisualizationSuggestion.hide", - "type": "CompoundType", - "tags": [], - "label": "hide", - "description": [ - "\nFlag indicating whether this suggestion should not be advertised to the user. It is still\nconsidered in scenarios where the available suggestion with the highest suggestion is applied\ndirectly." - ], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.VisualizationSuggestion.incomplete", - "type": "CompoundType", - "tags": [], - "label": "incomplete", - "description": [ - "\nFlag indicating whether this suggestion is incomplete" - ], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.VisualizationSuggestion.title", - "type": "string", - "tags": [], - "label": "title", - "description": [ - "\nDescriptive title of the suggestion. Should be as short as possible. This title is shown if\nthe suggestion is advertised to the user and will also show either the `previewExpression` or\nthe `previewIcon`" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.VisualizationSuggestion.state", - "type": "Uncategorized", - "tags": [], - "label": "state", - "description": [ - "\nThe new state of the visualization if this suggestion is applied." - ], - "signature": [ - "T" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.VisualizationSuggestion.previewIcon", - "type": "CompoundType", - "tags": [], - "label": "previewIcon", - "description": [ - "\nAn EUI icon type shown instead of the preview expression." - ], - "signature": [ - "string | React.ComponentType<{}>" - ], - "path": "x-pack/plugins/lens/public/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYArgs", - "type": "Interface", - "tags": [], - "label": "XYArgs", - "description": [], - "signature": [ + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XYArgs", - "text": "XYArgs" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - " extends ", + "; filters: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.DataLayerArgs", - "text": "DataLayerArgs" - } - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.endValue", - "type": "CompoundType", - "tags": [], - "label": "endValue", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.EndValue", - "text": "EndValue" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.emphasizeFitting", - "type": "CompoundType", - "tags": [], - "label": "emphasizeFitting", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.valueLabels", - "type": "CompoundType", - "tags": [], - "label": "valueLabels", - "description": [], - "signature": [ - "\"hide\" | \"show\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.referenceLines", - "type": "Array", - "tags": [], - "label": "referenceLines", - "description": [], - "signature": [ - "ReferenceLineConfigResult", - "[]" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.fittingFunction", - "type": "CompoundType", - "tags": [], - "label": "fittingFunction", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.FittingFunction", - "text": "FittingFunction" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.fillOpacity", - "type": "number", - "tags": [], - "label": "fillOpacity", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.hideEndzones", - "type": "CompoundType", - "tags": [], - "label": "hideEndzones", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.yAxisConfigs", - "type": "Array", - "tags": [], - "label": "yAxisConfigs", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.YAxisConfigResult", - "text": "YAxisConfigResult" - }, - "[] | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.xAxisConfig", - "type": "CompoundType", - "tags": [], - "label": "xAxisConfig", - "description": [], - "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XAxisConfigResult", - "text": "XAxisConfigResult" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.addTimeMarker", - "type": "CompoundType", - "tags": [], - "label": "addTimeMarker", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.markSizeRatio", - "type": "number", - "tags": [], - "label": "markSizeRatio", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.minTimeBarInterval", - "type": "string", - "tags": [], - "label": "minTimeBarInterval", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.minBarHeight", - "type": "number", - "tags": [], - "label": "minBarHeight", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.splitRowAccessor", - "type": "CompoundType", - "tags": [], - "label": "splitRowAccessor", - "description": [], - "signature": [ - "string | ", - { - "pluginId": "visualizations", - "scope": "common", - "docId": "kibVisualizationsPluginApi", - "section": "def-common.ExpressionValueVisDimension", - "text": "ExpressionValueVisDimension" - }, - " | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.detailedTooltip", - "type": "CompoundType", - "tags": [], - "label": "detailedTooltip", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.orderBucketsBySum", - "type": "CompoundType", - "tags": [], - "label": "orderBucketsBySum", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.XYArgs.showTooltip", - "type": "boolean", - "tags": [], - "label": "showTooltip", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYChartProps", - "type": "Interface", - "tags": [], - "label": "XYChartProps", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.XYChartProps.args", - "type": "Object", - "tags": [], - "label": "args", - "description": [], - "signature": [ - "XYProps" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "common", + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.XYChartProps.syncTooltips", - "type": "boolean", - "tags": [], - "label": "syncTooltips", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.XYChartProps.syncCursor", - "type": "boolean", - "tags": [], - "label": "syncCursor", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.XYChartProps.syncColors", - "type": "boolean", - "tags": [], - "label": "syncColors", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.XYChartProps.canNavigateToLens", - "type": "CompoundType", - "tags": [], - "label": "canNavigateToLens", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record> | undefined>; title?: string | undefined; gridLine?: ", - { - "pluginId": "@kbn/chart-expressions-common", - "scope": "common", - "docId": "kibKbnChartExpressionsCommonPluginApi", - "section": "def-common.MakeOverridesSerializable", - "text": "MakeOverridesSerializable" - }, - " | undefined>; position?: ", - "Position", - " | undefined; ticks?: number | undefined; domain?: ", - { - "pluginId": "@kbn/chart-expressions-common", - "scope": "common", - "docId": "kibKbnChartExpressionsCommonPluginApi", - "section": "def-common.MakeOverridesSerializable", - "text": "MakeOverridesSerializable" - }, - "<", - "YDomainRange", - " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> & Partial | ", - "RecursivePartial", - "<", - "Theme", - ">[] | undefined>; showLegend?: boolean | undefined; legendPosition?: ", - "Position", - " | ", - "LegendPositionConfig", - " | undefined; rotation?: ", - "Rotation", - " | undefined; debug?: boolean | undefined; locale?: string | undefined; rendering?: ", - "Rendering", - " | undefined; animateData?: boolean | undefined; externalPointerEvents?: ", - "MakeOverridesSerializable", - "<", - "ExternalPointerEventsSettings", - " | undefined>; pointBuffer?: ", - "MarkBuffer", - " | undefined; pointerUpdateTrigger?: ", - "PointerUpdateTrigger", - " | undefined; brushAxis?: ", - "BrushAxis", - " | undefined; minBrushDelta?: number | undefined; allowBrushingLastHistogramBin?: boolean | undefined; ariaLabelHeadingLevel?: \"h1\" | \"h2\" | \"h3\" | \"h4\" | \"h5\" | \"h6\" | \"p\" | undefined; ariaUseDefaultSummary?: boolean | undefined; dow?: number | undefined; legendValues?: ", - "MakeOverridesSerializable", - "<", - "LegendValue", - "[] | undefined>; legendMaxDepth?: number | undefined; legendSize?: number | undefined; flatLegend?: boolean | undefined; ariaDescription?: string | undefined; ariaLabel?: string | undefined; xDomain?: ", - "MakeOverridesSerializable", - "<", - "CustomXDomain", - " | undefined>; debugState?: boolean | undefined; onProjectionClick?: \"ignore\" | undefined; onElementClick?: \"ignore\" | undefined; onElementOver?: \"ignore\" | undefined; onElementOut?: \"ignore\" | undefined; onBrushEnd?: \"ignore\" | undefined; onWillRender?: \"ignore\" | undefined; onProjectionAreaChange?: \"ignore\" | undefined; onAnnotationClick?: \"ignore\" | undefined; resizeDebounce?: number | undefined; pointerUpdateDebounce?: number | undefined; roundHistogramBrushValues?: boolean | undefined; renderingSort?: \"ignore\" | undefined; noResults?: React.ComponentType<{}> | React.ReactChild | undefined; ariaLabelledBy?: string | undefined; ariaDescribedBy?: string | undefined; ariaTableCaption?: string | undefined; legendStrategy?: ", - "LegendStrategy", - " | undefined; onLegendItemOver?: \"ignore\" | undefined; onLegendItemOut?: \"ignore\" | undefined; onLegendItemClick?: \"ignore\" | undefined; onLegendItemPlusClick?: \"ignore\" | undefined; onLegendItemMinusClick?: \"ignore\" | undefined; legendAction?: \"ignore\" | undefined; legendSort?: \"ignore\" | undefined; customLegend?: \"ignore\" | undefined; legendTitle?: string | undefined; }>> & Partial>) | undefined" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig", - "type": "Interface", - "tags": [], - "label": "XYDataLayerConfig", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" + }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.accessors", - "type": "Array", - "tags": [], - "label": "accessors", - "description": [], - "signature": [ - "string[]" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.layerType", - "type": "string", - "tags": [], - "label": "layerType", - "description": [], - "signature": [ - "\"data\"" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.seriesType", - "type": "CompoundType", - "tags": [], - "label": "seriesType", - "description": [], - "signature": [ - "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[]; visualizationType: string; state: { query: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.xAccessor", - "type": "string", - "tags": [], - "label": "xAccessor", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, + " | ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.simpleView", - "type": "CompoundType", - "tags": [], - "label": "simpleView", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, + "; filters: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.yConfig", - "type": "Array", - "tags": [], - "label": "yConfig", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.YConfig", - "text": "YConfig" - }, - "[] | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.palette", - "type": "Object", - "tags": [], - "label": "palette", - "description": [], - "signature": [ - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }> | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.collapseFn", - "type": "CompoundType", - "tags": [], - "label": "collapseFn", - "description": [], - "signature": [ - "CollapseFunction", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; } | undefined) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.Suggestion", + "text": "Suggestion" }, + "[] | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", + "deprecated": false, + "trackAdoption": false, + "returnComment": [], + "children": [ { "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.xScaleType", + "id": "def-public.LensSuggestionsApi.$1", "type": "CompoundType", "tags": [], - "label": "xScaleType", + "label": "context", "description": [], "signature": [ { - "pluginId": "expressionXY", + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.VisualizeFieldContext", + "text": "VisualizeFieldContext" + }, + " | ", + "VisualizeEditorContext", + "<", + { + "pluginId": "visualizations", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XScaleType", - "text": "XScaleType" + "docId": "kibVisualizationsPluginApi", + "section": "def-common.Configuration", + "text": "Configuration" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.isHistogram", - "type": "CompoundType", - "tags": [], - "label": "isHistogram", - "description": [], - "signature": [ - "boolean | undefined" + ">" ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "path": "x-pack/plugins/lens/public/plugin.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.columnToLabel", - "type": "string", + "id": "def-public.LensSuggestionsApi.$2", + "type": "Object", "tags": [], - "label": "columnToLabel", + "label": "dataViews", "description": [], "signature": [ - "string | undefined" + { + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataView", + "text": "DataView" + } ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "path": "x-pack/plugins/lens/public/plugin.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.XYDataLayerConfig.colorMapping", - "type": "Object", + "id": "def-public.LensSuggestionsApi.$3", + "type": "Array", "tags": [], - "label": "colorMapping", + "label": "excludedVisualizations", "description": [], "signature": [ - "Config", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYReferenceLineLayerConfig", - "type": "Interface", - "tags": [], - "label": "XYReferenceLineLayerConfig", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.XYReferenceLineLayerConfig.layerId", - "type": "string", - "tags": [], - "label": "layerId", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "string[] | undefined" + ], + "path": "x-pack/plugins/lens/public/plugin.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.XYReferenceLineLayerConfig.accessors", - "type": "Array", + "id": "def-public.LensSuggestionsApi.$4", + "type": "CompoundType", "tags": [], - "label": "accessors", + "label": "preferredChartType", "description": [], "signature": [ - "string[]" + { + "pluginId": "@kbn/visualization-utils", + "scope": "common", + "docId": "kibKbnVisualizationUtilsPluginApi", + "section": "def-common.ChartType", + "text": "ChartType" + }, + " | undefined" ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "path": "x-pack/plugins/lens/public/plugin.ts", "deprecated": false, "trackAdoption": false }, { "parentPluginId": "lens", - "id": "def-public.XYReferenceLineLayerConfig.yConfig", - "type": "Array", + "id": "def-public.LensSuggestionsApi.$5", + "type": "CompoundType", "tags": [], - "label": "yConfig", + "label": "preferredVisAttributes", "description": [], "signature": [ + "{ title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.XYState", + "text": "XYState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + "PieVisualizationState", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.HeatmapVisualizationState", + "text": "HeatmapVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.YConfig", - "text": "YConfig" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - "[] | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYReferenceLineLayerConfig.layerType", - "type": "string", - "tags": [], - "label": "layerType", - "description": [], - "signature": [ - "\"referenceLine\"" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYRender", - "type": "Interface", - "tags": [], - "label": "XYRender", - "description": [], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.XYRender.type", - "type": "string", - "tags": [], - "label": "type", - "description": [], - "signature": [ - "\"render\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYRender.as", - "type": "string", - "tags": [], - "label": "as", - "description": [], - "signature": [ - "\"xyVis\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYRender.value", - "type": "Object", - "tags": [], - "label": "value", - "description": [], - "signature": [ + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XYChartProps", - "text": "XYChartProps" - } - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_renderers.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState", - "type": "Interface", - "tags": [], - "label": "XYState", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.XYState.preferredSeriesType", - "type": "CompoundType", - "tags": [], - "label": "preferredSeriesType", - "description": [], - "signature": [ - "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.legend", - "type": "Object", - "tags": [], - "label": "legend", - "description": [], - "signature": [ + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" + }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/core-saved-objects-common", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.LegendConfig", - "text": "LegendConfig" - } - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.valueLabels", - "type": "CompoundType", - "tags": [], - "label": "valueLabels", - "description": [], - "signature": [ - "ValueLabelConfig", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.fittingFunction", - "type": "CompoundType", - "tags": [], - "label": "fittingFunction", - "description": [], - "signature": [ + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.FittingFunction", - "text": "FittingFunction" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.emphasizeFitting", - "type": "CompoundType", - "tags": [], - "label": "emphasizeFitting", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.endValue", - "type": "CompoundType", - "tags": [], - "label": "endValue", - "description": [], - "signature": [ + " | ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.EndValue", - "text": "EndValue" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.xExtent", - "type": "Object", - "tags": [], - "label": "xExtent", - "description": [], - "signature": [ + "; filters: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.AxisExtentConfig", - "text": "AxisExtentConfig" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.yLeftExtent", - "type": "Object", - "tags": [], - "label": "yLeftExtent", - "description": [], - "signature": [ + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/core-saved-objects-common", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.AxisExtentConfig", - "text": "AxisExtentConfig" + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.layers", - "type": "Array", - "tags": [], - "label": "layers", - "description": [], - "signature": [ + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.XYLayerConfig", - "text": "XYLayerConfig" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - "[]" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.xTitle", - "type": "string", - "tags": [], - "label": "xTitle", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.yTitle", - "type": "string", - "tags": [], - "label": "yTitle", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.yRightTitle", - "type": "string", - "tags": [], - "label": "yRightTitle", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.yLeftScale", - "type": "CompoundType", - "tags": [], - "label": "yLeftScale", - "description": [], - "signature": [ + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "pluginId": "expressionXY", + "pluginId": "lens", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.YScaleType", - "text": "YScaleType" + "docId": "kibLensPluginApi", + "section": "def-common.LegacyMetricState", + "text": "LegacyMetricState" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.yRightScale", - "type": "CompoundType", - "tags": [], - "label": "yRightScale", - "description": [], - "signature": [ + "; }; } | { title: string; description?: string | undefined; references: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/core-saved-objects-common", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.YScaleType", - "text": "YScaleType" + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.axisTitlesVisibilitySettings", - "type": "Object", - "tags": [], - "label": "axisTitlesVisibilitySettings", - "description": [], - "signature": [ + "[]; visualizationType: \"lnsMetric\"; state: { query: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.AxesSettingsConfig", - "text": "AxesSettingsConfig" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.tickLabelsVisibilitySettings", - "type": "Object", - "tags": [], - "label": "tickLabelsVisibilitySettings", - "description": [], - "signature": [ + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.AxesSettingsConfig", - "text": "AxesSettingsConfig" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.gridlinesVisibilitySettings", - "type": "Object", - "tags": [], - "label": "gridlinesVisibilitySettings", - "description": [], - "signature": [ + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.AxesSettingsConfig", - "text": "AxesSettingsConfig" + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.labelsOrientation", - "type": "Object", - "tags": [], - "label": "labelsOrientation", - "description": [], - "signature": [ - "LabelsOrientationConfig", - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.curveType", - "type": "CompoundType", - "tags": [], - "label": "curveType", - "description": [], - "signature": [ + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.XYCurveType", - "text": "XYCurveType" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.fillOpacity", - "type": "number", - "tags": [], - "label": "fillOpacity", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.minBarHeight", - "type": "number", - "tags": [], - "label": "minBarHeight", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.hideEndzones", - "type": "CompoundType", - "tags": [], - "label": "hideEndzones", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.XYState.showCurrentTimeMarker", - "type": "CompoundType", - "tags": [], - "label": "showCurrentTimeMarker", - "description": [], - "signature": [ - "boolean | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig", - "type": "Interface", - "tags": [], - "label": "YConfig", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "lens", - "id": "def-public.YConfig.forAccessor", - "type": "string", - "tags": [], - "label": "forAccessor", - "description": [], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig.color", - "type": "string", - "tags": [], - "label": "color", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig.icon", - "type": "string", - "tags": [], - "label": "icon", - "description": [], - "signature": [ - "string | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig.lineWidth", - "type": "number", - "tags": [], - "label": "lineWidth", - "description": [], - "signature": [ - "number | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig.lineStyle", - "type": "CompoundType", - "tags": [], - "label": "lineStyle", - "description": [], - "signature": [ - "\"dashed\" | \"solid\" | \"dotted\" | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig.fill", - "type": "CompoundType", - "tags": [], - "label": "fill", - "description": [], - "signature": [ + "; filters: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.FillStyle", - "text": "FillStyle" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "lens", - "id": "def-public.YConfig.iconPosition", - "type": "CompoundType", - "tags": [], - "label": "iconPosition", - "description": [], - "signature": [ + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.YAxisMode", - "text": "YAxisMode" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - " | undefined" + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; } | undefined" ], - "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", + "path": "x-pack/plugins/lens/public/plugin.ts", "deprecated": false, "trackAdoption": false } ], "initialIsOpen": false - } - ], - "enums": [], - "misc": [ - { - "parentPluginId": "lens", - "id": "def-public.AvgIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "AvgIndexPatternColumn", - "description": [], - "signature": [ - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" - }, - " & { operationType: \"average\"; params?: { emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.AxisExtentConfigResult", + "id": "def-public.LineStyle", "type": "Type", "tags": [], - "label": "AxisExtentConfigResult", + "label": "LineStyle", "description": [], "signature": [ - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.AxisExtentConfig", - "text": "AxisExtentConfig" - }, - " & { type: \"axisExtentConfig\"; }" + "\"dashed\" | \"solid\" | \"dotted\" | \"dot-dashed\"" ], "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, @@ -10992,43 +24191,58 @@ }, { "parentPluginId": "lens", - "id": "def-public.AxisExtentMode", + "id": "def-public.MaxIndexPatternColumn", "type": "Type", "tags": [], - "label": "AxisExtentMode", + "label": "MaxIndexPatternColumn", "description": [], "signature": [ - "\"custom\" | \"full\" | \"dataBounds\"" + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " & { operationType: \"max\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined; }" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.CounterRateIndexPatternColumn", + "id": "def-public.MedianIndexPatternColumn", "type": "Type", "tags": [], - "label": "CounterRateIndexPatternColumn", + "label": "MedianIndexPatternColumn", "description": [], "signature": [ - "FormattedIndexPatternColumn", - " & ", - "ReferenceBasedIndexPatternColumn", - " & { operationType: \"counter_rate\"; }" + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " & { operationType: \"median\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined; }" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/counter_rate.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.CountIndexPatternColumn", + "id": "def-public.MinIndexPatternColumn", "type": "Type", "tags": [], - "label": "CountIndexPatternColumn", + "label": "MinIndexPatternColumn", "description": [], "signature": [ { @@ -11038,369 +24252,246 @@ "section": "def-public.FieldBasedIndexPatternColumn", "text": "FieldBasedIndexPatternColumn" }, - " & { operationType: \"count\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + " & { operationType: \"min\"; params?: { emptyAsNull?: boolean | undefined; format?: ", "ValueFormatConfig", " | undefined; } | undefined; }" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/count.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.CumulativeSumIndexPatternColumn", + "id": "def-public.MovingAverageIndexPatternColumn", "type": "Type", "tags": [], - "label": "CumulativeSumIndexPatternColumn", + "label": "MovingAverageIndexPatternColumn", "description": [], "signature": [ "FormattedIndexPatternColumn", " & ", "ReferenceBasedIndexPatternColumn", - " & { operationType: \"cumulative_sum\"; }" + " & { operationType: \"moving_average\"; params: { window: number; }; }" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/cumulative_sum.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/moving_average.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.DataLayerConfig", + "id": "def-public.OperationType", "type": "Type", "tags": [], - "label": "DataLayerConfig", - "description": [], - "signature": [ - "Omit<", - { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.DataLayerArgs", - "text": "DataLayerArgs" - }, - ", \"palette\"> & { type: \"dataLayer\"; layerType: \"data\"; palette: ", - { - "pluginId": "@kbn/coloring", - "scope": "common", - "docId": "kibKbnColoringPluginApi", - "section": "def-common.PaletteOutput", - "text": "PaletteOutput" - }, - "<{ [key: string]: unknown; }>; table: ", - { - "pluginId": "expressions", - "scope": "common", - "docId": "kibExpressionsPluginApi", - "section": "def-common.Datatable", - "text": "Datatable" - }, - "; } & ", - "WithLayerId" + "label": "OperationType", + "description": [ + "\nA union type of all available operation types. The operation type is a unique id of an operation.\nEach column is assigned to exactly one operation type." ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.DataType", - "type": "Type", - "tags": [], - "label": "DataType", - "description": [], "signature": [ - "\"string\" | \"number\" | \"boolean\" | \"date\" | ", - "FieldOnlyDataType" + "string" ], - "path": "x-pack/plugins/lens/public/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/index.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.DerivativeIndexPatternColumn", + "id": "def-public.OverallSumIndexPatternColumn", "type": "Type", "tags": [], - "label": "DerivativeIndexPatternColumn", + "label": "OverallSumIndexPatternColumn", "description": [], "signature": [ "FormattedIndexPatternColumn", " & ", "ReferenceBasedIndexPatternColumn", - " & { operationType: \"differences\"; }" + " & { operationType: \"overall_sum\"; }" ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/differences.tsx", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/overall_metric.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.EmbeddableComponent", + "id": "def-public.PersistedIndexPatternLayer", "type": "Type", "tags": [], - "label": "EmbeddableComponent", + "label": "PersistedIndexPatternLayer", "description": [], "signature": [ - "React.ComponentClass<", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.EmbeddableComponentProps", - "text": "EmbeddableComponentProps" - }, - ", any> | React.FunctionComponent<", + "{ columns: Record" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.EmbeddableComponentProps", - "type": "Type", - "tags": [], - "label": "EmbeddableComponentProps", - "description": [], - "signature": [ - "(", + ">; ignoreGlobalFilters?: boolean | undefined; columnOrder: string[]; linkToLayers?: string[] | undefined; incompleteColumns?: Record[] | undefined; showInspector?: boolean | undefined; abortController?: AbortController | undefined; }" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FillStyle", - "type": "Type", - "tags": [], - "label": "FillStyle", - "description": [], - "signature": [ - "\"none\" | \"above\" | \"below\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.FittingFunction", - "type": "Type", - "tags": [], - "label": "FittingFunction", - "description": [], - "signature": [ - "\"None\" | \"Average\" | \"Zero\" | \"Linear\" | \"Carry\" | \"Lookahead\" | \"Nearest\"" + " | undefined> | undefined; sampling?: number | undefined; }" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.GaugeVisualizationState", + "id": "def-public.PieLayerState", "type": "Type", "tags": [], - "label": "GaugeVisualizationState", + "label": "PieLayerState", "description": [], "signature": [ - "Omit<", - { - "pluginId": "expressionGauge", - "scope": "common", - "docId": "kibExpressionGaugePluginApi", - "section": "def-common.GaugeState", - "text": "GaugeState" - }, - ", \"min\" | \"max\" | \"metric\" | \"goal\"> & { metricAccessor?: string | undefined; minAccessor?: string | undefined; maxAccessor?: string | undefined; goalAccessor?: string | undefined; } & { layerId: string; layerType: ", + "SharedPieLayerState", + " & { layerId: string; layerType: ", "LayerType", "; }" ], - "path": "x-pack/plugins/lens/public/visualizations/gauge/constants.ts", + "path": "x-pack/plugins/lens/common/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.GenericIndexPatternColumn", + "id": "def-public.ReferenceLineLayerConfig", "type": "Type", "tags": [], - "label": "GenericIndexPatternColumn", + "label": "ReferenceLineLayerConfig", "description": [], "signature": [ { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "pluginId": "expressionXY", + "scope": "common", + "docId": "kibExpressionXYPluginApi", + "section": "def-common.ReferenceLineLayerArgs", + "text": "ReferenceLineLayerArgs" }, - " | ", - "BaseIndexPatternColumn", - " | ", - "ReferenceBasedIndexPatternColumn" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/column_types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.HeatmapVisualizationState", - "type": "Type", - "tags": [], - "label": "HeatmapVisualizationState", - "description": [], - "signature": [ - "Omit<", + " & { type: \"referenceLineLayer\"; layerType: \"referenceLine\"; table: ", { - "pluginId": "expressionHeatmap", + "pluginId": "expressions", "scope": "common", - "docId": "kibExpressionHeatmapPluginApi", - "section": "def-common.HeatmapArguments", - "text": "HeatmapArguments" - }, - ", \"palette\"> & { layerId: string; layerType: ", - "LayerType", - "; valueAccessor?: string | undefined; xAccessor?: string | undefined; yAccessor?: string | undefined; shape: \"heatmap\"; } & { palette?: ", - "Palette", - " | undefined; }" + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; } & ", + "WithLayerId" ], - "path": "x-pack/plugins/lens/public/visualizations/heatmap/types.ts", + "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.IconPosition", + "id": "def-public.SeriesType", "type": "Type", "tags": [], - "label": "IconPosition", + "label": "SeriesType", "description": [], "signature": [ - "\"right\" | \"left\" | \"auto\" | \"above\" | \"below\"" + "\"area\" | \"line\" | \"bar\" | \"bar_stacked\" | \"area_stacked\" | \"bar_horizontal\" | \"bar_percentage_stacked\" | \"bar_horizontal_stacked\" | \"area_percentage_stacked\" | \"bar_horizontal_percentage_stacked\"" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/visualizations/xy/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.LayerType", + "id": "def-public.StandardDeviationIndexPatternColumn", "type": "Type", "tags": [], - "label": "LayerType", + "label": "StandardDeviationIndexPatternColumn", "description": [], "signature": [ - "\"data\" | \"annotations\" | \"metricTrendline\" | \"referenceLine\"" + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" + }, + " & { operationType: \"standard_deviation\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined; }" ], - "path": "x-pack/plugins/lens/common/types.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.LegendConfigResult", + "id": "def-public.SumIndexPatternColumn", "type": "Type", "tags": [], - "label": "LegendConfigResult", + "label": "SumIndexPatternColumn", "description": [], "signature": [ { - "pluginId": "expressionXY", - "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.LegendConfig", - "text": "LegendConfig" + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FieldBasedIndexPatternColumn", + "text": "FieldBasedIndexPatternColumn" }, - " & { type: \"legendConfig\"; }" + " & { operationType: \"sum\"; params?: { emptyAsNull?: boolean | undefined; format?: ", + "ValueFormatConfig", + " | undefined; } | undefined; }" ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.LENS_EMBEDDABLE_TYPE", - "type": "string", + "id": "def-public.TimeScaleIndexPatternColumn", + "type": "Type", "tags": [], - "label": "LENS_EMBEDDABLE_TYPE", + "label": "TimeScaleIndexPatternColumn", "description": [], "signature": [ - "\"lens\"" + "FormattedIndexPatternColumn", + " & ", + "ReferenceBasedIndexPatternColumn", + " & { operationType: \"normalize_by_unit\"; params: { unit?: string | undefined; }; }" ], - "path": "x-pack/plugins/lens/common/constants.ts", + "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/time_scale.tsx", "deprecated": false, "trackAdoption": false, "initialIsOpen": false }, { "parentPluginId": "lens", - "id": "def-public.LensApi", + "id": "def-public.TypedLensByValueInput", "type": "Type", "tags": [], - "label": "LensApi", + "label": "TypedLensByValueInput", "description": [], "signature": [ + "{ id?: string | undefined; className?: string | undefined; style?: React.CSSProperties | undefined; title?: string | undefined; onLoad?: ((isLoading: boolean, adapters?: Partial<", { - "pluginId": "@kbn/presentation-publishing", - "scope": "public", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.HasType", - "text": "HasType" - }, - "<\"lens\"> & { getSavedVis: () => Readonly<", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSavedObjectAttributes", - "text": "LensSavedObjectAttributes" + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.DefaultInspectorAdapters", + "text": "DefaultInspectorAdapters" }, - " | undefined>; canViewUnderlyingData$: ", + "> | undefined, dataLoading$?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -11408,49 +24499,55 @@ "section": "def-public.PublishingSubject", "text": "PublishingSubject" }, - "; getViewUnderlyingDataArgs: () => ", - "ViewUnderlyingDataArgs", - "; getFullAttributes: () => ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensSavedObjectAttributes", - "text": "LensSavedObjectAttributes" - }, - " | undefined; } & ", + " | undefined) => void) | undefined; description?: string | undefined; viewMode?: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.PublishesPanelTitle", - "text": "PublishesPanelTitle" + "section": "def-public.ViewMode", + "text": "ViewMode" }, - " & ", + " | undefined; timeRange?: ", { - "pluginId": "@kbn/presentation-publishing", - "scope": "public", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.PublishesTimeRange", - "text": "PublishesTimeRange" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.TimeRange", + "text": "TimeRange" }, - " & ", + " | undefined; query?: ", { - "pluginId": "@kbn/presentation-publishing", - "scope": "public", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.PublishesFilters", - "text": "PublishesFilters" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - " & { isCompatibleWithUnifiedSearch?: (() => boolean) | undefined; query$: ", + " | ", { - "pluginId": "@kbn/presentation-publishing", - "scope": "public", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.PublishingSubject", - "text": "PublishingSubject" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - "<", + " | undefined; filters?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[] | undefined; attributes: { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -11466,55 +24563,57 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | undefined>; } & Partial<", + "; filters: ", { - "pluginId": "@kbn/presentation-publishing", + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", "scope": "public", - "docId": "kibKbnPresentationPublishingPluginApi", - "section": "def-public.HasParentApi", - "text": "HasParentApi" + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - ">>" - ], - "path": "x-pack/plugins/lens/public/embeddable/interfaces/lens_api.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LensEmbeddableInput", - "type": "Type", - "tags": [], - "label": "LensEmbeddableInput", - "description": [], - "signature": [ - "LensByValueInput", - " | ", - "LensByReferenceInput" - ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LensSavedObjectAttributes", - "type": "Type", - "tags": [], - "label": "LensSavedObjectAttributes", - "description": [], - "signature": [ - "{ title: string; description?: string | undefined; state: { datasourceStates: Record; visualization: unknown; query: ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -11522,7 +24621,15 @@ "section": "def-common.Query", "text": "Query" }, - "; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; filters: ", + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -11530,7 +24637,7 @@ "section": "def-common.Filter", "text": "Filter" }, - "[]; adHocDataViews?: Record, dataViews: ", + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "pluginId": "@kbn/visualization-utils", + "pluginId": "@kbn/core-saved-objects-common", "scope": "common", - "docId": "kibKbnVisualizationUtilsPluginApi", - "section": "def-common.ChartType", - "text": "ChartType" + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - " | undefined, preferredVisAttributes?: LensAttributes<\"lnsXY\", ", + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -11621,570 +24731,337 @@ "section": "def-public.HeatmapVisualizationState", "text": "HeatmapVisualizationState" }, - "> | LensAttributes<\"lnsGauge\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" - }, - "> | LensAttributes<\"lnsDatatable\", ", + "; }; } | { title: string; description?: string | undefined; references: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + "[]; visualizationType: \"lnsGauge\"; state: { query: ", { - "pluginId": "lens", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - "> | LensAttributes<\"lnsMetric\", ", + " | ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - "> | LensAttributes | undefined) => ", + "; filters: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.Suggestion", - "text": "Suggestion" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, - "[] | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false, - "returnComment": [], - "children": [ + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "dataViews", + "scope": "common", + "docId": "kibDataViewsPluginApi", + "section": "def-common.DataViewSpec", + "text": "DataViewSpec" }, + "> | undefined; internalReferences?: ", { - "parentPluginId": "lens", - "id": "def-public.LensSuggestionsApi.$2", - "type": "Object", - "tags": [], - "label": "dataViews", - "description": [], - "signature": [ - { - "pluginId": "dataViews", - "scope": "common", - "docId": "kibDataViewsPluginApi", - "section": "def-common.DataView", - "text": "DataView" - } - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, + "[] | undefined; datasourceStates: { formBased?: ", { - "parentPluginId": "lens", - "id": "def-public.LensSuggestionsApi.$3", - "type": "Array", - "tags": [], - "label": "excludedVisualizations", - "description": [], - "signature": [ - "string[] | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { - "parentPluginId": "lens", - "id": "def-public.LensSuggestionsApi.$4", - "type": "CompoundType", - "tags": [], - "label": "preferredChartType", - "description": [], - "signature": [ - { - "pluginId": "@kbn/visualization-utils", - "scope": "common", - "docId": "kibKbnVisualizationUtilsPluginApi", - "section": "def-common.ChartType", - "text": "ChartType" - }, - " | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.GaugeVisualizationState", + "text": "GaugeVisualizationState" }, + "; }; } | { title: string; description?: string | undefined; references: ", { - "parentPluginId": "lens", - "id": "def-public.LensSuggestionsApi.$5", - "type": "CompoundType", - "tags": [], - "label": "preferredVisAttributes", - "description": [], - "signature": [ - "LensAttributes<\"lnsXY\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" - }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" - }, - "> | LensAttributes<\"lnsGauge\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" - }, - "> | LensAttributes<\"lnsDatatable\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" - }, - "> | LensAttributes<\"lnsLegacyMetric\", ", - { - "pluginId": "lens", - "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" - }, - "> | LensAttributes<\"lnsMetric\", ", - { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" - }, - "> | LensAttributes | undefined" - ], - "path": "x-pack/plugins/lens/public/plugin.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.LineStyle", - "type": "Type", - "tags": [], - "label": "LineStyle", - "description": [], - "signature": [ - "\"dashed\" | \"solid\" | \"dotted\" | \"dot-dashed\"" - ], - "path": "src/plugins/chart_expressions/expression_xy/common/types/expression_functions.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MaxIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "MaxIndexPatternColumn", - "description": [], - "signature": [ + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - " & { operationType: \"max\"; params?: { emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MedianIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "MedianIndexPatternColumn", - "description": [], - "signature": [ + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - " & { operationType: \"median\"; params?: { emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MinIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "MinIndexPatternColumn", - "description": [], - "signature": [ + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "section": "def-public.DatatableVisualizationState", + "text": "DatatableVisualizationState" }, - " & { operationType: \"min\"; params?: { emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.MovingAverageIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "MovingAverageIndexPatternColumn", - "description": [], - "signature": [ - "FormattedIndexPatternColumn", - " & ", - "ReferenceBasedIndexPatternColumn", - " & { operationType: \"moving_average\"; params: { window: number; }; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/moving_average.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.OperationType", - "type": "Type", - "tags": [], - "label": "OperationType", - "description": [ - "\nA union type of all available operation types. The operation type is a unique id of an operation.\nEach column is assigned to exactly one operation type." - ], - "signature": [ - "string" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/index.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.OverallSumIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "OverallSumIndexPatternColumn", - "description": [], - "signature": [ - "FormattedIndexPatternColumn", - " & ", - "ReferenceBasedIndexPatternColumn", - " & { operationType: \"overall_sum\"; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/overall_metric.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.PersistedIndexPatternLayer", - "type": "Type", - "tags": [], - "label": "PersistedIndexPatternLayer", - "description": [], - "signature": [ - "{ columns: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.GenericIndexPatternColumn", - "text": "GenericIndexPatternColumn" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - ">; ignoreGlobalFilters?: boolean | undefined; columnOrder: string[]; linkToLayers?: string[] | undefined; incompleteColumns?: Record | undefined; sampling?: number | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.PieLayerState", - "type": "Type", - "tags": [], - "label": "PieLayerState", - "description": [], - "signature": [ - "SharedPieLayerState", - " & { layerId: string; layerType: ", - "LayerType", - "; }" - ], - "path": "x-pack/plugins/lens/common/types.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.ReferenceLineLayerConfig", - "type": "Type", - "tags": [], - "label": "ReferenceLineLayerConfig", - "description": [], - "signature": [ + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", { - "pluginId": "expressionXY", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibExpressionXYPluginApi", - "section": "def-common.ReferenceLineLayerArgs", - "text": "ReferenceLineLayerArgs" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" }, - " & { type: \"referenceLineLayer\"; layerType: \"referenceLine\"; table: ", + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - " & { operationType: \"standard_deviation\"; params?: { emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.SumIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "SumIndexPatternColumn", - "description": [], - "signature": [ + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.FieldBasedIndexPatternColumn", - "text": "FieldBasedIndexPatternColumn" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" }, - " & { operationType: \"sum\"; params?: { emptyAsNull?: boolean | undefined; format?: ", - "ValueFormatConfig", - " | undefined; } | undefined; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/metrics.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.TimeScaleIndexPatternColumn", - "type": "Type", - "tags": [], - "label": "TimeScaleIndexPatternColumn", - "description": [], - "signature": [ - "FormattedIndexPatternColumn", - " & ", - "ReferenceBasedIndexPatternColumn", - " & { operationType: \"normalize_by_unit\"; params: { unit?: string | undefined; }; }" - ], - "path": "x-pack/plugins/lens/public/datasources/form_based/operations/definitions/calculations/time_scale.tsx", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "lens", - "id": "def-public.TypedLensByValueInput", - "type": "Type", - "tags": [], - "label": "TypedLensByValueInput", - "description": [ - "\nType-safe variant of by value embeddable input for Lens.\nThis can be used to hardcode certain Lens chart configurations within another app." - ], - "signature": [ - "Omit<", - "LensByValueInput", - ", \"attributes\" | \"overrides\"> & { attributes: LensAttributes<\"lnsXY\", ", + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.XYState", - "text": "XYState" + "section": "def-public.MetricVisualizationState", + "text": "MetricVisualizationState" }, - "> | LensAttributes<\"lnsPie\", ", - "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", + "; }; } | { title: string; description?: string | undefined; references: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.HeatmapVisualizationState", - "text": "HeatmapVisualizationState" + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "> | LensAttributes<\"lnsGauge\", ", + "[]; visualizationType: string; state: { query: ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.GaugeVisualizationState", - "text": "GaugeVisualizationState" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" }, - "> | LensAttributes<\"lnsDatatable\", ", + " | ", { - "pluginId": "lens", - "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.DatatableVisualizationState", - "text": "DatatableVisualizationState" + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + "; filters: ", { - "pluginId": "lens", + "pluginId": "@kbn/es-query", "scope": "common", - "docId": "kibLensPluginApi", - "section": "def-common.LegacyMetricState", - "text": "LegacyMetricState" + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "> | LensAttributes<\"lnsMetric\", ", + "[] | undefined; datasourceStates: { formBased?: ", { "pluginId": "lens", "scope": "public", "docId": "kibLensPluginApi", - "section": "def-public.MetricVisualizationState", - "text": "MetricVisualizationState" + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }; references?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" }, - "> | LensAttributes; overrides?: Partial> | Partial; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; }" + " | undefined>; hide?: boolean | undefined; showOverlappingTicks?: boolean | undefined; showOverlappingLabels?: boolean | undefined; timeAxisLayerCount?: number | undefined; maximumFractionDigits?: number | undefined; tickFormat?: \"ignore\" | undefined; integersOnly?: boolean | undefined; labelFormat?: \"ignore\" | undefined; showDuplicatedTicks?: boolean | undefined; }>> | undefined; executionContext?: ", + { + "pluginId": "@kbn/core-execution-context-common", + "scope": "common", + "docId": "kibKbnCoreExecutionContextCommonPluginApi", + "section": "def-common.KibanaExecutionContext", + "text": "KibanaExecutionContext" + }, + " | undefined; palette?: ", + { + "pluginId": "@kbn/coloring", + "scope": "common", + "docId": "kibKbnColoringPluginApi", + "section": "def-common.PaletteOutput", + "text": "PaletteOutput" + }, + "<{ [key: string]: unknown; }> | undefined; onBrushEnd?: ((data: { table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; column: number; range: number[]; timeFieldName?: string | undefined; preventDefault: () => void; }) => void) | undefined; timeslice?: [number, number] | undefined; hidePanelTitles?: boolean | undefined; syncTooltips?: boolean | undefined; syncColors?: boolean | undefined; syncCursor?: boolean | undefined; lastReloadRequestTime?: number | undefined; enhancements?: { dynamicActions: ", + { + "pluginId": "uiActionsEnhanced", + "scope": "common", + "docId": "kibUiActionsEnhancedPluginApi", + "section": "def-common.DynamicActionsState", + "text": "DynamicActionsState" + }, + "; } | undefined; disabledActions?: string[] | undefined; disableTriggers?: boolean | undefined; searchSessionId?: string | undefined; onFilter?: ((data: { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; column: number; row: number; value: any; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; } | { data: { table: Pick<", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + ", \"columns\" | \"rows\">; cells: { column: number; row: number; }[]; relation?: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.BooleanRelation", + "text": "BooleanRelation" + }, + " | undefined; }[]; timeFieldName?: string | undefined; negate?: boolean | undefined; preventDefault: () => void; }) => void) | undefined; withDefaultActions?: boolean | undefined; abortController?: AbortController | undefined; renderMode?: ", + { + "pluginId": "@kbn/presentation-publishing", + "scope": "public", + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.ViewMode", + "text": "ViewMode" + }, + " | undefined; noPadding?: boolean | undefined; isNewPanel?: boolean | undefined; extraActions?: ", + { + "pluginId": "uiActions", + "scope": "public", + "docId": "kibUiActionsPluginApi", + "section": "def-public.Action", + "text": "Action" + }, + "[] | undefined; showInspector?: boolean | undefined; canEditInline?: boolean | undefined; onTableRowClick?: ((data: { rowIndex: number; table: ", + { + "pluginId": "expressions", + "scope": "common", + "docId": "kibExpressionsPluginApi", + "section": "def-common.Datatable", + "text": "Datatable" + }, + "; columns?: string[] | undefined; preventDefault: () => void; }) => void) | undefined; onBeforeBadgesRender?: ((userMessages: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) => ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.UserMessage", + "text": "UserMessage" + }, + "[]) | undefined; }" ], - "path": "x-pack/plugins/lens/public/embeddable/embeddable_component.tsx", + "path": "x-pack/plugins/lens/public/react_embeddable/types.ts", "deprecated": false, "trackAdoption": false, "initialIsOpen": false diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index f383c13e0c1c..2a0fa0fac8df 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 693 | 0 | 591 | 62 | +| 647 | 0 | 548 | 60 | ## Client @@ -31,9 +31,6 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k ### Functions -### Classes - - ### Interfaces diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index 469c1f399b3a..50c415af42cc 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2024-11-22 +date: 2024-12-03 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 5879ddb4b981..4bb9d046ea56 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.devdocs.json b/api_docs/licensing.devdocs.json index fc5da83ec022..954110ba3ede 100644 --- a/api_docs/licensing.devdocs.json +++ b/api_docs/licensing.devdocs.json @@ -850,14 +850,6 @@ "plugin": "watcher", "path": "x-pack/plugins/watcher/public/plugin.ts" }, - { - "plugin": "profiling", - "path": "x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx" - }, - { - "plugin": "apm", - "path": "x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx" - }, { "plugin": "slo", "path": "x-pack/plugins/observability_solution/slo/public/plugin.ts" diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index da1f9abca610..8e4aa9179672 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index 9a09412f4ec3..3666a3ae56f0 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 780e650de166..03c4dff3ed05 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/llm_tasks.mdx b/api_docs/llm_tasks.mdx index 29e203881126..d8ce2477322a 100644 --- a/api_docs/llm_tasks.mdx +++ b/api_docs/llm_tasks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/llmTasks title: "llmTasks" image: https://source.unsplash.com/400x175/?github description: API docs for the llmTasks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'llmTasks'] --- import llmTasksObj from './llm_tasks.devdocs.json'; diff --git a/api_docs/logs_data_access.mdx b/api_docs/logs_data_access.mdx index 329560fefeeb..583d6c438c7a 100644 --- a/api_docs/logs_data_access.mdx +++ b/api_docs/logs_data_access.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/logsDataAccess title: "logsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the logsDataAccess plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsDataAccess'] --- import logsDataAccessObj from './logs_data_access.devdocs.json'; -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/logs_explorer.devdocs.json b/api_docs/logs_explorer.devdocs.json index fefcffd0f917..d05a47b7590d 100644 --- a/api_docs/logs_explorer.devdocs.json +++ b/api_docs/logs_explorer.devdocs.json @@ -311,7 +311,13 @@ "description": [], "signature": [ "Pick>, \"data\" | \"history\" | \"uiSettings\" | \"timefilter\" | \"filterManager\"> & { urlStateStorage: ", { "pluginId": "kibanaUtils", diff --git a/api_docs/logs_explorer.mdx b/api_docs/logs_explorer.mdx index 72054cd0a16a..baefde768016 100644 --- a/api_docs/logs_explorer.mdx +++ b/api_docs/logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsExplorer title: "logsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logsExplorer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsExplorer'] --- import logsExplorerObj from './logs_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.devdocs.json b/api_docs/logs_shared.devdocs.json index 70accf5e5f65..9f8ec3fc78fa 100644 --- a/api_docs/logs_shared.devdocs.json +++ b/api_docs/logs_shared.devdocs.json @@ -3164,6 +3164,46 @@ "path": "x-pack/plugins/observability_solution/logs_shared/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "logsShared", + "id": "def-public.LogsSharedClientStartDeps.embeddable", + "type": "Object", + "tags": [], + "label": "embeddable", + "description": [], + "signature": [ + { + "pluginId": "embeddable", + "scope": "public", + "docId": "kibEmbeddablePluginApi", + "section": "def-public.EmbeddableStart", + "text": "EmbeddableStart" + } + ], + "path": "x-pack/plugins/observability_solution/logs_shared/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "logsShared", + "id": "def-public.LogsSharedClientStartDeps.savedSearch", + "type": "Object", + "tags": [], + "label": "savedSearch", + "description": [], + "signature": [ + { + "pluginId": "savedSearch", + "scope": "public", + "docId": "kibSavedSearchPluginApi", + "section": "def-public.SavedSearchPublicPluginStart", + "text": "SavedSearchPublicPluginStart" + } + ], + "path": "x-pack/plugins/observability_solution/logs_shared/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 34a08a7a8a62..86875b505932 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 314 | 0 | 285 | 34 | +| 316 | 0 | 287 | 34 | ## Client diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 17ab011cd0c2..2a0acf38e95f 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2024-11-22 +date: 2024-12-03 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 88612499f04b..c26fbbab4607 100644 --- a/api_docs/maps.devdocs.json +++ b/api_docs/maps.devdocs.json @@ -158,6 +158,22 @@ "children": [], "returnComment": [] }, + { + "parentPluginId": "maps", + "id": "def-public.DataRequest.getError", + "type": "Function", + "tags": [], + "label": "getError", + "description": [], + "signature": [ + "() => Error | undefined" + ], + "path": "x-pack/plugins/maps/public/classes/util/data_request.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, { "parentPluginId": "maps", "id": "def-public.DataRequest.renderError", @@ -2287,6 +2303,60 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.IVectorSource.hasLegendDetails", + "type": "Function", + "tags": [], + "label": "hasLegendDetails", + "description": [ + "\nspecifies if a source provides its own legend details or if the default vector_style is used if the source has this method it must also implement renderLegendDetails" + ], + "signature": [ + "(() => Promise) | undefined" + ], + "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "maps", + "id": "def-public.IVectorSource.renderLegendDetails", + "type": "Function", + "tags": [], + "label": "renderLegendDetails", + "description": [ + "\nspecifies if a source provides its own legend details or if the default vector_style is used" + ], + "signature": [ + "((vectorStyle: ", + "IVectorStyle", + ") => React.ReactElement> | null) | undefined" + ], + "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "maps", + "id": "def-public.IVectorSource.renderLegendDetails.$1", + "type": "Object", + "tags": [], + "label": "vectorStyle", + "description": [], + "signature": [ + "IVectorStyle" + ], + "path": "x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] } ], "initialIsOpen": false diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index f58e7a92e557..7b7896bf2a38 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kib | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 209 | 0 | 205 | 27 | +| 213 | 0 | 207 | 28 | ## Client diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index d715644222a0..fa7e566583a8 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index efcc57e6a843..7d48db892131 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; Exposes utilities for accessing metrics data -Contact [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) for questions regarding this plugin. +Contact [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 758784316b32..7f436ec13322 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/mock_idp_plugin.mdx b/api_docs/mock_idp_plugin.mdx index 5b30e3fd06ff..db1d4898b129 100644 --- a/api_docs/mock_idp_plugin.mdx +++ b/api_docs/mock_idp_plugin.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mockIdpPlugin title: "mockIdpPlugin" image: https://source.unsplash.com/400x175/?github description: API docs for the mockIdpPlugin plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mockIdpPlugin'] --- import mockIdpPluginObj from './mock_idp_plugin.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index 56b0c4de6567..23ecf827b250 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2024-11-22 +date: 2024-12-03 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 244e38b15e56..e761debc4aa2 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2024-11-22 +date: 2024-12-03 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 1f4170556107..699697eb251b 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2024-11-22 +date: 2024-12-03 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 f2dba3b50380..245a48893309 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index b6a06908fff4..cabc113dcef8 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 5b78cd03a134..6fffbb0d80b3 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.devdocs.json b/api_docs/observability.devdocs.json index 7ff6ef019cc9..89b649746b7a 100644 --- a/api_docs/observability.devdocs.json +++ b/api_docs/observability.devdocs.json @@ -1008,7 +1008,7 @@ "label": "useAnnotations", "description": [], "signature": [ - "({ domain, editAnnotation, slo, setEditAnnotation, }?: { slo?: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined; editAnnotation?: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null | undefined; setEditAnnotation?: ((annotation: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null) => void) | undefined; domain?: { min: string | number; max: string | number; } | undefined; }) => { annotations: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; })[]; onAnnotationClick: (annotations: { rects: ", + "({ domain, editAnnotation, slo, setEditAnnotation, }?: { slo?: ({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined; editAnnotation?: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null | undefined; setEditAnnotation?: ((annotation: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; }) | null) => void) | undefined; domain?: { min: string | number; max: string | number; } | undefined; }) => { annotations: ({ id: string; } & { annotation: { title?: string | undefined; type?: string | undefined; style?: { icon?: string | undefined; color?: string | undefined; line?: { width?: number | undefined; style?: \"dashed\" | \"solid\" | \"dotted\" | undefined; iconPosition?: \"top\" | \"bottom\" | undefined; textDecoration?: \"none\" | \"name\" | undefined; } | undefined; rect?: { fill?: \"inside\" | \"outside\" | undefined; } | undefined; } | undefined; }; '@timestamp': string; message: string; } & { event?: ({ start: string; } & { end?: string | undefined; }) | undefined; tags?: string[] | undefined; service?: { name?: string | undefined; environment?: string | undefined; version?: string | undefined; } | undefined; monitor?: { id?: string | undefined; } | undefined; slo?: ({ id: string; } & { instanceId?: string | undefined; }) | undefined; host?: { name?: string | undefined; } | undefined; })[]; onAnnotationClick: (annotations: { rects: ", "RectAnnotationEvent", "[]; lines: ", "LineAnnotationEvent", @@ -1045,7 +1045,7 @@ "label": "slo", "description": [], "signature": [ - "({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined" + "({ id: string; name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; settings: { syncDelay: string; frequency: string; preventInitialBackfill: boolean; } & { syncField?: string | null | undefined; }; revision: number; enabled: boolean; tags: string[]; createdAt: string; updatedAt: string; groupBy: string | string[]; version: number; } & { summary: { status: \"HEALTHY\" | \"NO_DATA\" | \"DEGRADING\" | \"VIOLATED\"; sliValue: number; errorBudget: { initial: number; consumed: number; remaining: number; isEstimated: boolean; }; fiveMinuteBurnRate: number; oneHourBurnRate: number; oneDayBurnRate: number; } & { summaryUpdatedAt?: string | null | undefined; }; groupings: { [x: string]: string | number; }; } & { instanceId?: string | undefined; meta?: { synthetics?: { monitorId: string; locationId: string; configId: string; } | undefined; } | undefined; remote?: { remoteName: string; kibanaUrl: string; } | undefined; }) | undefined" ], "path": "x-pack/plugins/observability_solution/observability/public/components/annotations/use_annotations.tsx", "deprecated": false, @@ -2863,6 +2863,27 @@ "path": "x-pack/plugins/observability_solution/observability/public/plugin.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-public.ObservabilityPublicPluginsSetup.streams", + "type": "Object", + "tags": [], + "label": "streams", + "description": [], + "signature": [ + { + "pluginId": "streams", + "scope": "public", + "docId": "kibStreamsPluginApi", + "section": "def-public.StreamsPluginSetup", + "text": "StreamsPluginSetup" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/observability/public/plugin.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -3813,6 +3834,27 @@ "path": "x-pack/plugins/observability_solution/observability/public/plugin.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-public.ObservabilityPublicPluginsStart.streams", + "type": "Object", + "tags": [], + "label": "streams", + "description": [], + "signature": [ + { + "pluginId": "streams", + "scope": "public", + "docId": "kibStreamsPluginApi", + "section": "def-public.StreamsPluginStart", + "text": "StreamsPluginStart" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/observability/public/plugin.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -8592,13 +8634,27 @@ "children": [ { "parentPluginId": "observability", - "id": "def-server.ObservabilityRouteCreateOptions.options", - "type": "Object", + "id": "def-server.ObservabilityRouteCreateOptions.tags", + "type": "Array", "tags": [], - "label": "options", + "label": "tags", "description": [], "signature": [ - "{ tags: string[]; access?: \"internal\" | \"public\" | undefined; }" + "string[] | undefined" + ], + "path": "x-pack/plugins/observability_solution/observability/server/routes/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "observability", + "id": "def-server.ObservabilityRouteCreateOptions.access", + "type": "CompoundType", + "tags": [], + "label": "access", + "description": [], + "signature": [ + "\"internal\" | \"public\" | undefined" ], "path": "x-pack/plugins/observability_solution/observability/server/routes/types.ts", "deprecated": false, @@ -8717,20 +8773,6 @@ "path": "x-pack/plugins/observability_solution/observability/server/routes/types.ts", "deprecated": false, "trackAdoption": false - }, - { - "parentPluginId": "observability", - "id": "def-server.ObservabilityRouteHandlerResources.config", - "type": "Object", - "tags": [], - "label": "config", - "description": [], - "signature": [ - "{ readonly enabled: boolean; readonly annotations: Readonly<{} & { index: string; enabled: boolean; }>; readonly unsafe: Readonly<{} & { alertDetails: Readonly<{} & { uptime: Readonly<{} & { enabled: boolean; }>; observability: Readonly<{} & { enabled: boolean; }>; metrics: Readonly<{} & { enabled: boolean; }>; logs: Readonly<{} & { enabled: boolean; }>; }>; thresholdRule: Readonly<{} & { enabled: boolean; }>; ruleFormV2: Readonly<{} & { enabled: boolean; }>; }>; readonly customThresholdRule: Readonly<{} & { groupByPageSize: number; }>; readonly createO11yGenericFeatureId: boolean; }" - ], - "path": "x-pack/plugins/observability_solution/observability/server/routes/types.ts", - "deprecated": false, - "trackAdoption": false } ], "initialIsOpen": false @@ -8762,7 +8804,15 @@ "section": "def-common.RouteParamsRT", "text": "RouteParamsRT" }, - " | undefined, any, any, Record>; }" + " | undefined, any, any, ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRouteCreateOptions", + "text": "ServerRouteCreateOptions" + }, + " | undefined>; }" ], "path": "x-pack/plugins/observability_solution/observability/server/routes/types.ts", "deprecated": false, @@ -8922,15 +8972,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - " ? TReturnType extends ", + " ? TReturnType extends ", { "pluginId": "@kbn/core-http-server", "scope": "server", diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index e13a0cdeffff..e41db5925119 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 695 | 2 | 687 | 23 | +| 697 | 2 | 689 | 23 | ## Client diff --git a/api_docs/observability_a_i_assistant.devdocs.json b/api_docs/observability_a_i_assistant.devdocs.json index 913dfebf5bf4..322e88d27cdf 100644 --- a/api_docs/observability_a_i_assistant.devdocs.json +++ b/api_docs/observability_a_i_assistant.devdocs.json @@ -2418,18 +2418,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -3159,7 +3149,15 @@ "Readable", ", ", "ObservabilityAIAssistantRouteCreateOptions", - ">; }, TEndpoint> & Omit & { signal: AbortSignal | null; }>) => Promise<", + ">; }, TEndpoint> & Omit & { signal: AbortSignal | null; } & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + ">) => Promise<", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -3390,18 +3388,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -4169,7 +4157,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions> extends never ? [] | [", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + "> extends never ? [] | [", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -4177,7 +4173,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions] : [", + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + "] : [", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -4185,7 +4189,15 @@ "section": "def-common.ClientRequestParamsOf", "text": "ClientRequestParamsOf" }, - " & TAdditionalClientOptions]" + " & TAdditionalClientOptions & ", + { + "pluginId": "@kbn/core-http-browser", + "scope": "public", + "docId": "kibKbnCoreHttpBrowserPluginApi", + "section": "def-public.HttpFetchOptions", + "text": "HttpFetchOptions" + }, + "]" ], "path": "packages/kbn-server-route-repository-utils/src/typings.ts", "deprecated": false, @@ -5083,18 +5095,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -5832,15 +5834,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - " ? TReturnType extends ", + " ? TReturnType extends ", { "pluginId": "@kbn/core-http-server", "scope": "server", @@ -6298,18 +6292,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", @@ -7063,7 +7047,7 @@ "section": "def-common.ServerRouteCreateOptions", "text": "ServerRouteCreateOptions" }, - "> ? TRouteParamsRT extends ", + " | undefined> ? TRouteParamsRT extends ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -7277,7 +7261,17 @@ "section": "def-common.AssistantScope", "text": "AssistantScope" }, - "[]; }; }" + "[]; }; } | { type: ", + { + "pluginId": "observabilityAIAssistant", + "scope": "public", + "docId": "kibObservabilityAIAssistantPluginApi", + "section": "def-public.ObservabilityAIAssistantTelemetryEventType", + "text": "ObservabilityAIAssistantTelemetryEventType" + }, + ".InsightResponse; payload: ", + "InsightResponse", + "; }" ], "path": "x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts", "deprecated": false, @@ -8038,18 +8032,8 @@ "<{ id: ", "StringC", "; text: ", - "BrandC", - "<", "StringC", - ", ", - { - "pluginId": "@kbn/io-ts-utils", - "scope": "common", - "docId": "kibKbnIoTsUtilsPluginApi", - "section": "def-common.NonEmptyStringBrand", - "text": "NonEmptyStringBrand" - }, - ">; public: ", + "; public: ", "Type", "; }>; }>, ", "ObservabilityAIAssistantRouteHandlerResources", diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index c583cc169e75..70d5cc9a5c0b 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 296 | 1 | 294 | 27 | +| 296 | 1 | 294 | 28 | ## Client diff --git a/api_docs/observability_a_i_assistant_app.mdx b/api_docs/observability_a_i_assistant_app.mdx index 11da1cf5a2c5..41bb15ce4fe0 100644 --- a/api_docs/observability_a_i_assistant_app.mdx +++ b/api_docs/observability_a_i_assistant_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistantApp title: "observabilityAIAssistantApp" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistantApp plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistantApp'] --- import observabilityAIAssistantAppObj from './observability_a_i_assistant_app.devdocs.json'; diff --git a/api_docs/observability_ai_assistant_management.mdx b/api_docs/observability_ai_assistant_management.mdx index 8ab2193dec67..39d707158fee 100644 --- a/api_docs/observability_ai_assistant_management.mdx +++ b/api_docs/observability_ai_assistant_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAiAssistantManagement title: "observabilityAiAssistantManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAiAssistantManagement plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAiAssistantManagement'] --- import observabilityAiAssistantManagementObj from './observability_ai_assistant_management.devdocs.json'; diff --git a/api_docs/observability_logs_explorer.mdx b/api_docs/observability_logs_explorer.mdx index 01d2931bc5a8..9a8534c58aea 100644 --- a/api_docs/observability_logs_explorer.mdx +++ b/api_docs/observability_logs_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogsExplorer title: "observabilityLogsExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogsExplorer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogsExplorer'] --- import observabilityLogsExplorerObj from './observability_logs_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index 9f205d47a638..0446c0eb1c38 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.devdocs.json b/api_docs/observability_shared.devdocs.json index 24d754631845..f8aa2aed0f6f 100644 --- a/api_docs/observability_shared.devdocs.json +++ b/api_docs/observability_shared.devdocs.json @@ -9417,13 +9417,13 @@ "objects": [ { "parentPluginId": "observabilityShared", - "id": "def-common.ENTITY_TYPES", + "id": "def-common.BUILT_IN_ENTITY_TYPES", "type": "Object", "tags": [], - "label": "ENTITY_TYPES", + "label": "BUILT_IN_ENTITY_TYPES", "description": [], "signature": [ - "{ readonly HOST: \"host\"; readonly CONTAINER: \"container\"; readonly SERVICE: \"service\"; readonly KUBERNETES: { readonly CLUSTER: { ecs: \"kubernetes_cluster_ecs\"; semconv: \"kubernetes_cluster_semconv\"; }; readonly CONTAINER: { ecs: \"kubernetes_container_ecs\"; semconv: \"kubernetes_container_semconv\"; }; readonly CRONJOB: { ecs: \"kubernetes_cron_job_ecs\"; semconv: \"kubernetes_cron_job_semconv\"; }; readonly DAEMONSET: { ecs: \"kubernetes_daemon_set_ecs\"; semconv: \"kubernetes_daemon_set_semconv\"; }; readonly DEPLOYMENT: { ecs: \"kubernetes_deployment_ecs\"; semconv: \"kubernetes_deployment_semconv\"; }; readonly JOB: { ecs: \"kubernetes_job_ecs\"; semconv: \"kubernetes_job_semconv\"; }; readonly NAMESPACE: { ecs: \"kubernetes_namespace_ecs\"; semconv: \"kubernetes_namespace_semconv\"; }; readonly NODE: { ecs: \"kubernetes_node_ecs\"; semconv: \"kubernetes_node_semconv\"; }; readonly POD: { ecs: \"kubernetes_pod_ecs\"; semconv: \"kubernetes_pod_semconv\"; }; readonly STATEFULSET: { ecs: \"kubernetes_stateful_set_ecs\"; semconv: \"kubernetes_stateful_set_semconv\"; }; }; }" + "{ readonly HOST: \"host\"; readonly CONTAINER: \"container\"; readonly SERVICE: \"service\"; readonly KUBERNETES: { readonly CLUSTER: { ecs: \"k8s.cluster.ecs\"; semconv: \"k8s.cluster.semconv\"; }; readonly CONTAINER: { ecs: \"k8s.container.ecs\"; semconv: \"k8s.container.semconv\"; }; readonly CRONJOB: { ecs: \"k8s.cron_job.ecs\"; semconv: \"k8s.cron_job.semconv\"; }; readonly DAEMONSET: { ecs: \"k8s.daemonset.ecs\"; semconv: \"k8s.daemonset.semconv\"; }; readonly DEPLOYMENT: { ecs: \"k8s.deployment.ecs\"; semconv: \"k8s.deployment.semconv\"; }; readonly JOB: { ecs: \"k8s.job.ecs\"; semconv: \"k8s.job.semconv\"; }; readonly NAMESPACE: { ecs: \"k8s.namespace.ecs\"; semconv: \"k8s.namespace.semconv\"; }; readonly NODE: { ecs: \"k8s.node.ecs\"; semconv: \"k8s.node.semconv\"; }; readonly POD: { ecs: \"k8s.pod.ecs\"; semconv: \"k8s.pod.semconv\"; }; readonly SERVICE: { ecs: \"k8s.service.ecs\"; semconv: \"k8s.service.semconv\"; }; readonly STATEFULSET: { ecs: \"k8s.statefulset.ecs\"; semconv: \"k8s.statefulset.semconv\"; }; }; }" ], "path": "x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts", "deprecated": false, diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 878e058030c2..3784f6203d55 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 64e5de0e2b42..bf64f7fd4fd9 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index 3b7ec39b0ea8..3916ebb5cb95 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index bacd3236a5a3..d321ce8d8ca2 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,29 +15,29 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 887 | 757 | 47 | +| 895 | 762 | 43 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 54464 | 247 | 40907 | 2015 | +| 54810 | 240 | 41195 | 2033 | ## Plugin Directory | Plugin name           | Maintaining team | Description | API Cnt | Any Cnt | Missing
comments | Missing
exports | |--------------|----------------|-----------|--------------|----------|---------------|--------| -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 322 | 0 | 316 | 37 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 321 | 0 | 315 | 37 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 4 | 0 | 4 | 1 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 4 | 0 | 4 | 1 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | AIOps plugin maintained by ML team. | 72 | 0 | 8 | 2 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 880 | 1 | 848 | 50 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | The user interface for Elastic APM | 29 | 0 | 29 | 119 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 86 | 0 | 86 | 3 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 93 | 0 | 93 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 9 | 0 | 9 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Considering using bfetch capabilities when fetching large amounts of data. This services supports batching HTTP requests and streaming responses back. | 60 | 1 | 59 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Canvas application to Kibana | 9 | 0 | 8 | 3 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 126 | 0 | 106 | 28 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | The Case management system in Kibana | 125 | 0 | 105 | 28 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 267 | 2 | 252 | 9 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 83 | 0 | 20 | 1 | | cloudChat | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | Chat available on Elastic Cloud deployments for quicker assistance. | 0 | 0 | 0 | 0 | @@ -57,7 +57,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3209 | 31 | 2594 | 24 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 6 | 0 | 6 | 0 | -| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 10 | 0 | 10 | 0 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 9 | 0 | 9 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 35 | 0 | 25 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Reusable data view field editor across Kibana | 72 | 0 | 33 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data view management app | 2 | 0 | 2 | 0 | @@ -65,9 +65,9 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 31 | 3 | 25 | 4 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin introduces the concept of data set quality, where users can easily get an overview on the data sets they have. | 14 | 0 | 14 | 8 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 15 | 0 | 9 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 148 | 0 | 100 | 24 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 214 | 0 | 166 | 30 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 35 | 0 | 33 | 2 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A stateful layer to register shared features and provide an access point to discover without a direct dependency | 16 | 0 | 15 | 3 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | A stateful layer to register shared features and provide an access point to discover without a direct dependency | 26 | 0 | 23 | 2 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | Server APIs for the Elastic AI Assistant | 53 | 0 | 38 | 2 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds embeddables service to Kibana | 578 | 1 | 468 | 9 | @@ -75,7 +75,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides encryption and decryption utilities for saved objects containing sensitive information. | 54 | 0 | 47 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Adds dashboards for discovering and managing Enterprise Search products. | 5 | 0 | 5 | 0 | | | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | - | 2 | 0 | 2 | 0 | -| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | Entity manager plugin for entity assets (inventory, topology, etc) | 20 | 0 | 20 | 3 | +| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | Entity manager plugin for entity assets (inventory, topology, etc) | 37 | 0 | 37 | 3 | +| entityManagerApp | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | Entity manager plugin for entity assets (inventory, topology, etc) | 0 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 99 | 3 | 97 | 3 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 25 | 0 | 9 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 2 | 0 | 2 | 0 | @@ -103,7 +104,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | 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. | 89 | 0 | 89 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | File upload, download, sharing, and serving over HTTP implementation in Kibana. | 240 | 0 | 24 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Simple UI for managing files in Kibana | 3 | 0 | 3 | 0 | -| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1428 | 5 | 1303 | 81 | +| | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | - | 1435 | 5 | 1309 | 82 | | ftrApis | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 72 | 0 | 14 | 5 | | globalSearchBar | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 0 | 0 | 0 | 0 | @@ -115,7 +116,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Image embeddable | 1 | 0 | 1 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 244 | 0 | 239 | 1 | -| | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 40 | 0 | 29 | 6 | +| | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 40 | 0 | 28 | 6 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin visualizes data from Filebeat and Metricbeat, and integrates with other Observability solutions | 24 | 0 | 24 | 5 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 0 | | inputControlVis | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds Input Control visualization to Kibana | 0 | 0 | 0 | 0 | @@ -130,21 +131,21 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | kibanaUsageCollection | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 610 | 3 | 417 | 9 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 5 | 0 | 5 | 1 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 693 | 0 | 591 | 62 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Visualization editor allowing to quickly and easily configure compelling visualizations to use on dashboards and canvas workpads. Exposes components to embed visualizations and link into the Lens editor from within other apps in Kibana. | 647 | 0 | 548 | 60 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 8 | 0 | 8 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 4 | 0 | 4 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 119 | 0 | 42 | 10 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | A dashboard panel for creating links to dashboards or external links. | 5 | 0 | 5 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 227 | 0 | 98 | 52 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 5 | 0 | 1 | 2 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 15 | 0 | 13 | 7 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 15 | 0 | 13 | 7 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin provides a LogsExplorer component using the Discover customization framework, offering several affordances specifically designed for log consumption. | 120 | 4 | 120 | 23 | -| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes the shared components and APIs to access and visualize logs. | 314 | 0 | 285 | 34 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | Exposes the shared components and APIs to access and visualize logs. | 316 | 0 | 287 | 34 | | logstash | [@elastic/logstash](https://github.com/orgs/elastic/teams/logstash) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 44 | 0 | 44 | 7 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 209 | 0 | 205 | 27 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 213 | 0 | 207 | 28 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 60 | 0 | 60 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | Exposes utilities for accessing metrics data | 135 | 6 | 135 | 5 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | Exposes utilities for accessing metrics data | 135 | 6 | 135 | 5 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the machine learning features provided by Elastic. | 148 | 3 | 63 | 104 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 2 | 0 | 2 | 0 | | | [@elastic/stack-monitoring](https://github.com/orgs/elastic/teams/stack-monitoring) | - | 15 | 3 | 13 | 1 | @@ -153,8 +154,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 17 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 3 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 1 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 695 | 2 | 687 | 23 | -| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 296 | 1 | 294 | 27 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 697 | 2 | 689 | 23 | +| | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 296 | 1 | 294 | 28 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 4 | 0 | 4 | 0 | | | [@elastic/obs-ai-assistant](https://github.com/orgs/elastic/teams/obs-ai-assistant) | - | 2 | 0 | 2 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | This plugin exposes and registers observability log consumption features. | 19 | 0 | 19 | 1 | @@ -173,7 +174,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 263 | 0 | 226 | 10 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 24 | 0 | 19 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 97 | 2 | 96 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 25 | 0 | 25 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 26 | 0 | 26 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 148 | 0 | 139 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 0 | 30 | 3 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 105 | 0 | 58 | 0 | @@ -185,11 +186,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 10 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 18 | 0 | 18 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 11 | 0 | 7 | 1 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 21 | 0 | 21 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Plugin to provide access to and rendering of python notebooks for use in the persistent developer console. | 10 | 0 | 10 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 22 | 0 | 16 | 1 | | searchprofiler | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 455 | 0 | 238 | 0 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 187 | 0 | 119 | 33 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 191 | 0 | 123 | 34 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | ESS customizations for Security Solution. | 6 | 0 | 6 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Serverless customizations for security. | 7 | 0 | 7 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | The core Serverless plugin, providing APIs to Serverless Project plugins. | 25 | 0 | 24 | 0 | @@ -197,12 +199,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | Serverless customizations for search. | 7 | 0 | 7 | 0 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 134 | 0 | 134 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds URL Service and sharing capabilities to Kibana | 136 | 0 | 73 | 15 | -| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 45 | 0 | 45 | 4 | +| | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 47 | 0 | 47 | 2 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 22 | 1 | 22 | 1 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides the Spaces feature, which allows saved objects to be organized into meaningful categories. | 269 | 0 | 73 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 25 | 0 | 25 | 3 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 10 | 0 | 10 | 0 | -| | @simianhacker @flash1293 @dgieselaar | A manager for Streams | 12 | 7 | 12 | 2 | +| | @simianhacker @flash1293 @dgieselaar | A manager for Streams | 13 | 0 | 13 | 4 | +| | @simianhacker @flash1293 @dgieselaar | - | 8 | 0 | 8 | 0 | | synthetics | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | This plugin visualizes data from Synthetics and Heartbeat, and integrates with other Observability solutions. | 0 | 0 | 0 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 108 | 0 | 64 | 7 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 45 | 0 | 1 | 0 | @@ -210,14 +213,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | telemetryCollectionXpack | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 0 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 0 | 0 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats | 30 | 0 | 14 | 4 | -| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 226 | 1 | 182 | 17 | +| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 236 | 1 | 192 | 18 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | This plugin provides access to the transforms features provided by Elastic. Transforms enable you to convert existing Elasticsearch indices into summarized indices, which provide opportunities for new insights and analytics. | 4 | 0 | 4 | 1 | | translations | [@elastic/kibana-localization](https://github.com/orgs/elastic/teams/kibana-localization) | - | 0 | 0 | 0 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 594 | 1 | 568 | 51 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Adds UI Actions service to Kibana | 156 | 0 | 110 | 9 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Extends UI Actions plugin with more functionality | 212 | 0 | 145 | 11 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains services reliant on the plugin lifecycle for the unified doc viewer component (see @kbn/unified-doc-viewer). | 15 | 0 | 10 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 70 | 0 | 35 | 6 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | The `unifiedHistogram` plugin provides UI components to create a layout including a resizable histogram and a main display. | 69 | 0 | 35 | 6 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Contains all the key functionality of Kibana's unified search experience.Contains all the key functionality of Kibana's unified search experience. | 149 | 2 | 112 | 21 | | upgradeAssistant | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 0 | 0 | 0 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | This plugin visualizes data from Heartbeat, and integrates with other Observability solutions. | 1 | 0 | 1 | 0 | @@ -248,7 +251,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 14 | 0 | 14 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 64 | 0 | 64 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3 | 0 | 3 | 0 | -| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 36 | 0 | 0 | 0 | +| | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 37 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 2 | 0 | 0 | 0 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | - | 66 | 0 | 0 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 27 | 3 | 27 | 0 | @@ -257,13 +260,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 243 | 0 | 240 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 33 | 0 | 33 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 31 | 0 | 15 | 1 | -| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 320 | 0 | 304 | 8 | +| | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 321 | 0 | 305 | 8 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 73 | 0 | 73 | 2 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 18 | 0 | 18 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 4 | 0 | 4 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 87 | 0 | 87 | 11 | -| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 268 | 0 | 268 | 38 | +| | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 272 | 0 | 272 | 38 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 337 | 0 | 336 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 12 | 0 | 12 | 0 | | | [@elastic/security-defend-workflows](https://github.com/orgs/elastic/teams/security-defend-workflows) | - | 3 | 0 | 3 | 0 | @@ -280,8 +283,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 62 | 0 | 17 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 2 | 0 | -| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 89 | 1 | 89 | 0 | -| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 109 | 0 | 107 | 1 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 93 | 1 | 93 | 0 | +| | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 122 | 0 | 120 | 1 | | | [@elastic/kibana-cloud-security-posture](https://github.com/orgs/elastic/teams/kibana-cloud-security-posture) | - | 20 | 0 | 15 | 4 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 41 | 0 | 17 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | @@ -377,9 +380,10 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 54 | 7 | 54 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 15 | 0 | 15 | 1 | -| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 568 | 2 | 242 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 567 | 2 | 242 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 96 | 0 | 83 | 10 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 46 | 0 | 45 | 0 | +| | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 6 | 0 | 2 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 2 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 3 | 0 | 3 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 4 | 0 | 1 | 0 | @@ -509,28 +513,28 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 38 | 2 | 33 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 37 | 0 | 34 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 284 | 0 | 234 | 4 | -| | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 78 | 0 | 78 | 2 | +| | [@elastic/docs](https://github.com/orgs/elastic/teams/docs) | - | 80 | 0 | 80 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 5 | 0 | 5 | 1 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 57 | 0 | 30 | 6 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 37 | 0 | 28 | 2 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 16 | 0 | 8 | 0 | | | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 42 | 0 | 41 | 0 | -| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 169 | 0 | 140 | 10 | +| | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 170 | 0 | 141 | 10 | | | [@elastic/security-generative-ai](https://github.com/orgs/elastic/teams/security-generative-ai) | - | 442 | 0 | 405 | 0 | -| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | - | 45 | 0 | 45 | 0 | +| | [@elastic/obs-entities](https://github.com/orgs/elastic/teams/obs-entities) | - | 51 | 0 | 51 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 55 | 0 | 40 | 7 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 32 | 0 | 19 | 1 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 11 | 0 | 6 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 271 | 1 | 210 | 14 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 30 | 0 | 30 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | -| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 277 | 1 | 216 | 36 | +| | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 283 | 1 | 222 | 36 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 29 | 0 | 12 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 83 | 0 | 74 | 0 | | | [@elastic/kibana-esql](https://github.com/orgs/elastic/teams/kibana-esql) | - | 205 | 0 | 193 | 12 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 40 | 0 | 40 | 0 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | -| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 44 | 0 | 17 | 3 | +| | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 41 | 0 | 14 | 2 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 22 | 0 | 18 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 51 | 0 | 42 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 0 | 0 | @@ -540,7 +544,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 0 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 26 | 0 | 26 | 1 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 16 | 0 | 16 | 1 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 17 | 0 | 17 | 1 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 17 | 0 | 12 | 11 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 49 | 0 | 47 | 0 | | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | - | 33 | 3 | 24 | 6 | @@ -581,8 +585,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 23 | 0 | 7 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 8 | 0 | 2 | 3 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 45 | 0 | 0 | 0 | -| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 140 | 0 | 139 | 0 | -| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 20 | 0 | 11 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 140 | 0 | 139 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 20 | 0 | 11 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 88 | 0 | 10 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 56 | 0 | 6 | 0 | | | [@elastic/kibana-management](https://github.com/orgs/elastic/teams/kibana-management) | - | 2 | 0 | 0 | 0 | @@ -626,7 +630,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 5 | 0 | 5 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 99 | 1 | 99 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 6 | 0 | 6 | 1 | -| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 29 | 0 | 27 | 4 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 29 | 0 | 27 | 5 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 4 | 0 | 4 | 1 | | | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 12 | 0 | 12 | 0 | | | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 15 | 0 | 15 | 0 | @@ -639,7 +643,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 1 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 92 | 0 | 80 | 0 | -| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 224 | 0 | 188 | 6 | +| | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 229 | 0 | 193 | 6 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-ai-infra](https://github.com/orgs/elastic/teams/appex-ai-infra) | - | 31 | 0 | 31 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 168 | 0 | 55 | 0 | @@ -656,7 +660,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 18 | 0 | 18 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 40 | 0 | 38 | 5 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 13 | 0 | 9 | 0 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 6 | 1 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 14 | 0 | 7 | 1 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 98 | 0 | 88 | 13 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 13 | 0 | 13 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 36 | 0 | 36 | 2 | @@ -678,11 +682,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 16 | 0 | 16 | 1 | | | [@elastic/security-detections-response](https://github.com/orgs/elastic/teams/security-detections-response) | - | 138 | 0 | 135 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | +| | [@elastic/obs-ux-logs-team](https://github.com/orgs/elastic/teams/obs-ux-logs-team) | - | 15 | 0 | 14 | 0 | +| | [@elastic/appex-qa](https://github.com/orgs/elastic/teams/appex-qa) | - | 119 | 0 | 86 | 8 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 35 | 0 | 34 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 8 | 0 | 8 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3 | 0 | 3 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 76 | 0 | 76 | 0 | -| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3948 | 0 | 3948 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 3954 | 0 | 3954 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 18 | 1 | 17 | 1 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 36 | 0 | 34 | 3 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 20 | 0 | 18 | 1 | @@ -719,16 +725,16 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 211 | 0 | 162 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 28 | 0 | 25 | 0 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 120 | 0 | 116 | 0 | -| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 60 | 0 | 54 | 0 | +| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 63 | 0 | 55 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 69 | 0 | 64 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 42 | 0 | 42 | 0 | +| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 39 | 0 | 39 | 0 | | | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 15 | 0 | 15 | 0 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 30 | 0 | 30 | 2 | -| | [@elastic/appex-sharedux @elastic/kibana-management](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 1 | 0 | 1 | 0 | -| | [@elastic/appex-sharedux @elastic/kibana-management @elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/appex-sharedux ) | - | 1 | 0 | 1 | 0 | +| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 28 | 0 | 28 | 2 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 1 | 0 | 1 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 7 | 1 | -| | [@elastic/search-kibana @elastic/kibana-management](https://github.com/orgs/elastic/teams/search-kibana ) | - | 1 | 0 | 1 | 0 | -| | [@elastic/security-solution @elastic/kibana-management](https://github.com/orgs/elastic/teams/security-solution ) | - | 1 | 0 | 1 | 0 | +| | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 1 | 0 | 1 | 0 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 1 | 0 | 1 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 0 | 0 | | | [@elastic/obs-ux-infra_services-team](https://github.com/orgs/elastic/teams/obs-ux-infra_services-team) | - | 5 | 0 | 5 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 2 | 2 | @@ -783,7 +789,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 32 | 2 | 32 | 0 | | | [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/obs-ux-management-team) | - | 19 | 0 | 19 | 0 | | | [@elastic/kibana-core](https://github.com/orgs/elastic/teams/kibana-core) | - | 7 | 0 | 5 | 1 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 320 | 4 | 272 | 14 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 353 | 4 | 298 | 14 | | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 37 | 1 | 19 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 131 | 3 | 98 | 2 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 1 | 0 | @@ -792,12 +798,12 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 9 | 0 | 7 | 0 | | | [@elastic/response-ops](https://github.com/orgs/elastic/teams/response-ops) | - | 15 | 0 | 15 | 0 | | | [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) | - | 2 | 0 | 2 | 1 | -| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 39 | 0 | 25 | 1 | -| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 86 | 0 | 86 | 1 | +| | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 40 | 0 | 25 | 1 | +| | [@elastic/obs-knowledge-team](https://github.com/orgs/elastic/teams/obs-knowledge-team) | - | 92 | 0 | 92 | 2 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 42 | 0 | 28 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 61 | 0 | 52 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 9 | 0 | 8 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 184 | 0 | 108 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the unified data table which can be integrated into apps | 186 | 0 | 109 | 1 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 18 | 0 | 17 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Contains functionality for the field list and field stats which can be integrated into apps | 317 | 0 | 288 | 8 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 13 | 0 | 9 | 0 | diff --git a/api_docs/presentation_panel.mdx b/api_docs/presentation_panel.mdx index 7b01ef460a9c..ba7ad19e35c1 100644 --- a/api_docs/presentation_panel.mdx +++ b/api_docs/presentation_panel.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationPanel title: "presentationPanel" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationPanel plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationPanel'] --- import presentationPanelObj from './presentation_panel.devdocs.json'; diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index 370b3a29ab49..608ee8ec6052 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/product_doc_base.mdx b/api_docs/product_doc_base.mdx index 6f37accb2327..b4d5a3abd7bb 100644 --- a/api_docs/product_doc_base.mdx +++ b/api_docs/product_doc_base.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/productDocBase title: "productDocBase" image: https://source.unsplash.com/400x175/?github description: API docs for the productDocBase plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'productDocBase'] --- import productDocBaseObj from './product_doc_base.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 84148793290b..e483cfd96c65 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index a126eee9f130..acc71b8508e7 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index ffb7dafceff4..0c8f1c61f827 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2024-11-22 +date: 2024-12-03 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 77ab774652a2..35957e03e59f 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2024-11-22 +date: 2024-12-03 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 5c6de0ea3fea..774258153466 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index 0d285a2b751d..a2312f45d5df 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2024-11-22 +date: 2024-12-03 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 05ec2fb29f0f..4e8cb4f0a32f 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2024-11-22 +date: 2024-12-03 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 d3a810154ffa..bb90830dba62 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.devdocs.json b/api_docs/saved_objects_finder.devdocs.json index 866969ae30c3..c6104240fef8 100644 --- a/api_docs/saved_objects_finder.devdocs.json +++ b/api_docs/saved_objects_finder.devdocs.json @@ -533,6 +533,20 @@ "path": "src/plugins/saved_objects_finder/common/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "savedObjectsFinder", + "id": "def-common.FinderAttributes.description", + "type": "string", + "tags": [], + "label": "description", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "src/plugins/saved_objects_finder/common/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 7ef035785acd..0d9cdee95f93 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 25 | 0 | 25 | 1 | +| 26 | 0 | 26 | 1 | ## Client diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 607032b173e1..15bd21d5b6d1 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2024-11-22 +date: 2024-12-03 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 38664c94a97b..ec1638958e02 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2024-11-22 +date: 2024-12-03 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 6b9877691d61..a613566c6077 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2024-11-22 +date: 2024-12-03 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 a57d40cdae1f..56a59050b905 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2024-11-22 +date: 2024-12-03 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 0409c2b38ef8..0086b8cb10a9 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2024-11-22 +date: 2024-12-03 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 ab0e270d9f0c..c06d70c38dd9 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/search_assistant.mdx b/api_docs/search_assistant.mdx index f67cffe88f10..30858fc27f43 100644 --- a/api_docs/search_assistant.mdx +++ b/api_docs/search_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchAssistant title: "searchAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the searchAssistant plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchAssistant'] --- import searchAssistantObj from './search_assistant.devdocs.json'; diff --git a/api_docs/search_connectors.mdx b/api_docs/search_connectors.mdx index b46fb0f713d3..72f4f46714b7 100644 --- a/api_docs/search_connectors.mdx +++ b/api_docs/search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchConnectors title: "searchConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the searchConnectors plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchConnectors'] --- import searchConnectorsObj from './search_connectors.devdocs.json'; diff --git a/api_docs/search_homepage.mdx b/api_docs/search_homepage.mdx index 80b0b327debf..c90944ba6218 100644 --- a/api_docs/search_homepage.mdx +++ b/api_docs/search_homepage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchHomepage title: "searchHomepage" image: https://source.unsplash.com/400x175/?github description: API docs for the searchHomepage plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchHomepage'] --- import searchHomepageObj from './search_homepage.devdocs.json'; diff --git a/api_docs/search_indices.devdocs.json b/api_docs/search_indices.devdocs.json index 8b486873528f..8446bc09cbb0 100644 --- a/api_docs/search_indices.devdocs.json +++ b/api_docs/search_indices.devdocs.json @@ -85,7 +85,7 @@ "label": "startAppId", "description": [], "signature": [ - "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"serverlessWebCrawlers\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"streams\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"serverlessWebCrawlers\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"streams:overview\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:siem_migrations-rules\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" ], "path": "x-pack/plugins/search_indices/public/types.ts", "deprecated": false, diff --git a/api_docs/search_indices.mdx b/api_docs/search_indices.mdx index 0ce9640fe762..fd27a066f005 100644 --- a/api_docs/search_indices.mdx +++ b/api_docs/search_indices.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchIndices title: "searchIndices" image: https://source.unsplash.com/400x175/?github description: API docs for the searchIndices plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchIndices'] --- import searchIndicesObj from './search_indices.devdocs.json'; diff --git a/api_docs/search_inference_endpoints.mdx b/api_docs/search_inference_endpoints.mdx index eafd7f17bb87..56b3db801e11 100644 --- a/api_docs/search_inference_endpoints.mdx +++ b/api_docs/search_inference_endpoints.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchInferenceEndpoints title: "searchInferenceEndpoints" image: https://source.unsplash.com/400x175/?github description: API docs for the searchInferenceEndpoints plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchInferenceEndpoints'] --- import searchInferenceEndpointsObj from './search_inference_endpoints.devdocs.json'; diff --git a/api_docs/search_navigation.devdocs.json b/api_docs/search_navigation.devdocs.json new file mode 100644 index 000000000000..9f9ff7e4294c --- /dev/null +++ b/api_docs/search_navigation.devdocs.json @@ -0,0 +1,390 @@ +{ + "id": "searchNavigation", + "client": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem", + "type": "Interface", + "tags": [], + "label": "ClassicNavItem", + "description": [], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem.datatestsubj", + "type": "string", + "tags": [], + "label": "'data-test-subj'", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem.deepLink", + "type": "Object", + "tags": [], + "label": "deepLink", + "description": [], + "signature": [ + { + "pluginId": "searchNavigation", + "scope": "public", + "docId": "kibSearchNavigationPluginApi", + "section": "def-public.ClassicNavItemDeepLink", + "text": "ClassicNavItemDeepLink" + }, + " | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem.iconToString", + "type": "string", + "tags": [], + "label": "iconToString", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem.id", + "type": "string", + "tags": [], + "label": "id", + "description": [], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem.items", + "type": "Array", + "tags": [], + "label": "items", + "description": [], + "signature": [ + { + "pluginId": "searchNavigation", + "scope": "public", + "docId": "kibSearchNavigationPluginApi", + "section": "def-public.ClassicNavItem", + "text": "ClassicNavItem" + }, + "[] | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItem.name", + "type": "CompoundType", + "tags": [], + "label": "name", + "description": [], + "signature": [ + "string | number | boolean | React.ReactElement> | Iterable | React.ReactPortal | null | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItemDeepLink", + "type": "Interface", + "tags": [], + "label": "ClassicNavItemDeepLink", + "description": [], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItemDeepLink.link", + "type": "CompoundType", + "tags": [], + "label": "link", + "description": [], + "signature": [ + "\"fleet\" | \"graph\" | \"ml\" | \"monitoring\" | \"profiling\" | \"metrics\" | \"management\" | \"apm\" | \"synthetics\" | \"ux\" | \"canvas\" | \"logs\" | \"dashboards\" | \"slo\" | \"observabilityAIAssistant\" | \"home\" | \"integrations\" | \"discover\" | \"observability-overview\" | \"streams\" | \"appSearch\" | \"dev_tools\" | \"maps\" | \"visualize\" | \"dev_tools:console\" | \"dev_tools:searchprofiler\" | \"dev_tools:painless_lab\" | \"dev_tools:grokdebugger\" | \"ml:notifications\" | \"ml:nodes\" | \"ml:overview\" | \"ml:memoryUsage\" | \"ml:settings\" | \"ml:dataVisualizer\" | \"ml:logPatternAnalysis\" | \"ml:logRateAnalysis\" | \"ml:singleMetricViewer\" | \"ml:anomalyDetection\" | \"ml:anomalyExplorer\" | \"ml:dataDrift\" | \"ml:dataFrameAnalytics\" | \"ml:resultExplorer\" | \"ml:analyticsMap\" | \"ml:aiOps\" | \"ml:changePointDetections\" | \"ml:modelManagement\" | \"ml:nodesOverview\" | \"ml:esqlDataVisualizer\" | \"ml:fileUpload\" | \"ml:indexDataVisualizer\" | \"ml:calendarSettings\" | \"ml:filterListsSettings\" | \"ml:suppliedConfigurations\" | \"osquery\" | \"management:transform\" | \"management:watcher\" | \"management:cases\" | \"management:tags\" | \"management:maintenanceWindows\" | \"management:cross_cluster_replication\" | \"management:dataViews\" | \"management:spaces\" | \"management:settings\" | \"management:users\" | \"management:migrate_data\" | \"management:search_sessions\" | \"management:data_quality\" | \"management:filesManagement\" | \"management:roles\" | \"management:reporting\" | \"management:aiAssistantManagementSelection\" | \"management:securityAiAssistantManagement\" | \"management:observabilityAiAssistantManagement\" | \"management:api_keys\" | \"management:license_management\" | \"management:index_lifecycle_management\" | \"management:index_management\" | \"management:ingest_pipelines\" | \"management:jobsListLink\" | \"management:objects\" | \"management:pipelines\" | \"management:remote_clusters\" | \"management:role_mappings\" | \"management:rollup_jobs\" | \"management:snapshot_restore\" | \"management:triggersActions\" | \"management:triggersActionsConnectors\" | \"management:upgrade_assistant\" | \"enterpriseSearch\" | \"enterpriseSearchContent\" | \"enterpriseSearchApplications\" | \"searchInferenceEndpoints\" | \"enterpriseSearchAnalytics\" | \"workplaceSearch\" | \"serverlessElasticsearch\" | \"serverlessConnectors\" | \"serverlessWebCrawlers\" | \"searchPlayground\" | \"searchHomepage\" | \"enterpriseSearchContent:connectors\" | \"enterpriseSearchContent:searchIndices\" | \"enterpriseSearchContent:webCrawlers\" | \"enterpriseSearchApplications:searchApplications\" | \"enterpriseSearchApplications:playground\" | \"appSearch:engines\" | \"searchInferenceEndpoints:inferenceEndpoints\" | \"elasticsearchStart\" | \"elasticsearchIndices\" | \"enterpriseSearchElasticsearch\" | \"enterpriseSearchVectorSearch\" | \"enterpriseSearchSemanticSearch\" | \"enterpriseSearchAISearch\" | \"elasticsearchIndices:createIndex\" | \"observability-logs-explorer\" | \"last-used-logs-viewer\" | \"observabilityOnboarding\" | \"inventory\" | \"logs:settings\" | \"logs:stream\" | \"logs:log-categories\" | \"logs:anomalies\" | \"observability-overview:cases\" | \"observability-overview:alerts\" | \"observability-overview:rules\" | \"observability-overview:cases_create\" | \"observability-overview:cases_configure\" | \"metrics:settings\" | \"metrics:hosts\" | \"metrics:inventory\" | \"metrics:metrics-explorer\" | \"metrics:assetDetails\" | \"apm:services\" | \"apm:traces\" | \"apm:dependencies\" | \"apm:service-map\" | \"apm:settings\" | \"apm:service-groups-list\" | \"apm:storage-explorer\" | \"synthetics:overview\" | \"synthetics:certificates\" | \"profiling:functions\" | \"profiling:stacktraces\" | \"profiling:flamegraphs\" | \"inventory:datastreams\" | \"streams:overview\" | \"securitySolutionUI\" | \"securitySolutionUI:\" | \"securitySolutionUI:cases\" | \"securitySolutionUI:alerts\" | \"securitySolutionUI:rules\" | \"securitySolutionUI:policy\" | \"securitySolutionUI:overview\" | \"securitySolutionUI:dashboards\" | \"securitySolutionUI:kubernetes\" | \"securitySolutionUI:cases_create\" | \"securitySolutionUI:cases_configure\" | \"securitySolutionUI:hosts\" | \"securitySolutionUI:users\" | \"securitySolutionUI:cloud_defend-policies\" | \"securitySolutionUI:cloud_security_posture-dashboard\" | \"securitySolutionUI:cloud_security_posture-findings\" | \"securitySolutionUI:cloud_security_posture-benchmarks\" | \"securitySolutionUI:network\" | \"securitySolutionUI:data_quality\" | \"securitySolutionUI:explore\" | \"securitySolutionUI:assets\" | \"securitySolutionUI:cloud_defend\" | \"securitySolutionUI:notes\" | \"securitySolutionUI:administration\" | \"securitySolutionUI:attack_discovery\" | \"securitySolutionUI:blocklist\" | \"securitySolutionUI:cloud_security_posture-rules\" | \"securitySolutionUI:detections\" | \"securitySolutionUI:detection_response\" | \"securitySolutionUI:endpoints\" | \"securitySolutionUI:event_filters\" | \"securitySolutionUI:exceptions\" | \"securitySolutionUI:host_isolation_exceptions\" | \"securitySolutionUI:hosts-all\" | \"securitySolutionUI:hosts-anomalies\" | \"securitySolutionUI:hosts-risk\" | \"securitySolutionUI:hosts-events\" | \"securitySolutionUI:hosts-sessions\" | \"securitySolutionUI:hosts-uncommon_processes\" | \"securitySolutionUI:investigations\" | \"securitySolutionUI:get_started\" | \"securitySolutionUI:machine_learning-landing\" | \"securitySolutionUI:network-anomalies\" | \"securitySolutionUI:network-dns\" | \"securitySolutionUI:network-events\" | \"securitySolutionUI:network-flows\" | \"securitySolutionUI:network-http\" | \"securitySolutionUI:network-tls\" | \"securitySolutionUI:response_actions_history\" | \"securitySolutionUI:rules-add\" | \"securitySolutionUI:rules-create\" | \"securitySolutionUI:rules-landing\" | \"securitySolutionUI:siem_migrations-rules\" | \"securitySolutionUI:threat_intelligence\" | \"securitySolutionUI:timelines\" | \"securitySolutionUI:timelines-templates\" | \"securitySolutionUI:trusted_apps\" | \"securitySolutionUI:users-all\" | \"securitySolutionUI:users-anomalies\" | \"securitySolutionUI:users-authentications\" | \"securitySolutionUI:users-events\" | \"securitySolutionUI:users-risk\" | \"securitySolutionUI:entity_analytics\" | \"securitySolutionUI:entity_analytics-management\" | \"securitySolutionUI:entity_analytics-asset-classification\" | \"securitySolutionUI:entity_analytics-entity_store_management\" | \"securitySolutionUI:coverage-overview\" | \"fleet:settings\" | \"fleet:agents\" | \"fleet:policies\" | \"fleet:data_streams\" | \"fleet:enrollment_tokens\" | \"fleet:uninstall_tokens\"" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.ClassicNavItemDeepLink.shouldShowActiveForSubroutes", + "type": "CompoundType", + "tags": [], + "label": "shouldShowActiveForSubroutes", + "description": [], + "signature": [ + "boolean | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginSetup", + "type": "Interface", + "tags": [], + "label": "SearchNavigationPluginSetup", + "description": [], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart", + "type": "Interface", + "tags": [], + "label": "SearchNavigationPluginStart", + "description": [], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.registerOnAppMountHandler", + "type": "Function", + "tags": [], + "label": "registerOnAppMountHandler", + "description": [], + "signature": [ + "(onAppMount: () => Promise) => void" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.registerOnAppMountHandler.$1", + "type": "Function", + "tags": [], + "label": "onAppMount", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.handleOnAppMount", + "type": "Function", + "tags": [], + "label": "handleOnAppMount", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.setGetBaseClassicNavItems", + "type": "Function", + "tags": [], + "label": "setGetBaseClassicNavItems", + "description": [], + "signature": [ + "(classicNavItemsFn: () => ", + { + "pluginId": "searchNavigation", + "scope": "public", + "docId": "kibSearchNavigationPluginApi", + "section": "def-public.ClassicNavItem", + "text": "ClassicNavItem" + }, + "[]) => void" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.setGetBaseClassicNavItems.$1", + "type": "Function", + "tags": [], + "label": "classicNavItemsFn", + "description": [], + "signature": [ + "() => ", + { + "pluginId": "searchNavigation", + "scope": "public", + "docId": "kibSearchNavigationPluginApi", + "section": "def-public.ClassicNavItem", + "text": "ClassicNavItem" + }, + "[]" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.useClassicNavigation", + "type": "Function", + "tags": [], + "label": "useClassicNavigation", + "description": [], + "signature": [ + "(history: ", + { + "pluginId": "@kbn/core-application-browser", + "scope": "public", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-public.ScopedHistory", + "text": "ScopedHistory" + }, + ") => ", + { + "pluginId": "@kbn/shared-ux-page-solution-nav", + "scope": "common", + "docId": "kibKbnSharedUxPageSolutionNavPluginApi", + "section": "def-common.SolutionNavProps", + "text": "SolutionNavProps" + }, + " | undefined" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "searchNavigation", + "id": "def-public.SearchNavigationPluginStart.useClassicNavigation.$1", + "type": "Object", + "tags": [], + "label": "history", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-application-browser", + "scope": "public", + "docId": "kibKbnCoreApplicationBrowserPluginApi", + "section": "def-public.ScopedHistory", + "text": "ScopedHistory" + }, + "" + ], + "path": "x-pack/plugins/search_solution/search_navigation/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + } + ], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "searchNavigation", + "id": "def-common.PLUGIN_ID", + "type": "string", + "tags": [], + "label": "PLUGIN_ID", + "description": [], + "signature": [ + "\"searchNavigation\"" + ], + "path": "x-pack/plugins/search_solution/search_navigation/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "searchNavigation", + "id": "def-common.PLUGIN_NAME", + "type": "string", + "tags": [], + "label": "PLUGIN_NAME", + "description": [], + "signature": [ + "\"searchNavigation\"" + ], + "path": "x-pack/plugins/search_solution/search_navigation/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/search_navigation.mdx b/api_docs/search_navigation.mdx new file mode 100644 index 000000000000..13ec3c71cb61 --- /dev/null +++ b/api_docs/search_navigation.mdx @@ -0,0 +1,41 @@ +--- +#### +#### 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: kibSearchNavigationPluginApi +slug: /kibana-dev-docs/api/searchNavigation +title: "searchNavigation" +image: https://source.unsplash.com/400x175/?github +description: API docs for the searchNavigation plugin +date: 2024-12-03 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNavigation'] +--- +import searchNavigationObj from './search_navigation.devdocs.json'; + + + +Contact [@elastic/search-kibana](https://github.com/orgs/elastic/teams/search-kibana) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 21 | 0 | 21 | 0 | + +## Client + +### Setup + + +### Start + + +### Interfaces + + +## Common + +### Consts, variables and types + + diff --git a/api_docs/search_notebooks.mdx b/api_docs/search_notebooks.mdx index 49b4a6ced27b..87e79557b6d0 100644 --- a/api_docs/search_notebooks.mdx +++ b/api_docs/search_notebooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchNotebooks title: "searchNotebooks" image: https://source.unsplash.com/400x175/?github description: API docs for the searchNotebooks plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchNotebooks'] --- import searchNotebooksObj from './search_notebooks.devdocs.json'; diff --git a/api_docs/search_playground.mdx b/api_docs/search_playground.mdx index a2f9128eeb98..25725925c071 100644 --- a/api_docs/search_playground.mdx +++ b/api_docs/search_playground.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/searchPlayground title: "searchPlayground" image: https://source.unsplash.com/400x175/?github description: API docs for the searchPlayground plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'searchPlayground'] --- import searchPlaygroundObj from './search_playground.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index beced7ef042f..202af8402040 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.devdocs.json b/api_docs/security_solution.devdocs.json index f62340cda683..8320b9f63393 100644 --- a/api_docs/security_solution.devdocs.json +++ b/api_docs/security_solution.devdocs.json @@ -266,6 +266,108 @@ "trackAdoption": false, "children": [], "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.registerDiscoverSharedFeatures", + "type": "Function", + "tags": [], + "label": "registerDiscoverSharedFeatures", + "description": [], + "signature": [ + "(core: ", + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreSetup", + "text": "CoreSetup" + }, + "<", + "StartPluginsDependencies", + ", ", + { + "pluginId": "securitySolution", + "scope": "public", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + }, + ">, plugins: ", + "SetupPlugins", + ") => Promise" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.registerDiscoverSharedFeatures.$1", + "type": "Object", + "tags": [], + "label": "core", + "description": [], + "signature": [ + { + "pluginId": "@kbn/core-lifecycle-browser", + "scope": "public", + "docId": "kibKbnCoreLifecycleBrowserPluginApi", + "section": "def-public.CoreSetup", + "text": "CoreSetup" + }, + "<", + "StartPluginsDependencies", + ", ", + { + "pluginId": "securitySolution", + "scope": "public", + "docId": "kibSecuritySolutionPluginApi", + "section": "def-public.PluginStart", + "text": "PluginStart" + }, + ">" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.registerDiscoverSharedFeatures.$2", + "type": "Object", + "tags": [], + "label": "plugins", + "description": [], + "signature": [ + "SetupPlugins" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] + }, + { + "parentPluginId": "securitySolution", + "id": "def-public.Plugin.getLazyDiscoverSharedDeps", + "type": "Function", + "tags": [], + "label": "getLazyDiscoverSharedDeps", + "description": [], + "signature": [ + "() => Promise" + ], + "path": "x-pack/plugins/security_solution/public/plugin.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [], + "returnComment": [] } ], "initialIsOpen": false @@ -880,8 +982,8 @@ "pluginId": "timelines", "scope": "common", "docId": "kibTimelinesPluginApi", - "section": "def-common.EqlOptionsSelected", - "text": "EqlOptionsSelected" + "section": "def-common.EqlOptions", + "text": "EqlOptions" } ], "path": "x-pack/plugins/security_solution/public/timelines/store/model.ts", @@ -1829,7 +1931,7 @@ "label": "setComponents", "description": [], "signature": [ - "(components: Partial<{ GetStarted: React.ComponentType<{ indicesExist?: boolean | undefined; }>; DashboardsLandingCallout: React.ComponentType<{}>; }>) => void" + "(components: Partial<{ GetStarted: React.ComponentType<{ indicesExist?: boolean | undefined; }>; DashboardsLandingCallout: React.ComponentType<{}>; EnablementModalCallout: React.ComponentType<{}>; }>) => void" ], "path": "x-pack/plugins/security_solution/public/types.ts", "deprecated": false, @@ -1844,7 +1946,7 @@ "label": "components", "description": [], "signature": [ - "{ GetStarted?: React.ComponentType<{ indicesExist?: boolean | undefined; }> | undefined; DashboardsLandingCallout?: React.ComponentType<{}> | undefined; }" + "{ GetStarted?: React.ComponentType<{ indicesExist?: boolean | undefined; }> | undefined; DashboardsLandingCallout?: React.ComponentType<{}> | undefined; EnablementModalCallout?: React.ComponentType<{}> | undefined; }" ], "path": "x-pack/plugins/security_solution/public/contract_components.ts", "deprecated": false, @@ -3267,7 +3369,7 @@ "\nA list of allowed values that can be used in `xpack.securitySolution.enableExperimental`.\nThis object is then used to validate and parse the value entered." ], "signature": [ - "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: true; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesDisabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly graphVisualizationInFlyoutEnabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreDisabled: false; readonly siemMigrationsEnabled: false; readonly defendInsights: false; }" + "{ readonly excludePoliciesInFilterEnabled: false; readonly kubernetesEnabled: false; readonly donutChartEmbeddablesEnabled: false; readonly previewTelemetryUrlEnabled: false; readonly extendedRuleExecutionLoggingEnabled: false; readonly socTrendsEnabled: false; readonly responseActionUploadEnabled: true; readonly automatedProcessActionsEnabled: true; readonly responseActionsSentinelOneV1Enabled: true; readonly responseActionsSentinelOneV2Enabled: true; readonly responseActionsSentinelOneGetFileEnabled: true; readonly responseActionsSentinelOneKillProcessEnabled: true; readonly responseActionsSentinelOneProcessesEnabled: true; readonly responseActionsCrowdstrikeManualHostIsolationEnabled: true; readonly endpointManagementSpaceAwarenessEnabled: false; readonly securitySolutionNotesDisabled: false; readonly entityAlertPreviewDisabled: false; readonly assistantModelEvaluation: false; readonly newUserDetailsFlyoutManagedUser: false; readonly riskScoringPersistence: true; readonly riskScoringRoutesEnabled: true; readonly esqlRulesDisabled: false; readonly protectionUpdatesEnabled: true; readonly disableTimelineSaveTour: false; readonly riskEnginePrivilegesRouteEnabled: true; readonly sentinelOneDataInAnalyzerEnabled: true; readonly sentinelOneManualHostActionsEnabled: true; readonly crowdstrikeDataInAnalyzerEnabled: true; readonly responseActionsTelemetryEnabled: false; readonly jamfDataInAnalyzerEnabled: true; readonly timelineEsqlTabDisabled: false; readonly analyzerDatePickersAndSourcererDisabled: false; readonly graphVisualizationInFlyoutEnabled: false; readonly prebuiltRulesCustomizationEnabled: false; readonly malwareOnWriteScanOptionAvailable: true; readonly unifiedManifestEnabled: true; readonly valueListItemsModalEnabled: true; readonly filterProcessDescendantsForEventFiltersEnabled: true; readonly dataIngestionHubEnabled: false; readonly entityStoreDisabled: false; readonly siemMigrationsEnabled: false; readonly defendInsights: false; }" ], "path": "x-pack/plugins/security_solution/common/experimental_features.ts", "deprecated": false, diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index fe996ca8192c..1568e2234ad2 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 187 | 0 | 119 | 33 | +| 191 | 0 | 123 | 34 | ## Client diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index d3702f31a2a0..37360609c9b1 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index da76bda855ad..21ecd0fdc8ee 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 9ed3edf484f4..6d3ac863fa09 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index ca029505d397..868a24e2392b 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index c69eda54adde..9ff4dc7b3e9e 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 621edaab4fed..4065f8ed52a9 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2024-11-22 +date: 2024-12-03 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 18739a7c29ae..922d5c624d3a 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/slo.devdocs.json b/api_docs/slo.devdocs.json index 6252ccc31c97..9c7a930086fa 100644 --- a/api_docs/slo.devdocs.json +++ b/api_docs/slo.devdocs.json @@ -384,6 +384,27 @@ "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "slo", + "id": "def-public.SLOPublicPluginsSetup.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.SecurityPluginSetup", + "text": "SecurityPluginSetup" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/slo/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1076,6 +1097,27 @@ "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "slo", + "id": "def-public.SLOPublicPluginsStart.security", + "type": "Object", + "tags": [], + "label": "security", + "description": [], + "signature": [ + { + "pluginId": "@kbn/security-plugin-types-public", + "scope": "public", + "docId": "kibKbnSecurityPluginTypesPublicPluginApi", + "section": "def-public.SecurityPluginStart", + "text": "SecurityPluginStart" + }, + " | undefined" + ], + "path": "x-pack/plugins/observability_solution/slo/public/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -1100,9 +1142,7 @@ "section": "def-common.RecursivePartial", "text": "RecursivePartial" }, - "<", - "CreateSLOForm", - "<{ type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }>> | undefined; }>; }" + "<{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }> | undefined; }>; }" ], "path": "x-pack/plugins/observability_solution/slo/public/types.ts", "deprecated": false, @@ -1137,8 +1177,8 @@ "text": "LocatorPublic" }, "<", - "SloEditLocatorParams", - ">; sloListLocator: ", + "RecursivePartial", + "<{ name: string; description: string; indicator: { type: \"sli.apm.transactionDuration\"; params: { environment: string; service: string; transactionType: string; transactionName: string; threshold: number; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.apm.transactionErrorRate\"; params: { environment: string; service: string; transactionType: string; transactionName: string; index: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.synthetics.availability\"; params: { monitorIds: { value: string; label: string; }[]; index: string; } & { tags?: { value: string; label: string; }[] | undefined; projects?: { value: string; label: string; }[] | undefined; filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.kql.custom\"; params: { index: string; good: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; total: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.custom\"; params: { index: string; good: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; total: { metrics: (({ name: string; aggregation: \"sum\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.metric.timeslice\"; params: { index: string; metric: { metrics: (({ name: string; aggregation: \"min\" | \"max\" | \"sum\" | \"avg\" | \"cardinality\" | \"last_value\" | \"std_deviation\"; field: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"doc_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ name: string; aggregation: \"percentile\"; field: string; percentile: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }))[]; equation: string; threshold: number; comparator: \"GT\" | \"GTE\" | \"LT\" | \"LTE\"; }; timestampField: string; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; } | { type: \"sli.histogram.custom\"; params: { index: string; timestampField: string; good: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); total: ({ field: string; aggregation: \"value_count\"; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }) | ({ field: string; aggregation: \"range\"; from: number; to: number; } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; }); } & { filter?: string | { kqlQuery: string; filters: { meta: { alias?: string | null | undefined; disabled?: boolean | undefined; negate?: boolean | undefined; controlledBy?: string | undefined; group?: string | undefined; index?: string | undefined; isMultiIndex?: boolean | undefined; type?: string | undefined; key?: string | undefined; field?: string | undefined; params?: any; value?: string | undefined; }; query: { [x: string]: any; }; }[]; } | undefined; dataViewId?: string | undefined; }; }; timeWindow: { duration: string; type: \"rolling\"; } | { duration: string; type: \"calendarAligned\"; }; budgetingMethod: \"occurrences\" | \"timeslices\"; objective: { target: number; } & { timesliceTarget?: number | undefined; timesliceWindow?: string | undefined; }; } & { id?: string | undefined; settings?: { syncDelay?: string | undefined; frequency?: string | undefined; preventInitialBackfill?: boolean | undefined; syncField?: string | null | undefined; } | undefined; tags?: string[] | undefined; groupBy?: string | string[] | undefined; revision?: number | undefined; }>>; sloListLocator: ", { "pluginId": "share", "scope": "common", diff --git a/api_docs/slo.mdx b/api_docs/slo.mdx index 0e3f28446c7f..dd266c0213c9 100644 --- a/api_docs/slo.mdx +++ b/api_docs/slo.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/slo title: "slo" image: https://source.unsplash.com/400x175/?github description: API docs for the slo plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'slo'] --- import sloObj from './slo.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/obs-ux-management-team](https://github.com/orgs/elastic/teams/ | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 45 | 0 | 45 | 4 | +| 47 | 0 | 47 | 2 | ## Client diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index 9aaee9101af9..a7b3818f4a82 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2024-11-22 +date: 2024-12-03 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 82fef50bf0bd..635c21d79589 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2024-11-22 +date: 2024-12-03 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 93ec82031426..c787e7566524 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2024-11-22 +date: 2024-12-03 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 cf41a04195d6..abd4c2df3a8d 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/streams.devdocs.json b/api_docs/streams.devdocs.json index 02800505b082..bf552dc47d88 100644 --- a/api_docs/streams.devdocs.json +++ b/api_docs/streams.devdocs.json @@ -6,12 +6,323 @@ "interfaces": [], "enums": [], "misc": [], - "objects": [] + "objects": [], + "setup": { + "parentPluginId": "streams", + "id": "def-public.StreamsPluginSetup", + "type": "Interface", + "tags": [], + "label": "StreamsPluginSetup", + "description": [], + "path": "x-pack/plugins/streams/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "streams", + "id": "def-public.StreamsPluginSetup.status$", + "type": "Object", + "tags": [], + "label": "status$", + "description": [], + "signature": [ + "Observable", + "<{ status: \"unknown\" | \"disabled\" | \"enabled\"; }>" + ], + "path": "x-pack/plugins/streams/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "streams", + "id": "def-public.StreamsPluginStart", + "type": "Interface", + "tags": [], + "label": "StreamsPluginStart", + "description": [], + "path": "x-pack/plugins/streams/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "streams", + "id": "def-public.StreamsPluginStart.streamsRepositoryClient", + "type": "Object", + "tags": [], + "label": "streamsRepositoryClient", + "description": [], + "signature": [ + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.RouteRepositoryClient", + "text": "RouteRepositoryClient" + }, + "<{ \"POST /api/streams/_disable\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /api/streams/_disable\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: true; }, undefined>; \"POST /internal/streams/esql\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /internal/streams/esql\", Zod.ZodObject<{ body: Zod.ZodObject<{ query: Zod.ZodString; operationName: Zod.ZodString; filter: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodTypeAny, \"passthrough\">>>; kuery: Zod.ZodOptional; start: Zod.ZodOptional; end: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectOutputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }, { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectInputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectOutputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }; }, { body: { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectInputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }; }>, ", + "StreamsRouteHandlerResources", + ", ", + "UnparsedEsqlResponse", + ", undefined>; \"GET /api/streams/_status\": { endpoint: \"GET /api/streams/_status\"; handler: ServerRouteHandler<", + "StreamsRouteHandlerResources", + ", undefined, { enabled: boolean; }>; security?: ", + { + "pluginId": "@kbn/core-http-server", + "scope": "server", + "docId": "kibKbnCoreHttpServerPluginApi", + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; }; \"GET /api/streams\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /api/streams\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "StreamsRouteHandlerResources", + ", { definitions: { id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }[]; trees: ", + "StreamTree", + "[]; }, undefined>; \"DELETE /api/streams/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"DELETE /api/streams/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: true; }, undefined>; \"PUT /api/streams/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"PUT /api/streams/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; body: Zod.ZodObject<{ processing: Zod.ZodDefault>; config: Zod.ZodDiscriminatedUnion<\"type\", [Zod.ZodObject<{ type: Zod.ZodLiteral<\"grok\">; field: Zod.ZodString; patterns: Zod.ZodArray; pattern_definitions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; }, { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; }>, Zod.ZodObject<{ type: Zod.ZodLiteral<\"dissect\">; field: Zod.ZodString; pattern: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { type: \"dissect\"; field: string; pattern: string; }, { type: \"dissect\"; field: string; pattern: string; }>]>; }, \"strip\", Zod.ZodTypeAny, { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }, { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }>, \"many\">>; fields: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }>, \"many\">>; children: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { id: string; condition?: ", + "Condition", + "; }, { id: string; condition?: ", + "Condition", + "; }>, \"many\">>; }, \"strip\", Zod.ZodTypeAny, { children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; }, { children?: { id: string; condition?: ", + "Condition", + "; }[] | undefined; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[] | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; }; }, { path: { id: string; }; body: { children?: { id: string; condition?: ", + "Condition", + "; }[] | undefined; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[] | undefined; }; }>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: boolean; }, undefined>; \"GET /api/streams/{id}\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"GET /api/streams/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "StreamsRouteHandlerResources", + ", { id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; } & { inheritedFields: ({ type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; } & { from: string; })[]; }, undefined>; \"POST /api/streams/{id}/_fork\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /api/streams/{id}/_fork\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; body: Zod.ZodObject<{ stream: Zod.ZodObject>; config: Zod.ZodDiscriminatedUnion<\"type\", [Zod.ZodObject<{ type: Zod.ZodLiteral<\"grok\">; field: Zod.ZodString; patterns: Zod.ZodArray; pattern_definitions: Zod.ZodOptional>; }, \"strip\", Zod.ZodTypeAny, { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; }, { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; }>, Zod.ZodObject<{ type: Zod.ZodLiteral<\"dissect\">; field: Zod.ZodString; pattern: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { type: \"dissect\"; field: string; pattern: string; }, { type: \"dissect\"; field: string; pattern: string; }>]>; }, \"strip\", Zod.ZodTypeAny, { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }, { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }>, \"many\">>; fields: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }>, \"many\">>; children: Zod.ZodDefault>; }, \"strip\", Zod.ZodTypeAny, { id: string; condition?: ", + "Condition", + "; }, { id: string; condition?: ", + "Condition", + "; }>, \"many\">>; }, { id: Zod.ZodString; managed: Zod.ZodDefault; unmanaged_elasticsearch_assets: Zod.ZodOptional; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }>, \"many\">>; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }>; condition: Zod.ZodType<", + "Condition", + ", Zod.ZodTypeDef, ", + "Condition", + ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", + "Condition", + "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", + "Condition", + "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", + "Condition", + "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", + "Condition", + "; }; }>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: true; }, undefined>; \"POST /api/streams/_resync\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /api/streams/_resync\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: true; }, undefined>; \"POST /api/streams/_enable\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" + }, + "<\"POST /api/streams/_enable\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: true; }, undefined>; }, ", + "StreamsRepositoryClientOptions", + ">" + ], + "path": "x-pack/plugins/streams/public/types.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "streams", + "id": "def-public.StreamsPluginStart.status$", + "type": "Object", + "tags": [], + "label": "status$", + "description": [], + "signature": [ + "Observable", + "<{ status: \"unknown\" | \"disabled\" | \"enabled\"; }>" + ], + "path": "x-pack/plugins/streams/public/types.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "lifecycle": "start", + "initialIsOpen": true + } }, "server": { "classes": [], "functions": [], - "interfaces": [], + "interfaces": [ + { + "parentPluginId": "streams", + "id": "def-server.ListStreamResponse", + "type": "Interface", + "tags": [], + "label": "ListStreamResponse", + "description": [], + "path": "x-pack/plugins/streams/server/lib/streams/stream_crud.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "streams", + "id": "def-server.ListStreamResponse.total", + "type": "number", + "tags": [], + "label": "total", + "description": [], + "path": "x-pack/plugins/streams/server/lib/streams/stream_crud.ts", + "deprecated": false, + "trackAdoption": false + }, + { + "parentPluginId": "streams", + "id": "def-server.ListStreamResponse.definitions", + "type": "Array", + "tags": [], + "label": "definitions", + "description": [], + "signature": [ + "{ id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }[]" + ], + "path": "x-pack/plugins/streams/server/lib/streams/stream_crud.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], "enums": [], "misc": [ { @@ -37,7 +348,7 @@ "label": "StreamsRouteRepository", "description": [], "signature": [ - "{ \"GET /api/streams 2023-10-31\": ", + "{ \"POST /api/streams/_disable\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -45,25 +356,9 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/streams 2023-10-31\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "<\"POST /api/streams/_disable\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", "StreamsRouteHandlerResources", - ", ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" - }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"DELETE /api/streams/{id} 2023-10-31\": ", + ", { acknowledged: true; }, undefined>; \"POST /internal/streams/esql\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -71,25 +366,47 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"DELETE /api/streams/{id} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "<\"POST /internal/streams/esql\", Zod.ZodObject<{ body: Zod.ZodObject<{ query: Zod.ZodString; operationName: Zod.ZodString; filter: Zod.ZodOptional, Zod.objectInputType<{}, Zod.ZodTypeAny, \"passthrough\">>>; kuery: Zod.ZodOptional; start: Zod.ZodOptional; end: Zod.ZodOptional; }, \"strip\", Zod.ZodTypeAny, { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectOutputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }, { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectInputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }>; }, \"strip\", Zod.ZodTypeAny, { body: { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectOutputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }; }, { body: { query: string; operationName: string; start?: number | undefined; end?: number | undefined; filter?: Zod.objectInputType<{}, Zod.ZodTypeAny, \"passthrough\"> | undefined; kuery?: string | undefined; }; }>, ", "StreamsRouteHandlerResources", ", ", + "UnparsedEsqlResponse", + ", undefined>; \"GET /api/streams/_status\": { endpoint: \"GET /api/streams/_status\"; handler: ServerRouteHandler<", + "StreamsRouteHandlerResources", + ", undefined, { enabled: boolean; }>; security?: ", { "pluginId": "@kbn/core-http-server", "scope": "server", "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" + "section": "def-server.RouteSecurity", + "text": "RouteSecurity" + }, + " | undefined; }; \"GET /api/streams\": ", + { + "pluginId": "@kbn/server-route-repository-utils", + "scope": "common", + "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", + "section": "def-common.ServerRoute", + "text": "ServerRoute" }, - ", ", + "<\"GET /api/streams\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "StreamsRouteHandlerResources", + ", { definitions: { id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }[]; trees: ", + "StreamTree", + "[]; }, undefined>; \"DELETE /api/streams/{id}\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" + "section": "def-common.ServerRoute", + "text": "ServerRoute" }, - ">; \"PUT /api/streams/{id} 2023-10-31\": ", + "<\"DELETE /api/streams/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "StreamsRouteHandlerResources", + ", { acknowledged: true; }, undefined>; \"PUT /api/streams/{id}\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -97,7 +414,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"PUT /api/streams/{id} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; body: Zod.ZodObject<{ processing: Zod.ZodDefault; body: Zod.ZodObject<{ processing: Zod.ZodDefault | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }>, \"many\">>; fields: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }>, \"many\">>; children: Zod.ZodDefault, \"many\">>; fields: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }>, \"many\">>; children: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { id: string; condition?: ", + ">>; }, \"strip\", Zod.ZodTypeAny, { id: string; condition?: ", "Condition", "; }, { id: string; condition?: ", "Condition", @@ -131,23 +448,7 @@ "Condition", "; }[] | undefined; }; }>, ", "StreamsRouteHandlerResources", - ", ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" - }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"GET /api/streams/{id} 2023-10-31\": ", + ", { acknowledged: boolean; }, undefined>; \"GET /api/streams/{id}\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -155,25 +456,13 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"GET /api/streams/{id} 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", + "<\"GET /api/streams/{id}\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; }, { path: { id: string; }; }>, ", "StreamsRouteHandlerResources", - ", ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" - }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"POST /api/streams/{id}/_fork 2023-10-31\": ", + ", { id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; } & { inheritedFields: ({ type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; } & { from: string; })[]; }, undefined>; \"POST /api/streams/{id}/_fork\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -181,7 +470,7 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/streams/{id}/_fork 2023-10-31\", Zod.ZodObject<{ path: Zod.ZodObject<{ id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; }, { id: string; }>; body: Zod.ZodObject<{ stream: Zod.ZodObject; body: Zod.ZodObject<{ stream: Zod.ZodObject | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }>, \"many\">>; fields: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }>, \"many\">>; children: Zod.ZodDefault, \"many\">>; fields: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }, { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }>, \"many\">>; children: Zod.ZodDefault; }, \"strip\", Zod.ZodTypeAny, { id: string; condition?: ", + ">>; }, \"strip\", Zod.ZodTypeAny, { id: string; condition?: ", "Condition", "; }, { id: string; condition?: ", "Condition", - "; }>, \"many\">>; }, { id: Zod.ZodString; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }>, \"many\">>; }, { id: Zod.ZodString; managed: Zod.ZodDefault; unmanaged_elasticsearch_assets: Zod.ZodOptional; id: Zod.ZodString; }, \"strip\", Zod.ZodTypeAny, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }, { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }>, \"many\">>; }>, \"children\">, \"strip\", Zod.ZodTypeAny, { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }, { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }>; condition: Zod.ZodType<", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }>; condition: Zod.ZodType<", "Condition", ", Zod.ZodTypeDef, ", "Condition", - ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + ">; }, \"strip\", Zod.ZodTypeAny, { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }, { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }; condition?: ", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }>; }, \"strip\", Zod.ZodTypeAny, { path: { id: string; }; body: { stream: { id: string; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[]; }; condition?: ", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", - "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "; }; }, { path: { id: string; }; body: { stream: { id: string; fields?: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[] | undefined; managed?: boolean | undefined; processing?: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", "Condition", - "; }[] | undefined; }; condition?: ", + "; }[] | undefined; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; condition?: ", "Condition", "; }; }>, ", "StreamsRouteHandlerResources", - ", ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" - }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"POST /api/streams/_resync 2023-10-31\": ", + ", { acknowledged: true; }, undefined>; \"POST /api/streams/_resync\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -247,25 +520,9 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/streams/_resync 2023-10-31\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "<\"POST /api/streams/_resync\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", "StreamsRouteHandlerResources", - ", ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" - }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; \"POST /api/streams/_enable 2023-10-31\": ", + ", { acknowledged: true; }, undefined>; \"POST /api/streams/_enable\": ", { "pluginId": "@kbn/server-route-repository-utils", "scope": "common", @@ -273,25 +530,9 @@ "section": "def-common.ServerRoute", "text": "ServerRoute" }, - "<\"POST /api/streams/_enable 2023-10-31\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", + "<\"POST /api/streams/_enable\", Zod.ZodObject<{}, \"strip\", Zod.ZodTypeAny, {}, {}>, ", "StreamsRouteHandlerResources", - ", ", - { - "pluginId": "@kbn/core-http-server", - "scope": "server", - "docId": "kibKbnCoreHttpServerPluginApi", - "section": "def-server.IKibanaResponse", - "text": "IKibanaResponse" - }, - ", ", - { - "pluginId": "@kbn/server-route-repository-utils", - "scope": "common", - "docId": "kibKbnServerRouteRepositoryUtilsPluginApi", - "section": "def-common.DefaultRouteCreateOptions", - "text": "DefaultRouteCreateOptions" - }, - ">; }" + ", { acknowledged: true; }, undefined>; }" ], "path": "x-pack/plugins/streams/server/routes/index.ts", "deprecated": false, @@ -299,120 +540,7 @@ "initialIsOpen": false } ], - "objects": [ - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository", - "type": "Object", - "tags": [], - "label": "StreamsRouteRepository", - "description": [], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "streams", - "id": "def-server.StreamsRouteRepository.Unnamed", - "type": "Any", - "tags": [], - "label": "Unnamed", - "description": [], - "signature": [ - "any" - ], - "path": "x-pack/plugins/streams/server/routes/index.ts", - "deprecated": false, - "trackAdoption": false - } - ], - "initialIsOpen": false - } - ], + "objects": [], "setup": { "parentPluginId": "streams", "id": "def-server.StreamsPluginSetup", @@ -447,7 +575,27 @@ "functions": [], "interfaces": [], "enums": [], - "misc": [], + "misc": [ + { + "parentPluginId": "streams", + "id": "def-common.StreamDefinition", + "type": "Type", + "tags": [], + "label": "StreamDefinition", + "description": [], + "signature": [ + "{ id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }" + ], + "path": "x-pack/plugins/streams/common/types.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], "objects": [] } } \ No newline at end of file diff --git a/api_docs/streams.mdx b/api_docs/streams.mdx index 61dc95c44fdd..9c4865f7f286 100644 --- a/api_docs/streams.mdx +++ b/api_docs/streams.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/streams title: "streams" image: https://source.unsplash.com/400x175/?github description: API docs for the streams plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'streams'] --- import streamsObj from './streams.devdocs.json'; @@ -21,7 +21,15 @@ Contact @simianhacker @flash1293 @dgieselaar for questions regarding this plugin | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 12 | 7 | 12 | 2 | +| 13 | 0 | 13 | 4 | + +## Client + +### Setup + + +### Start + ## Server @@ -31,9 +39,14 @@ Contact @simianhacker @flash1293 @dgieselaar for questions regarding this plugin ### Start -### Objects - +### Interfaces + ### Consts, variables and types +## Common + +### Consts, variables and types + + diff --git a/api_docs/streams_app.devdocs.json b/api_docs/streams_app.devdocs.json new file mode 100644 index 000000000000..12a4d9b1b7d5 --- /dev/null +++ b/api_docs/streams_app.devdocs.json @@ -0,0 +1,148 @@ +{ + "id": "streamsApp", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "streamsApp", + "id": "def-public.StreamsAppPublicSetup", + "type": "Interface", + "tags": [], + "label": "StreamsAppPublicSetup", + "description": [], + "path": "x-pack/plugins/streams_app/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "streamsApp", + "id": "def-public.StreamsAppPublicStart", + "type": "Interface", + "tags": [], + "label": "StreamsAppPublicStart", + "description": [], + "path": "x-pack/plugins/streams_app/public/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [], + "setup": { + "parentPluginId": "streamsApp", + "id": "def-server.StreamsAppServerSetup", + "type": "Interface", + "tags": [], + "label": "StreamsAppServerSetup", + "description": [], + "path": "x-pack/plugins/streams_app/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "setup", + "initialIsOpen": true + }, + "start": { + "parentPluginId": "streamsApp", + "id": "def-server.StreamsAppServerStart", + "type": "Interface", + "tags": [], + "label": "StreamsAppServerStart", + "description": [], + "path": "x-pack/plugins/streams_app/server/types.ts", + "deprecated": false, + "trackAdoption": false, + "children": [], + "lifecycle": "start", + "initialIsOpen": true + } + }, + "common": { + "classes": [], + "functions": [], + "interfaces": [ + { + "parentPluginId": "streamsApp", + "id": "def-common.EntityTypeDefinition", + "type": "Interface", + "tags": [], + "label": "EntityTypeDefinition", + "description": [], + "path": "x-pack/plugins/streams_app/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "streamsApp", + "id": "def-common.EntityTypeDefinition.displayName", + "type": "string", + "tags": [], + "label": "displayName", + "description": [], + "path": "x-pack/plugins/streams_app/common/index.ts", + "deprecated": false, + "trackAdoption": false + } + ], + "initialIsOpen": false + } + ], + "enums": [], + "misc": [ + { + "parentPluginId": "streamsApp", + "id": "def-common.Entity", + "type": "Type", + "tags": [], + "label": "Entity", + "description": [], + "signature": [ + "EntityBase & { type: \"stream\"; properties: { id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; }" + ], + "path": "x-pack/plugins/streams_app/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + }, + { + "parentPluginId": "streamsApp", + "id": "def-common.StreamEntity", + "type": "Type", + "tags": [], + "label": "StreamEntity", + "description": [], + "signature": [ + "EntityBase & { type: \"stream\"; properties: { id: string; children: { id: string; condition?: ", + "Condition", + "; }[]; fields: { type: \"boolean\" | \"ip\" | \"keyword\" | \"date\" | \"long\" | \"double\" | \"match_only_text\"; name: string; }[]; managed: boolean; processing: { config: { type: \"grok\"; field: string; patterns: string[]; pattern_definitions?: Record | undefined; } | { type: \"dissect\"; field: string; pattern: string; }; condition?: ", + "Condition", + "; }[]; unmanaged_elasticsearch_assets?: { id: string; type: \"ingest_pipeline\" | \"data_stream\" | \"index_template\" | \"component_template\"; }[] | undefined; }; }" + ], + "path": "x-pack/plugins/streams_app/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/streams_app.mdx b/api_docs/streams_app.mdx new file mode 100644 index 000000000000..629a0ca06511 --- /dev/null +++ b/api_docs/streams_app.mdx @@ -0,0 +1,49 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibStreamsAppPluginApi +slug: /kibana-dev-docs/api/streamsApp +title: "streamsApp" +image: https://source.unsplash.com/400x175/?github +description: API docs for the streamsApp plugin +date: 2024-12-03 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'streamsApp'] +--- +import streamsAppObj from './streams_app.devdocs.json'; + + + +Contact @simianhacker @flash1293 @dgieselaar for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 8 | 0 | 8 | 0 | + +## Client + +### Setup + + +### Start + + +## Server + +### Setup + + +### Start + + +## Common + +### Interfaces + + +### Consts, variables and types + + diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index eb637b28265b..3a338e11eac2 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2024-11-22 +date: 2024-12-03 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 f9df55ffe063..ed12ad96ade8 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2024-11-22 +date: 2024-12-03 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 312c866bf523..ade6bf4aa32f 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index 92f25b5d7305..cb5728a3d59f 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 60e8abc57119..3a2034cece75 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.devdocs.json b/api_docs/timelines.devdocs.json index 0904b1d8c25a..c404e4317d82 100644 --- a/api_docs/timelines.devdocs.json +++ b/api_docs/timelines.devdocs.json @@ -1465,7 +1465,181 @@ }, "common": { "classes": [], - "functions": [], + "functions": [ + { + "parentPluginId": "timelines", + "id": "def-common.getDataFromFieldsHits", + "type": "Function", + "tags": [], + "label": "getDataFromFieldsHits", + "description": [], + "signature": [ + "(fields: ", + "Fields", + ", prependField?: string | undefined, prependFieldCategory?: string | undefined) => ", + { + "pluginId": "timelines", + "scope": "common", + "docId": "kibTimelinesPluginApi", + "section": "def-common.TimelineEventsDetailsItem", + "text": "TimelineEventsDetailsItem" + }, + "[]" + ], + "path": "x-pack/plugins/timelines/common/utils/field_formatters.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "timelines", + "id": "def-common.getDataFromFieldsHits.$1", + "type": "Object", + "tags": [], + "label": "fields", + "description": [], + "signature": [ + "Fields", + "" + ], + "path": "x-pack/plugins/timelines/common/utils/field_formatters.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "timelines", + "id": "def-common.getDataFromFieldsHits.$2", + "type": "string", + "tags": [], + "label": "prependField", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/timelines/common/utils/field_formatters.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + }, + { + "parentPluginId": "timelines", + "id": "def-common.getDataFromFieldsHits.$3", + "type": "string", + "tags": [], + "label": "prependFieldCategory", + "description": [], + "signature": [ + "string | undefined" + ], + "path": "x-pack/plugins/timelines/common/utils/field_formatters.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "timelines", + "id": "def-common.isGeoField", + "type": "Function", + "tags": [], + "label": "isGeoField", + "description": [], + "signature": [ + "(field: string) => boolean" + ], + "path": "x-pack/plugins/timelines/common/utils/field_formatters.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "timelines", + "id": "def-common.isGeoField.$1", + "type": "string", + "tags": [], + "label": "field", + "description": [], + "signature": [ + "string" + ], + "path": "x-pack/plugins/timelines/common/utils/field_formatters.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "timelines", + "id": "def-common.toArray", + "type": "Function", + "tags": [], + "label": "toArray", + "description": [], + "signature": [ + "(value: T | T[] | null | undefined) => T[]" + ], + "path": "x-pack/plugins/timelines/common/utils/to_array.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "timelines", + "id": "def-common.toArray.$1", + "type": "CompoundType", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "T | T[] | null | undefined" + ], + "path": "x-pack/plugins/timelines/common/utils/to_array.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "timelines", + "id": "def-common.toObjectArrayOfStrings", + "type": "Function", + "tags": [], + "label": "toObjectArrayOfStrings", + "description": [], + "signature": [ + "(value: T | T[] | null) => { str: string; isObjectArray?: boolean | undefined; }[]" + ], + "path": "x-pack/plugins/timelines/common/utils/to_array.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "timelines", + "id": "def-common.toObjectArrayOfStrings.$1", + "type": "CompoundType", + "tags": [], + "label": "value", + "description": [], + "signature": [ + "T | T[] | null" + ], + "path": "x-pack/plugins/timelines/common/utils/to_array.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": false + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], "interfaces": [ { "parentPluginId": "timelines", @@ -1843,10 +2017,10 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsData", + "id": "def-common.EqlFieldsComboBoxOptions", "type": "Interface", "tags": [], - "label": "EqlOptionsData", + "label": "EqlFieldsComboBoxOptions", "description": [], "path": "x-pack/plugins/timelines/common/search_strategy/timeline/events/eql/index.ts", "deprecated": false, @@ -1854,7 +2028,7 @@ "children": [ { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsData.keywordFields", + "id": "def-common.EqlFieldsComboBoxOptions.keywordFields", "type": "Array", "tags": [], "label": "keywordFields", @@ -1869,7 +2043,7 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsData.dateFields", + "id": "def-common.EqlFieldsComboBoxOptions.dateFields", "type": "Array", "tags": [], "label": "dateFields", @@ -1884,7 +2058,7 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsData.nonDateFields", + "id": "def-common.EqlFieldsComboBoxOptions.nonDateFields", "type": "Array", "tags": [], "label": "nonDateFields", @@ -1902,10 +2076,10 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsSelected", + "id": "def-common.EqlOptions", "type": "Interface", "tags": [], - "label": "EqlOptionsSelected", + "label": "EqlOptions", "description": [], "path": "x-pack/plugins/timelines/common/search_strategy/timeline/events/eql/index.ts", "deprecated": false, @@ -1913,7 +2087,7 @@ "children": [ { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsSelected.eventCategoryField", + "id": "def-common.EqlOptions.eventCategoryField", "type": "string", "tags": [], "label": "eventCategoryField", @@ -1927,7 +2101,7 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsSelected.tiebreakerField", + "id": "def-common.EqlOptions.tiebreakerField", "type": "string", "tags": [], "label": "tiebreakerField", @@ -1941,7 +2115,7 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsSelected.timestampField", + "id": "def-common.EqlOptions.timestampField", "type": "string", "tags": [], "label": "timestampField", @@ -1955,7 +2129,7 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsSelected.query", + "id": "def-common.EqlOptions.query", "type": "string", "tags": [], "label": "query", @@ -1969,7 +2143,7 @@ }, { "parentPluginId": "timelines", - "id": "def-common.EqlOptionsSelected.size", + "id": "def-common.EqlOptions.size", "type": "number", "tags": [], "label": "size", @@ -4143,8 +4317,8 @@ "pluginId": "timelines", "scope": "common", "docId": "kibTimelinesPluginApi", - "section": "def-common.EqlOptionsSelected", - "text": "EqlOptionsSelected" + "section": "def-common.EqlOptions", + "text": "EqlOptions" } ], "path": "x-pack/plugins/timelines/common/search_strategy/timeline/events/eql/index.ts", diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index 6ae93884c4c2..8b41d13110bf 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-threat-hunting-investigations](https://github.com/org | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 226 | 1 | 182 | 17 | +| 236 | 1 | 192 | 18 | ## Client @@ -50,6 +50,9 @@ Contact [@elastic/security-threat-hunting-investigations](https://github.com/org ### Objects +### Functions + + ### Interfaces diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index d374a68bd97e..fe7f7d34d99c 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 1b7bc8b02715..9585065993bd 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index 7527fb3a6988..923384e4c260 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2024-11-22 +date: 2024-12-03 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 0d133d56b7a3..76c339e7a7e3 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index 17e877e7461d..3327549edae0 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.devdocs.json b/api_docs/unified_histogram.devdocs.json index 0e6073ee1cd5..0e201c9411bb 100644 --- a/api_docs/unified_histogram.devdocs.json +++ b/api_docs/unified_histogram.devdocs.json @@ -549,7 +549,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined; isChartLoading?: boolean | undefined; onVisContextChanged?: ((nextVisContext: ", + " | undefined; isChartLoading?: boolean | undefined; breakdownField?: string | undefined; onBreakdownFieldChange?: ((breakdownField: string | undefined) => void) | undefined; onVisContextChanged?: ((nextVisContext: ", { "pluginId": "unifiedHistogram", "scope": "public", @@ -780,24 +780,22 @@ }, { "parentPluginId": "unifiedHistogram", - "id": "def-public.UnifiedHistogramChartLoadEvent.embeddableOutput$", + "id": "def-public.UnifiedHistogramChartLoadEvent.dataLoading$", "type": "Object", "tags": [], - "label": "embeddableOutput$", + "label": "dataLoading$", "description": [ - "\nObservable of the lens embeddable output" + "\nObservable for the data change subscription" ], "signature": [ - "Observable", - "<", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableOutput", - "text": "LensEmbeddableOutput" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - "> | undefined" + " | undefined" ], "path": "src/plugins/unified_histogram/public/types.ts", "deprecated": false, @@ -1073,22 +1071,6 @@ "deprecated": false, "trackAdoption": false, "children": [ - { - "parentPluginId": "unifiedHistogram", - "id": "def-public.UnifiedHistogramState.breakdownField", - "type": "string", - "tags": [], - "label": "breakdownField", - "description": [ - "\nThe current field used for the breakdown" - ], - "signature": [ - "string | undefined" - ], - "path": "src/plugins/unified_histogram/public/container/services/state_service.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "unifiedHistogram", "id": "def-public.UnifiedHistogramState.currentSuggestionContext", @@ -1168,24 +1150,22 @@ }, { "parentPluginId": "unifiedHistogram", - "id": "def-public.UnifiedHistogramState.lensEmbeddableOutput$", + "id": "def-public.UnifiedHistogramState.dataLoading$", "type": "Object", "tags": [], - "label": "lensEmbeddableOutput$", + "label": "dataLoading$", "description": [ "\nLens embeddable output observable" ], "signature": [ - "Observable", - "<", { - "pluginId": "lens", + "pluginId": "@kbn/presentation-publishing", "scope": "public", - "docId": "kibLensPluginApi", - "section": "def-public.LensEmbeddableOutput", - "text": "LensEmbeddableOutput" + "docId": "kibKbnPresentationPublishingPluginApi", + "section": "def-public.PublishingSubject", + "text": "PublishingSubject" }, - "> | undefined" + " | undefined" ], "path": "src/plugins/unified_histogram/public/container/services/state_service.ts", "deprecated": false, @@ -1360,7 +1340,65 @@ "label": "attributes", "description": [], "signature": [ - "LensAttributes<\"lnsXY\", ", + "{ title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsXY\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -1368,9 +1406,125 @@ "section": "def-public.XYState", "text": "XYState" }, - "> | LensAttributes<\"lnsPie\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsPie\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", "PieVisualizationState", - "> | LensAttributes<\"lnsHeatmap\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsHeatmap\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -1378,7 +1532,65 @@ "section": "def-public.HeatmapVisualizationState", "text": "HeatmapVisualizationState" }, - "> | LensAttributes<\"lnsGauge\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsGauge\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -1386,7 +1598,65 @@ "section": "def-public.GaugeVisualizationState", "text": "GaugeVisualizationState" }, - "> | LensAttributes<\"lnsDatatable\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsDatatable\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -1394,7 +1664,65 @@ "section": "def-public.DatatableVisualizationState", "text": "DatatableVisualizationState" }, - "> | LensAttributes<\"lnsLegacyMetric\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsLegacyMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "common", @@ -1402,7 +1730,65 @@ "section": "def-common.LegacyMetricState", "text": "LegacyMetricState" }, - "> | LensAttributes<\"lnsMetric\", ", + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: \"lnsMetric\"; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: ", { "pluginId": "lens", "scope": "public", @@ -1410,7 +1796,65 @@ "section": "def-public.MetricVisualizationState", "text": "MetricVisualizationState" }, - "> | LensAttributes" + "; }; } | { title: string; description?: string | undefined; references: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[]; visualizationType: string; state: { query: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Query", + "text": "Query" + }, + " | ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.AggregateQuery", + "text": "AggregateQuery" + }, + "; filters: ", + { + "pluginId": "@kbn/es-query", + "scope": "common", + "docId": "kibKbnEsQueryPluginApi", + "section": "def-common.Filter", + "text": "Filter" + }, + "[]; globalPalette?: { activePaletteId: string; state?: unknown; } | undefined; adHocDataViews?: Record | undefined; internalReferences?: ", + { + "pluginId": "@kbn/core-saved-objects-common", + "scope": "common", + "docId": "kibKbnCoreSavedObjectsCommonPluginApi", + "section": "def-common.SavedObjectReference", + "text": "SavedObjectReference" + }, + "[] | undefined; datasourceStates: { formBased?: ", + { + "pluginId": "lens", + "scope": "public", + "docId": "kibLensPluginApi", + "section": "def-public.FormBasedPersistedState", + "text": "FormBasedPersistedState" + }, + " | undefined; textBased?: ", + "TextBasedPersistedState", + " | undefined; }; visualization: unknown; }; }" ], "path": "src/plugins/unified_histogram/public/types.ts", "deprecated": false, @@ -1530,7 +1974,7 @@ "signature": [ "{ refetch: () => void; } & Pick<", "UnifiedHistogramStateService", - ", \"state$\" | \"setChartHidden\" | \"setTopPanelHeight\" | \"setBreakdownField\" | \"setTimeInterval\" | \"setTotalHits\">" + ", \"state$\" | \"setChartHidden\" | \"setTopPanelHeight\" | \"setTimeInterval\" | \"setTotalHits\">" ], "path": "src/plugins/unified_histogram/public/container/container.tsx", "deprecated": false, @@ -1571,7 +2015,7 @@ "section": "def-common.RequestAdapter", "text": "RequestAdapter" }, - " | undefined; isChartLoading?: boolean | undefined; onVisContextChanged?: ((nextVisContext: ", + " | undefined; isChartLoading?: boolean | undefined; breakdownField?: string | undefined; onBreakdownFieldChange?: ((breakdownField: string | undefined) => void) | undefined; onVisContextChanged?: ((nextVisContext: ", { "pluginId": "unifiedHistogram", "scope": "public", diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index be8dd17292a2..cb762669e1fe 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 70 | 0 | 35 | 6 | +| 69 | 0 | 35 | 6 | ## Client diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 8cfad5be3f00..4a7b6b6a9325 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 2d63214a6f4b..e39017387379 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index 0c45c37bb221..67b588c31ea6 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index f83cd5d6ae9a..9918c9f12084 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2024-11-22 +date: 2024-12-03 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 7a63eeb0e4a7..f9b10099d1e7 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2024-11-22 +date: 2024-12-03 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 df78cd34de7a..40dfc1020e70 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2024-11-22 +date: 2024-12-03 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 26941d1ddf05..1c52c77a9c37 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2024-11-22 +date: 2024-12-03 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 25a5834dede7..e6d466054207 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2024-11-22 +date: 2024-12-03 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 5adb18dc78c4..d582a5d36f3b 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2024-11-22 +date: 2024-12-03 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 d93490fb31ac..58bf93a18779 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2024-11-22 +date: 2024-12-03 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 1041603461f1..868a64d7ea52 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2024-11-22 +date: 2024-12-03 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 9d8810c19098..46f5b63e4c4c 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2024-11-22 +date: 2024-12-03 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 11d22d400930..0b7d0f0020d7 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2024-11-22 +date: 2024-12-03 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 d093b71336e6..edbc75b2fa1a 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2024-11-22 +date: 2024-12-03 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 63f32e78862a..f0e417c66112 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2024-11-22 +date: 2024-12-03 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 7304a38526b4..61634c53a811 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.devdocs.json b/api_docs/visualizations.devdocs.json index d2d15673ef45..234558c6457a 100644 --- a/api_docs/visualizations.devdocs.json +++ b/api_docs/visualizations.devdocs.json @@ -7050,7 +7050,7 @@ "section": "def-common.AggregateQuery", "text": "AggregateQuery" }, - " | undefined; getFilters: () => ", + " | undefined; canLinkToLibrary: (() => Promise) | undefined; canUnlinkFromLibrary: (() => Promise) | undefined; onEdit: () => Promise; isEditingEnabled: () => boolean; getEditHref: () => Promise; getTypeDisplayName: () => string; getFilters: () => ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -7058,7 +7058,7 @@ "section": "def-common.Filter", "text": "Filter" }, - "[]; canLinkToLibrary: (() => Promise) | undefined; canUnlinkFromLibrary: (() => Promise) | undefined; setTimeRange: (timeRange: ", + "[]; setTimeRange: (timeRange: ", { "pluginId": "@kbn/es-query", "scope": "common", @@ -7074,7 +7074,7 @@ "section": "def-public.VisualizeInput", "text": "VisualizeInput" }, - "; getDescription: () => string; onEdit: () => Promise; phase$: ", + "; getDescription: () => string; phase$: ", { "pluginId": "@kbn/presentation-publishing", "scope": "public", @@ -7090,7 +7090,15 @@ "section": "def-public.PhaseEvent", "text": "PhaseEvent" }, - " | undefined>; setPanelTitle: (newTitle: string | undefined) => void; isEditingEnabled: () => boolean; setHidePanelTitle: (hide: boolean | undefined) => void; getTypeDisplayName: () => string; setPanelDescription: (newTitle: string | undefined) => void; render: (domNode: HTMLElement) => Promise; getEditHref: () => Promise; reload: () => Promise; updateInput: (changes: Partial<", + " | undefined>; setPanelTitle: (newTitle: string | undefined) => void; setHidePanelTitle: (hide: boolean | undefined) => void; setPanelDescription: (newTitle: string | undefined) => void; render: (domNode: HTMLElement) => Promise; supportedTriggers: () => string[]; getInspectorAdapters: () => ", + { + "pluginId": "inspector", + "scope": "common", + "docId": "kibInspectorPluginApi", + "section": "def-common.Adapters", + "text": "Adapters" + }, + " | undefined; reload: () => Promise; updateInput: (changes: Partial<", { "pluginId": "visualizations", "scope": "public", @@ -7124,15 +7132,7 @@ "section": "def-common.VisParams", "text": "VisParams" }, - ">; getInspectorAdapters: () => ", - { - "pluginId": "inspector", - "scope": "common", - "docId": "kibInspectorPluginApi", - "section": "def-common.Adapters", - "text": "Adapters" - }, - " | undefined; openInspector: () => ", + ">; openInspector: () => ", { "pluginId": "@kbn/core-mount-utils-browser", "scope": "public", @@ -7148,7 +7148,7 @@ "section": "def-public.ExpressionRenderError", "text": "ExpressionRenderError" }, - ") => void; supportedTriggers: () => string[]; getExpressionVariables$: () => ", + ") => void; getExpressionVariables$: () => ", "Observable", " | undefined>; getExpressionVariables: () => Record | undefined; inputIsRefType: (input: ", { diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index 74138f0c8889..ac0e737f773a 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2024-11-22 +date: 2024-12-03 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/config/serverless.es.yml b/config/serverless.es.yml index eafa7f311339..3132125bfecd 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -59,6 +59,13 @@ xpack.features.overrides: stackAlerts: name: "Alerts" category: "enterpriseSearch" + ### Observability AI Assistant feature is moved to Search and renamed + observabilityAIAssistant: + name: "AI Assistant" + category: "enterpriseSearch" + ### AI Assistant enables the Inventory feature, moving to Search + inventory: + category: "enterpriseSearch" ## Cloud settings xpack.cloud.serverless.project_type: search @@ -113,7 +120,7 @@ data_visualizer.resultLinks.fileBeat.enabled: false xpack.searchPlayground.ui.enabled: true # Search InferenceEndpoints -xpack.searchInferenceEndpoints.ui.enabled: false +xpack.searchInferenceEndpoints.ui.enabled: true # Search Notebooks xpack.search.notebooks.catalog.url: https://elastic-enterprise-search.s3.us-east-2.amazonaws.com/serverless/catalog.json @@ -127,7 +134,6 @@ xpack.observabilityAIAssistant.enabled: true xpack.searchAssistant.enabled: true xpack.searchAssistant.ui.enabled: true xpack.observabilityAIAssistant.scope: "search" -xpack.observabilityAIAssistant.enableKnowledgeBase: false aiAssistantManagementSelection.preferredAIAssistantType: "observability" xpack.observabilityAiAssistantManagement.logSourcesEnabled: false xpack.observabilityAiAssistantManagement.spacesEnabled: false diff --git a/config/serverless.yml b/config/serverless.yml index 0967df966f61..d62f26a4642e 100644 --- a/config/serverless.yml +++ b/config/serverless.yml @@ -229,3 +229,8 @@ monitoring.ui.enabled: false xpack.securitySolution.enableUiSettingsValidations: true data.enableUiSettingsValidations: true discover.enableUiSettingsValidations: true + +## Data Usage in stack management +xpack.dataUsage.enabled: true +# This feature is disabled in Serverless until fully tested within a Serverless environment +xpack.dataUsage.enableExperimental: ['dataUsageDisabled'] diff --git a/dev_docs/tutorials/generating_oas_for_http_apis.mdx b/dev_docs/tutorials/generating_oas_for_http_apis.mdx index 19852206f800..f0f497c4286f 100644 --- a/dev_docs/tutorials/generating_oas_for_http_apis.mdx +++ b/dev_docs/tutorials/generating_oas_for_http_apis.mdx @@ -57,7 +57,9 @@ Other useful query parameters for filtering are: import { schema, TypeOf } from '@kbn/config-schema'; export const fooResource = schema.object({ - name: schema.string() + name: schema.string({ + meta: { description: 'A unique identifier for...' }, + }), // ...and any other fields you may need }); @@ -114,8 +116,14 @@ function registerFooRoute(router: IRouter, docLinks: DoclinksStart) { access: 'public', summary: 'Create a foo resource' description: `A foo resource enables baz. See the following [documentation](${docLinks.links.fooResource}).`, - tags: ['oas-tag:my tag'], // Each operation must have a tag that's used to group similar endpoints in the docs - deprecated: true // An indicator that the operation is deprecated + deprecated: true, // An indicator that the operation is deprecated + options: { + tags: ['oas-tag:my tag'], // Each operation must have a tag that's used to group similar endpoints in the docs + availability: { + since: '1.0.0', + stability: 'experimental', + }, + }, }) .addVersion({ version: '2023-10-31', diff --git a/dev_docs/tutorials/saved_objects.mdx b/dev_docs/tutorials/saved_objects.mdx index 233795374f2e..71b99e2ae5e7 100644 --- a/dev_docs/tutorials/saved_objects.mdx +++ b/dev_docs/tutorials/saved_objects.mdx @@ -126,6 +126,56 @@ Do not use field mappings like you would use data types for the columns of a SQL SQL index. Only specify field mappings for the fields you wish to search on or query. By specifying `dynamic: false` in any level of your mappings, Elasticsearch will accept and store any other fields even if they are not specified in your mappings. +Never use `enabled: false` or `index: false` in your mappings. Elasticsearch does not support toggling these mapping options, so if +your plugin ever needs to query the data, you will not be able to do so. Since these fields cannot be queried, they would require +migrating to a new field and making associated code changes. Instead, use `dynamic: false` which provides the same flexibility while +maintaining the future ability to query fields if necessary. + +Here's an example of what NOT to do: + +```ts +export const dashboardVisualization: SavedObjectsType = { + name: 'dashboard_visualization', + ... + mappings: { + properties: { + metadata: { + enabled: false, // ❌ Don't do this + properties: { + created_by: { type: 'keyword' } + } + }, + description: { + index: false, // ❌ Don't do this + type: 'text' + } + } + } +}; +``` + +Instead, use `dynamic: false` if you want to persist data which does not need to be queryable. +```ts +export const dashboardVisualization: SavedObjectsType = { + name: 'dashboard_visualization', + ... + mappings: { + properties: { + dynamic: false, // ✅ Do this instead + metadata: { + // dynamic: false gets inherited from above + properties: { + // `created_by` can now be stored but won't be queryable + } + }, + // `description` can now be stored but won't be queryable + } + } +}; +``` + +This approach maintains flexibility while ensuring all fields remain queryable if needed in the future. + Since Elasticsearch has a default limit of 1000 fields per index, plugins should carefully consider the fields they add to the mappings. Similarly, Saved Object types should never use `dynamic: true` as this can cause an arbitrary amount of fields to be added to the .kibana index. diff --git a/docs/CHANGELOG.asciidoc b/docs/CHANGELOG.asciidoc index 848042e475fe..ef8d4182144f 100644 --- a/docs/CHANGELOG.asciidoc +++ b/docs/CHANGELOG.asciidoc @@ -27,6 +27,59 @@ For information about the {kib} 9.0.0 release, review the following information. [[breaking-changes-9.0.0]] === Breaking changes +[discrete] +.Removed legacy alerting endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `POST /api/alerts/alert/{id?}` has been replaced by `POST /api/alerting/rule/{id?}` +* `GET /api/alerts/alert/{id}` has been replaced by `GET /api/alerting/rule/{id}` +* `PUT /api/alerts/alert/{id}` has been replaced by `PUT /api/alerting/rule/rule/{id}` +* `DELETE: /api/alerts/alert/{id}` has been replaced by `DELETE /api/alerting/rule/{id}` +* `POST /api/alerts/alert/{id}/_disable` has been replaced by `POST /api/alerting/rule/{id}/_disable` +* `POST /api/alerts/alert/{id}/_enable` has been replaced by `POST /api/alerting/rule/{id}/_enable` +* `GET /api/alerts/_find` has been replaced by `GET /api/alerting/rules/_find` +* `GET /api/alerts/_health` has been replaced by `GET /api/alerting/rule/_health` +* `GET /api/alerts/list_alert_types` has been replaced by `GET /api/alerting/rule_types` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_unmute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute` +* `POST /api/alerts/alert/{id}/_mute_all` has been replaced by `POST /api/alerting/rule/{id}/_mute_all` +* `POST /api/alerts/alert/{id}/_unmute_all` has been replaced by `POST /api/alerting/rule/{id}/_unmute_all` +* `POST /api/alerts/alert/{id}/_update_api_key` has been replaced by `POST /api/alerting/rule/{id}/_update_api_key` +* `GET /api/alerts/{id}/_instance_summary` has been deprecated without replacement. Will be removed in v9.0.0 +* `GET /api/alerts/{id}/state` has been deprecated without replacement. Will be removed in v9.0.0 +-- + +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 + +*Action* + +Remove references to `GET /api/alerts/{id}/_instance_summary` endpoint. +Remove references to `GET /api/alerts/{id}/state` endpoint. +Replace references to endpoints listed as deprecated by it's replacement. See `Details` section. +The updated APIs can be found in {api-kibana}/group/endpoint-alerting +==== + +.Removed legacy cases endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `GET /api/cases/status` has been deprecated with no replacement. Deleted in v9.0.0 +* `GET /api/cases/{case_id}/comments` has been replaced by `GET /api/cases/{case_id}/comments/_find` released in v7.13 +* `GET /api/cases//user_actions` has been replaced by `GET /api/cases//user_actions/_find` released in v8.7 +* `includeComments` parameter in `GET /api/cases/{case_id}` has been deprecated. Use `GET /api/cases/{case_id}/comments/_find` instead, released in v7.13 +-- + +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 + +*Action* + +Remove references to `GET /api/cases/status` endpoint. +Replace references to deprecated endpoints with the replacements listed in the breaking change details. +==== + [discrete] .Removed all security v1 endpoints (9.0.0) [%collapsible] diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index efe65e4a9954..00841c869ef4 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -470,6 +470,10 @@ The plugin exposes the static DefaultEditorController class to consume. |WARNING: Missing README. +|{kib-repo}blob/{branch}/x-pack/plugins/asset_inventory/README.md[assetInventory] +|Centralized asset inventory experience within the Elastic Security solution. A central place for users to view and manage all their assets from different environments. + + |{kib-repo}blob/{branch}/x-pack/plugins/banners/README.md[banners] |Allow to add a header banner that will be displayed on every page of the Kibana application @@ -917,6 +921,10 @@ routes, etc. |This plugin provides an interface to manage streams +|{kib-repo}blob/{branch}/x-pack/plugins/streams_app/README.md[streamsApp] +|Home of the Streams app plugin, which allows users to manage Streams via the UI. + + |{kib-repo}blob/{branch}/x-pack/plugins/observability_solution/synthetics/README.md[synthetics] |The purpose of this plugin is to provide users of Heartbeat more visibility of what's happening in their infrastructure. diff --git a/docs/discover/document-explorer.asciidoc b/docs/discover/document-explorer.asciidoc index 921e0504f459..47b4a5bc3fcf 100644 --- a/docs/discover/document-explorer.asciidoc +++ b/docs/discover/document-explorer.asciidoc @@ -29,7 +29,7 @@ image:images/discover-customize-table.png[Options to customize the table in Disc [[document-explorer-columns]] ==== Reorder and resize the columns -* To move a single column, open the column's contextual options, and select *Move left* or *Move right* in the available options. +* To move a single column, drag its header and drop it to the position you want. You can also open the column's contextual options, and select *Move left* or *Move right* in the available options. * To move multiple columns, click *Columns*. In the pop-up, drag the column names to their new order. diff --git a/docs/management/advanced-options.asciidoc b/docs/management/advanced-options.asciidoc index f6b8e6844ce0..fde70b5ffca0 100644 --- a/docs/management/advanced-options.asciidoc +++ b/docs/management/advanced-options.asciidoc @@ -208,10 +208,6 @@ The default refresh interval for the time filter. Example: [[timepicker-timedefaults]]`timepicker:timeDefaults`:: The default selection in the time filter. -[[truncate-maxheight]]`truncate:maxHeight`:: -deprecated:[8.16.0]The maximum height that a cell occupies in a table. Set to 0 to disable -truncation. - [[enableESQL]]`enableESQL`:: This setting enables ES|QL in Kibana. @@ -340,14 +336,6 @@ Hides the "Time" column in *Discover* and in all saved searches on dashboards. Highlights results in *Discover* and saved searches on dashboards. Highlighting slows requests when working on big documents. -[[doctable-legacy]]`doc_table:legacy`:: -deprecated:[8.15.0] Controls the way the document table looks and works. -To use the new *Document Explorer* instead of the classic view, turn off this option. -The *Document Explorer* offers better data sorting, resizable columns, and a full screen view. - -[[truncate-max-height]]`truncate:maxHeight`:: -The maximum height that a cell in a table can occupy. To disable truncation, set to 0. - [float] [[kibana-ml-settings]] diff --git a/docs/maps/asset-tracking-tutorial.asciidoc b/docs/maps/asset-tracking-tutorial.asciidoc index b1ded453214f..d7f8497c50b9 100644 --- a/docs/maps/asset-tracking-tutorial.asciidoc +++ b/docs/maps/asset-tracking-tutorial.asciidoc @@ -24,7 +24,7 @@ image::maps/images/asset-tracking-tutorial/construction_zones.png[] [float] === Prerequisites -- If you don’t already have {kib}, set it up with https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&elektra=docs[our free trial]. Download the deployment credentials. +- If you don’t already have {kib}, sign up for https://www.elastic.co/cloud/elasticsearch-service/signup?baymax=docs-body&elektra=docs[a free Elastic Cloud trial] and create a hosted deployment. When creating it, download the deployment credentials. - Obtain an API key for https://developer.trimet.org/[TriMet web services] at https://developer.trimet.org/appid/registration/. - {fleet-guide}/fleet-overview.html[Fleet] is enabled on your cluster, and one or more {fleet-guide}/elastic-agent-installation.html[{agent}s] is enrolled. diff --git a/docs/search/images/inference-endpoints-ui.png b/docs/search/images/inference-endpoints-ui.png new file mode 100644 index 000000000000..a4e091b6091f Binary files /dev/null and b/docs/search/images/inference-endpoints-ui.png differ diff --git a/docs/search/inference-endpoints/index.asciidoc b/docs/search/inference-endpoints/index.asciidoc index 30ead243d151..d547e00dd5b5 100644 --- a/docs/search/inference-endpoints/index.asciidoc +++ b/docs/search/inference-endpoints/index.asciidoc @@ -2,4 +2,14 @@ [[inference-endpoints]] == Inference endpoints UI -(coming in 8.16.0) \ No newline at end of file +Inference endpoints streamline the deployment and management of machine learning models in +{es}. The *Inference endpoints* page in {kib} provides an interface for displaying inference +endpoints that have been created using the {ref}/put-inference-api.html[Inference API]. + +[role="screenshot"] +image::images/inference-endpoints-ui.png[Inference endpoints UI] + +Available actions: + +* Copy the inference endpoint ID +* Delete endpoints \ No newline at end of file diff --git a/docs/settings/alert-action-settings.asciidoc b/docs/settings/alert-action-settings.asciidoc index 0f4987822dc3..6bd7eb1e7634 100644 --- a/docs/settings/alert-action-settings.asciidoc +++ b/docs/settings/alert-action-settings.asciidoc @@ -577,12 +577,6 @@ For a <>, <> - `xpack.alerting.cancelAlertsOnRuleTimeout` {ess-icon}:: Specifies whether to skip writing alerts and scheduling actions if rule processing was cancelled due to a timeout. Default: `true`. This setting can be diff --git a/docs/setup/install.asciidoc b/docs/setup/install.asciidoc index 83e6b6f26b33..c3bb456721b9 100644 --- a/docs/setup/install.asciidoc +++ b/docs/setup/install.asciidoc @@ -2,9 +2,9 @@ == Install {kib} [float] -=== Hosted {kib} +=== {kib} on Elastic Cloud -If you are running our hosted Elasticsearch Service on Elastic Cloud, you access Kibana with a single click. (You can {ess-trial}[sign up for a free trial] and start exploring data in minutes.) +If you are using Elastic Cloud, you access Kibana with a single click. (You can {ess-trial}[sign up for a free trial] and start exploring data in minutes.) [float] === Install {kib} yourself diff --git a/docs/setup/secure-settings.asciidoc b/docs/setup/secure-settings.asciidoc index 63d0465db9a0..4dc80b097b69 100644 --- a/docs/setup/secure-settings.asciidoc +++ b/docs/setup/secure-settings.asciidoc @@ -8,8 +8,8 @@ keystore, and the `kibana-keystore` tool to manage the settings in the keystore. [NOTE] ==== * Run all commands as the user who runs {kib}. -* Only the settings with the `(Secure)` qualifier should be stored in the keystore. - Unsupported, extraneous or invalid JSON-string settings cause {kib} to fail to start up. +* Any valid {kib} setting can be stored in the keystore securely. + Unsupported, extraneous or invalid settings will cause {kib} to fail to start up. ==== [float] diff --git a/docs/upgrade-notes.asciidoc b/docs/upgrade-notes.asciidoc index 329b6ab5cb66..236d768b16d4 100644 --- a/docs/upgrade-notes.asciidoc +++ b/docs/upgrade-notes.asciidoc @@ -50,6 +50,60 @@ For Elastic Security solution release information, refer to {security-guide}/rel [discrete] +[[breaking-201550]] +.Removed legacy alerting endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `POST /api/alerts/alert/{id?}` has been replaced by `POST /api/alerting/rule/{id?}` +* `GET /api/alerts/alert/{id}` has been replaced by `GET /api/alerting/rule/{id}` +* `PUT /api/alerts/alert/{id}` has been replaced by `PUT /api/alerting/rule/rule/{id}` +* `DELETE: /api/alerts/alert/{id}` has been replaced by `DELETE /api/alerting/rule/{id}` +* `POST /api/alerts/alert/{id}/_disable` has been replaced by `POST /api/alerting/rule/{id}/_disable` +* `POST /api/alerts/alert/{id}/_enable` has been replaced by `POST /api/alerting/rule/{id}/_enable` +* `GET /api/alerts/_find` has been replaced by `GET /api/alerting/rules/_find` +* `GET /api/alerts/_health` has been replaced by `GET /api/alerting/rule/_health` +* `GET /api/alerts/list_alert_types` has been replaced by `GET /api/alerting/rule_types` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_mute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_mute` +* `POST /api/alerts/alert/{alert_id}/alert_instance/{alert_instance_id}/_unmute` has been replaced by `POST /api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute` +* `POST /api/alerts/alert/{id}/_mute_all` has been replaced by `POST /api/alerting/rule/{id}/_mute_all` +* `POST /api/alerts/alert/{id}/_unmute_all` has been replaced by `POST /api/alerting/rule/{id}/_unmute_all` +* `POST /api/alerts/alert/{id}/_update_api_key` has been replaced by `POST /api/alerting/rule/{id}/_update_api_key` +* `GET /api/alerts/{id}/_instance_summary` has been deprecated without replacement. Will be removed in v9.0.0 +* `GET /api/alerts/{id}/state` has been deprecated without replacement. Will be removed in v9.0.0 +-- + +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 + +*Action* + +Remove references to `GET /api/alerts/{id}/_instance_summary` endpoint. +Remove references to `GET /api/alerts/{id}/state` endpoint. +Replace references to endpoints listed as deprecated by it's replacement. See `Details` section. +The updated APIs can be found here https://www.elastic.co/docs/api/doc/kibana/v8/group/endpoint-alerting +==== + +[[breaking-201004]] +.Removed legacy cases endpoints (9.0.0) +[%collapsible] +==== +*Details* + +-- +* `GET /api/cases/status` has been deprecated with no replacement. Deleted in v9.0.0 +* `GET /api/cases/{case_id}/comments` has been replaced by `GET /api/cases/{case_id}/comments/_find` released in v7.13 +* `GET /api/cases//user_actions` has been replaced by `GET /api/cases//user_actions/_find` released in v8.7 +* `includeComments` parameter in `GET /api/cases/{case_id}` has been deprecated. Use `GET /api/cases/{case_id}/comments/_find` instead, released in v7.13 +-- + +*Impact* + +Deprecated endpoints will fail with a 404 status code starting from version 9.0.0 + +*Action* + +Remove references to `GET /api/cases/status` endpoint. +Replace references to deprecated endpoints with the replacements listed in the breaking change details. +==== + [[breaking-199656]] .Removed all security v1 endpoints (9.0.0) [%collapsible] @@ -112,4 +166,3 @@ To access the assistant, go to **Stack Management** > **Upgrade Assistant**. - diff --git a/docs/user/alerting/troubleshooting/testing-connectors.asciidoc b/docs/user/alerting/troubleshooting/testing-connectors.asciidoc index 3170ec27ccdb..7d505f6eab80 100644 --- a/docs/user/alerting/troubleshooting/testing-connectors.asciidoc +++ b/docs/user/alerting/troubleshooting/testing-connectors.asciidoc @@ -18,7 +18,7 @@ image::user/alerting/images/teams-connector-test.png[Five clauses define the con ==== experimental[] Troubleshooting connectors with the `kbn-action` tool You can run an email action via https://github.com/pmuellr/kbn-action[kbn-action]. -In this example, it is a Cloud deployment of the {stack}: +In this example, it is a Cloud hosted deployment of the {stack}: [source, txt] -------------------------------------------------- diff --git a/docs/user/reporting/index.asciidoc b/docs/user/reporting/index.asciidoc index ed4fef61026f..4425cc45d9b4 100644 --- a/docs/user/reporting/index.asciidoc +++ b/docs/user/reporting/index.asciidoc @@ -72,7 +72,7 @@ NOTE: You can use the *Copy POST URL* option instead to generate the report from You can then download it from that message, or go to the *Stack Management > Reporting* page to view and access all of your reports. -NOTE: In "stateful" deployments, reports are stored in {es} and managed by the `kibana-reporting` {ilm} +NOTE: In self-managed and Cloud hosted deployments, reports are stored in {es} and managed by the `kibana-reporting` {ilm} ({ilm-init}) policy. By default, the policy stores reports forever. To learn more about {ilm-init} policies, refer to the {es} {ref}/index-lifecycle-management.html[{ilm-init} documentation]. @@ -108,7 +108,7 @@ Create and share JSON files for workpads. * *Embed code* — Embed fully interactive dashboards as an iframe on web pages. [[reporting-on-cloud-resource-requirements]] -NOTE: For Elastic Cloud deployments, {kib} instances require a minimum of 2GB RAM to generate PDF or PNG reports. To +NOTE: For Elastic Cloud hosted deployments, {kib} instances require a minimum of 2GB RAM to generate PDF or PNG reports. To change {kib} sizing, {ess-console}[edit the deployment]. diff --git a/examples/grid_example/public/app.tsx b/examples/grid_example/public/app.tsx index f144daa29f1a..1a44d2cb4f8c 100644 --- a/examples/grid_example/public/app.tsx +++ b/examples/grid_example/public/app.tsx @@ -23,10 +23,12 @@ import { EuiPageTemplate, EuiProvider, EuiSpacer, + EuiButtonGroup, + EuiButtonIcon, } from '@elastic/eui'; import { AppMountParameters } from '@kbn/core-application-browser'; import { CoreStart } from '@kbn/core-lifecycle-browser'; -import { GridLayout, GridLayoutData } from '@kbn/grid-layout'; +import { GridLayout, GridLayoutData, GridAccessMode } from '@kbn/grid-layout'; import { i18n } from '@kbn/i18n'; import { getPanelId } from './get_panel_id'; @@ -46,6 +48,8 @@ const DASHBOARD_GRID_COLUMN_COUNT = 48; export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { const savedState = useRef(getSerializedDashboardState()); const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false); + const [expandedPanelId, setExpandedPanelId] = useState(); + const [accessMode, setAccessMode] = useState('EDIT'); const [currentLayout, setCurrentLayout] = useState( dashboardInputToGridLayout(savedState.current) ); @@ -72,6 +76,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => {
{id}
{ + setExpandedPanelId(undefined); mockDashboardApi.removePanel(id); }} > @@ -81,6 +86,7 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { { + setExpandedPanelId(undefined); const newPanelId = await getPanelId({ coreStart, suggestion: id, @@ -92,10 +98,25 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { defaultMessage: 'Replace panel', })} + setExpandedPanelId((expandedId) => (expandedId ? undefined : id))} + aria-label={ + expandedPanelId + ? i18n.translate('examples.gridExample.minimizePanel', { + defaultMessage: 'Minimize panel {id}', + values: { id }, + }) + : i18n.translate('examples.gridExample.maximizePanel', { + defaultMessage: 'Maximize panel {id}', + values: { id }, + }) + } + /> ); }, - [coreStart, mockDashboardApi] + [coreStart, mockDashboardApi, setExpandedPanelId, expandedPanelId] ); return ( @@ -107,7 +128,12 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { defaultMessage: 'Grid Layout Example', })} /> - + { { + setExpandedPanelId(undefined); const panelId = await getPanelId({ coreStart, suggestion: uuidv4(), @@ -146,6 +173,34 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { + + { + setAccessMode(id as GridAccessMode); + }} + /> + {hasUnsavedChanges && ( @@ -190,6 +245,8 @@ export const GridExample = ({ coreStart }: { coreStart: CoreStart }) => { security: - apiKeyAuth: [] tags: @@ -7560,42 +7560,6 @@ paths: tags: - Security Entity Analytics API x-beta: true - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/Security_Entity_Analytics_API_IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API - x-beta: true /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -7749,6 +7713,12 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: If true returns a detailed status of the engine including all it's components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -7758,10 +7728,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + allOf: + - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/Security_Entity_Analytics_API_StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -9909,6 +9889,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -10618,6 +10603,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -11167,6 +11157,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -11696,6 +11691,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -12404,6 +12404,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -12953,6 +12958,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -13891,6 +13901,16 @@ paths: type: string type: array - type: string + - in: query + name: pkgName + required: false + schema: + type: string + - in: query + name: pkgVersion + required: false + schema: + type: string - in: query name: previewData required: false @@ -25537,6 +25557,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -25865,6 +25890,11 @@ paths: description: Agent policy IDs where that package policy will be added type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: additionalProperties: false @@ -26015,6 +26045,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: anyOf: @@ -26366,6 +26401,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -26826,6 +26866,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -27325,6 +27370,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -27655,6 +27705,11 @@ paths: description: Agent policy IDs where that package policy will be added type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: additionalProperties: false @@ -27804,6 +27859,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: anyOf: @@ -28154,6 +28214,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -28931,6 +28996,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -29210,6 +29280,11 @@ paths: description: Agent policy IDs where that package policy will be added type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: additionalProperties: false @@ -29839,6 +29914,7 @@ paths: secret_storage_requirements_met: type: boolean use_space_awareness_migration_started_at: + nullable: true type: string use_space_awareness_migration_status: enum: @@ -29972,6 +30048,7 @@ paths: secret_storage_requirements_met: type: boolean use_space_awareness_migration_started_at: + nullable: true type: string use_space_awareness_migration_status: enum: @@ -32150,8 +32227,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: exportSavedObjectsDefault parameters: - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' @@ -32210,8 +32285,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: importSavedObjectsDefault parameters: - $ref: '#/components/parameters/Serverless_saved_objects_kbn_xsrf' @@ -34415,8 +34488,6 @@ paths: schema: $ref: '#/components/schemas/SLOs_409_response' description: Conflict - The SLO id already exists - servers: - - url: https://localhost:5601 summary: Create an SLO tags: - slo @@ -34456,8 +34527,6 @@ paths: schema: $ref: '#/components/schemas/SLOs_403_response' description: Unauthorized response - servers: - - url: https://localhost:5601 summary: Batch delete rollup and summary data tags: - slo @@ -45658,6 +45727,47 @@ components: $ref: '#/components/schemas/Security_Entity_Analytics_API_AssetCriticalityLevel' required: - criticality_level + Security_Entity_Analytics_API_EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + Security_Entity_Analytics_API_EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentResource' + required: + - id + - installed + - resource Security_Entity_Analytics_API_EngineDataviewUpdateResult: type: object properties: @@ -48553,19 +48663,23 @@ components: properties: frequency: default: 1m - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. example: 5m type: string preventInitialBackfill: default: false - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. example: true type: boolean syncDelay: default: 1m - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. example: 5m type: string + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + example: event.ingested + type: string title: Settings type: object SLOs_slo_definition_response: diff --git a/oas_docs/output/kibana.yaml b/oas_docs/output/kibana.yaml index 6780ef4926c7..b1f218626236 100644 --- a/oas_docs/output/kibana.yaml +++ b/oas_docs/output/kibana.yaml @@ -10445,41 +10445,6 @@ paths: summary: Start an Entity Engine tags: - Security Entity Analytics API - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - responses: - '200': - content: - application/json; Elastic-Api-Version=2023-10-31: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/Security_Entity_Analytics_API_IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -10630,6 +10595,12 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: If true returns a detailed status of the engine including all it's components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -10639,10 +10610,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + allOf: + - $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/Security_Entity_Analytics_API_StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -12769,6 +12750,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -13477,6 +13463,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -14025,6 +14016,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -14553,6 +14549,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -15260,6 +15261,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -15808,6 +15814,11 @@ paths: required: - id type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -16739,6 +16750,16 @@ paths: type: string type: array - type: string + - in: query + name: pkgName + required: false + schema: + type: string + - in: query + name: pkgVersion + required: false + schema: + type: string - in: query name: previewData required: false @@ -28320,6 +28341,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -28647,6 +28673,11 @@ paths: description: Agent policy IDs where that package policy will be added type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: additionalProperties: false @@ -28797,6 +28828,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: anyOf: @@ -29148,6 +29184,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -29607,6 +29648,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -30104,6 +30150,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -30433,6 +30484,11 @@ paths: description: Agent policy IDs where that package policy will be added type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: additionalProperties: false @@ -30582,6 +30638,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: anyOf: @@ -30932,6 +30993,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -31706,6 +31772,11 @@ paths: items: type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean updated_at: type: string updated_by: @@ -31985,6 +32056,11 @@ paths: description: Agent policy IDs where that package policy will be added type: string type: array + supports_agentless: + default: false + description: Indicates whether the package policy belongs to an agentless agent policy. + nullable: true + type: boolean vars: additionalProperties: additionalProperties: false @@ -32607,6 +32683,7 @@ paths: secret_storage_requirements_met: type: boolean use_space_awareness_migration_started_at: + nullable: true type: string use_space_awareness_migration_status: enum: @@ -32739,6 +32816,7 @@ paths: secret_storage_requirements_met: type: boolean use_space_awareness_migration_started_at: + nullable: true type: string use_space_awareness_migration_status: enum: @@ -34992,7 +35070,7 @@ paths: schema: type: object description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. '400': content: application/json; Elastic-Api-Version=2023-10-31: @@ -35024,7 +35102,7 @@ paths: schema: type: object description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. '400': content: application/json; Elastic-Api-Version=2023-10-31: @@ -35043,8 +35121,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: exportSavedObjectsDefault parameters: - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' @@ -35204,8 +35280,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: importSavedObjectsDefault parameters: - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' @@ -35302,8 +35376,6 @@ paths: * Retry certain saved objects * Overwrite specific saved objects * Change references to different saved objects - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. operationId: resolveImportErrors parameters: - $ref: '#/components/parameters/Saved_objects_kbn_xsrf' @@ -53381,6 +53453,47 @@ components: $ref: '#/components/schemas/Security_Entity_Analytics_API_AssetCriticalityLevel' required: - criticality_level + Security_Entity_Analytics_API_EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + Security_Entity_Analytics_API_EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/Security_Entity_Analytics_API_EngineComponentResource' + required: + - id + - installed + - resource Security_Entity_Analytics_API_EngineDataviewUpdateResult: type: object properties: @@ -56258,19 +56371,23 @@ components: properties: frequency: default: 1m - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. example: 5m type: string preventInitialBackfill: default: false - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. example: true type: boolean syncDelay: default: 1m - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. example: 5m type: string + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + example: event.ingested + type: string title: Settings type: object SLOs_slo_definition_response: diff --git a/oas_docs/overlays/kibana.overlays.serverless.yaml b/oas_docs/overlays/kibana.overlays.serverless.yaml index 1054f774fe11..36efbe18e940 100644 --- a/oas_docs/overlays/kibana.overlays.serverless.yaml +++ b/oas_docs/overlays/kibana.overlays.serverless.yaml @@ -14,7 +14,7 @@ actions: - url: https://{kibana_url} variables: kibana_url: - default: localhost:5601 + default: # Mark all operations as beta - target: "$.paths[*]['get','put','post','delete','options','head','patch','trace']" description: Add x-beta diff --git a/oas_docs/overlays/kibana.overlays.yaml b/oas_docs/overlays/kibana.overlays.yaml index ed41f56088bf..666cba540a65 100644 --- a/oas_docs/overlays/kibana.overlays.yaml +++ b/oas_docs/overlays/kibana.overlays.yaml @@ -4,6 +4,17 @@ info: title: Overlays for the Kibana API document version: 0.0.1 actions: +# Clean up server definitions + - target: '$.servers.*' + description: Remove all servers so we can add our own. + remove: true + - target: '$.servers' + description: Add server into the now empty server array. + update: + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 # Add an introduction to spaces - target: '$' description: Add an extra page about spaces diff --git a/oas_docs/package-lock.json b/oas_docs/package-lock.json index 70fff86254f6..ab921922f0d1 100644 --- a/oas_docs/package-lock.json +++ b/oas_docs/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@redocly/cli": "^1.25.11", + "@redocly/cli": "^1.25.14", "bump-cli": "^2.8.4" } }, @@ -515,12 +515,12 @@ } }, "node_modules/@redocly/cli": { - "version": "1.25.11", - "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.25.11.tgz", - "integrity": "sha512-dttBsmLnnbTlJCTa+s7Sy+qtXDq692n7Ru3nUUIHp9XdCbhXIHWhpc8uAl+GmR4MGbVe8ohATl3J+zX3aFy82A==", + "version": "1.25.15", + "resolved": "https://registry.npmjs.org/@redocly/cli/-/cli-1.25.15.tgz", + "integrity": "sha512-ZD743CJX4FpMJvGNE9Cm3gNn8LNRzRjyrYNVPi1C4iIEtrFkr5Zq791qv6gUFehWns71svbVyzWD9ftVTdfqYg==", "license": "MIT", "dependencies": { - "@redocly/openapi-core": "1.25.11", + "@redocly/openapi-core": "1.25.15", "abort-controller": "^3.0.0", "chokidar": "^3.5.1", "colorette": "^1.2.0", @@ -550,17 +550,19 @@ } }, "node_modules/@redocly/config": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.16.0.tgz", - "integrity": "sha512-t9jnODbUcuANRSl/K4L9nb12V+U5acIHnVSl26NWrtSdDZVtoqUXk2yGFPZzohYf62cCfEQUT8ouJ3bhPfpnJg==" + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.17.1.tgz", + "integrity": "sha512-CEmvaJuG7pm2ylQg53emPmtgm4nW2nxBgwXzbVEHpGas/lGnMyN8Zlkgiz6rPw0unASg6VW3wlz27SOL5XFHYQ==", + "license": "MIT" }, "node_modules/@redocly/openapi-core": { - "version": "1.25.11", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.11.tgz", - "integrity": "sha512-bH+a8izQz4fnKROKoX3bEU8sQ9rjvEIZOqU6qTmxlhOJ0NsKa5e+LmU18SV0oFeg5YhWQhhEDihXkvKJ1wMMNQ==", + "version": "1.25.15", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.25.15.tgz", + "integrity": "sha512-/dpr5zpGj2t1Bf7EIXEboRZm1hsJZBQfv3Q1pkivtdAEg3if2khv+b9gY68aquC6cM/2aQY2kMLy8LlY2tn+Og==", + "license": "MIT", "dependencies": { "@redocly/ajv": "^8.11.2", - "@redocly/config": "^0.16.0", + "@redocly/config": "^0.17.0", "colorette": "^1.2.0", "https-proxy-agent": "^7.0.4", "js-levenshtein": "^1.1.6", diff --git a/oas_docs/package.json b/oas_docs/package.json index 3f6cae5c044b..9510dc4d31dc 100644 --- a/oas_docs/package.json +++ b/oas_docs/package.json @@ -8,7 +8,7 @@ }, "dependencies": { "bump-cli": "^2.8.4", - "@redocly/cli": "^1.25.11" + "@redocly/cli": "^1.25.14" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" diff --git a/package.json b/package.json index eca3c7830912..a4ad63ebb3b9 100644 --- a/package.json +++ b/package.json @@ -111,20 +111,20 @@ "@elastic/apm-rum": "^5.16.1", "@elastic/apm-rum-core": "^5.21.1", "@elastic/apm-rum-react": "^2.0.3", - "@elastic/charts": "68.0.2", + "@elastic/charts": "68.0.3", "@elastic/datemath": "5.0.3", "@elastic/ebt": "^1.1.1", "@elastic/ecs": "^8.11.1", "@elastic/elasticsearch": "^8.15.2", "@elastic/ems-client": "8.5.3", - "@elastic/eui": "97.3.1-borealis.2", - "@elastic/eui-theme-borealis": "0.0.2", + "@elastic/eui": "98.0.0-borealis.1", + "@elastic/eui-theme-borealis": "0.0.3", "@elastic/filesaver": "1.1.2", "@elastic/node-crypto": "^1.2.3", "@elastic/numeral": "^2.5.1", "@elastic/react-search-ui": "^1.20.2", "@elastic/react-search-ui-views": "^1.20.2", - "@elastic/request-converter": "^8.16.1", + "@elastic/request-converter": "^8.16.2", "@elastic/request-crypto": "^2.0.3", "@elastic/search-ui": "^1.20.2", "@elastic/search-ui-app-search-connector": "^1.20.2", @@ -191,6 +191,7 @@ "@kbn/apm-utils": "link:packages/kbn-apm-utils", "@kbn/app-link-test-plugin": "link:test/plugin_functional/plugins/app_link_test", "@kbn/application-usage-test-plugin": "link:x-pack/test/usage_collection/plugins/application_usage_test", + "@kbn/asset-inventory-plugin": "link:x-pack/plugins/asset_inventory", "@kbn/audit-log-plugin": "link:x-pack/test/security_api_integration/plugins/audit_log", "@kbn/avc-banner": "link:packages/kbn-avc-banner", "@kbn/banners-plugin": "link:x-pack/plugins/banners", @@ -785,6 +786,7 @@ "@kbn/saved-objects-settings": "link:packages/kbn-saved-objects-settings", "@kbn/saved-objects-tagging-oss-plugin": "link:src/plugins/saved_objects_tagging_oss", "@kbn/saved-objects-tagging-plugin": "link:x-pack/plugins/saved_objects_tagging", + "@kbn/saved-search-component": "link:packages/kbn-saved-search-component", "@kbn/saved-search-plugin": "link:src/plugins/saved_search", "@kbn/screenshot-mode-example-plugin": "link:examples/screenshot_mode_example", "@kbn/screenshot-mode-plugin": "link:src/plugins/screenshot_mode", @@ -937,6 +939,7 @@ "@kbn/status-plugin-a-plugin": "link:test/server_integration/plugins/status_plugin_a", "@kbn/status-plugin-b-plugin": "link:test/server_integration/plugins/status_plugin_b", "@kbn/std": "link:packages/kbn-std", + "@kbn/streams-app-plugin": "link:x-pack/plugins/streams_app", "@kbn/streams-plugin": "link:x-pack/plugins/streams", "@kbn/synthetics-plugin": "link:x-pack/plugins/observability_solution/synthetics", "@kbn/synthetics-private-location": "link:x-pack/packages/kbn-synthetics-private-location", @@ -1029,7 +1032,7 @@ "@langchain/langgraph": "0.2.19", "@langchain/openai": "^0.3.11", "@langtrase/trace-attributes": "^7.5.0", - "@launchdarkly/node-server-sdk": "^9.7.1", + "@launchdarkly/node-server-sdk": "^9.7.2", "@launchdarkly/openfeature-node-server": "^1.0.0", "@loaders.gl/core": "^3.4.7", "@loaders.gl/json": "^3.4.7", @@ -1082,7 +1085,7 @@ "ajv": "^8.17.1", "ansi-regex": "^6.1.0", "antlr4": "^4.13.1-patch-1", - "archiver": "^5.3.1", + "archiver": "^7.0.1", "async": "^3.2.3", "aws4": "^1.13.2", "axios": "^1.7.4", @@ -1221,7 +1224,7 @@ "query-string": "^6.13.2", "rbush": "^3.0.1", "re-resizable": "^6.9.9", - "re2js": "0.4.2", + "re2js": "0.4.3", "react": "^17.0.2", "react-diff-view": "^3.2.1", "react-dom": "^17.0.2", @@ -1310,7 +1313,7 @@ "zod": "^3.22.3" }, "devDependencies": { - "@apidevtools/swagger-parser": "^10.0.3", + "@apidevtools/swagger-parser": "^10.1.0", "@babel/cli": "^7.24.7", "@babel/core": "^7.24.7", "@babel/eslint-parser": "^7.24.7", @@ -1429,6 +1432,8 @@ "@kbn/core-ui-settings-server-mocks": "link:packages/core/ui-settings/core-ui-settings-server-mocks", "@kbn/core-usage-data-server-mocks": "link:packages/core/usage-data/core-usage-data-server-mocks", "@kbn/cypress-config": "link:packages/kbn-cypress-config", + "@kbn/dependency-ownership": "link:packages/kbn-dependency-ownership", + "@kbn/dependency-usage": "link:packages/kbn-dependency-usage", "@kbn/dev-cli-errors": "link:packages/kbn-dev-cli-errors", "@kbn/dev-cli-runner": "link:packages/kbn-dev-cli-runner", "@kbn/dev-proc-runner": "link:packages/kbn-dev-proc-runner", @@ -1482,6 +1487,7 @@ "@kbn/repo-path": "link:packages/kbn-repo-path", "@kbn/repo-source-classifier": "link:packages/kbn-repo-source-classifier", "@kbn/repo-source-classifier-cli": "link:packages/kbn-repo-source-classifier-cli", + "@kbn/scout": "link:packages/kbn-scout", "@kbn/security-api-integration-helpers": "link:x-pack/test/security_api_integration/packages/helpers", "@kbn/serverless-storybook-config": "link:packages/serverless/storybook/config", "@kbn/some-dev-log": "link:packages/kbn-some-dev-log", @@ -1510,7 +1516,7 @@ "@octokit/rest": "^17.11.2", "@parcel/watcher": "^2.1.0", "@playwright/test": "=1.46.0", - "@redocly/cli": "^1.25.11", + "@redocly/cli": "^1.25.14", "@statoscope/webpack-plugin": "^5.28.2", "@storybook/addon-a11y": "^6.5.16", "@storybook/addon-actions": "^6.5.16", @@ -1531,7 +1537,7 @@ "@storybook/testing-react": "^1.3.0", "@storybook/theming": "^6.5.16", "@testing-library/dom": "^10.4.0", - "@testing-library/jest-dom": "^6.5.0", + "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.0.1", "@testing-library/react-hooks": "^8.0.1", "@testing-library/user-event": "^14.5.2", @@ -1621,7 +1627,7 @@ "@types/picomatch": "^2.3.0", "@types/pidusage": "^2.0.2", "@types/pixelmatch": "^5.2.4", - "@types/pngjs": "^3.4.0", + "@types/pngjs": "^6.0.5", "@types/prop-types": "^15.7.5", "@types/rbush": "^3.0.0", "@types/react": "~18.2.0", @@ -1688,7 +1694,7 @@ "buildkite-test-collector": "^1.7.0", "callsites": "^3.1.0", "chance": "1.0.18", - "chromedriver": "^130.0.4", + "chromedriver": "^131.0.1", "clarify": "^2.2.0", "clean-webpack-plugin": "^3.0.0", "cli-progress": "^3.12.0", @@ -1699,7 +1705,7 @@ "cssnano": "^5.1.12", "cssnano-preset-default": "^5.2.12", "csstype": "^3.0.2", - "cypress": "13.6.3", + "cypress": "13.15.2", "cypress-axe": "^1.5.0", "cypress-file-upload": "^5.0.8", "cypress-multi-reporters": "^1.6.4", @@ -1708,6 +1714,7 @@ "cypress-recurse": "^1.35.2", "date-fns": "^2.29.3", "dependency-check": "^4.1.0", + "dependency-cruiser": "^16.4.2", "ejs": "^3.1.10", "enzyme": "^3.11.0", "enzyme-to-json": "^3.6.2", @@ -1786,9 +1793,9 @@ "native-hdr-histogram": "^1.0.0", "nock": "12.0.3", "null-loader": "^3.0.0", - "nyc": "^15.1.0", - "oboe": "^2.1.4", - "openapi-types": "^10.0.0", + "nyc": "^17.1.0", + "oboe": "^2.1.7", + "openapi-types": "^12.1.3", "p-reflect": "2.1.0", "peggy": "^1.2.0", "picomatch": "^2.3.1", @@ -1798,7 +1805,7 @@ "pixelmatch": "^5.3.0", "playwright": "=1.46.0", "playwright-chromium": "=1.46.0", - "pngjs": "^3.4.0", + "pngjs": "^7.0.0", "postcss": "^8.4.31", "postcss-loader": "^4.2.0", "postcss-prefix-selector": "^1.16.0", @@ -1814,7 +1821,7 @@ "rxjs-marbles": "^7.0.1", "sass-embedded": "^1.78.0", "sass-loader": "^10.5.1", - "selenium-webdriver": "^4.26.0", + "selenium-webdriver": "^4.27.0", "sharp": "0.32.6", "simple-git": "^3.16.0", "sinon": "^7.4.2", @@ -1824,7 +1831,7 @@ "style-loader": "^1.1.3", "stylelint": "^14.9.1", "stylelint-scss": "^4.3.0", - "superagent": "^9.0.2", + "superagent": "^10.1.1", "supertest": "^7.0.0", "svgo": "^2.8.0", "swagger-jsdoc": "^6.2.8", @@ -1852,7 +1859,7 @@ "webpack-sources": "^1.4.1", "webpack-visualizer-plugin2": "^1.1.0", "xml-crypto": "^6.0.0", - "xmlbuilder": "13.0.2", + "xmlbuilder": "15.1.1", "yargs": "^15.4.1", "yarn-deduplicate": "^6.0.2", "zod-to-json-schema": "^3.23.0" diff --git a/packages/core/http/core-http-router-server-internal/src/router.test.ts b/packages/core/http/core-http-router-server-internal/src/router.test.ts index 2c702fb3ef70..f0eaa96879d4 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.test.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.test.ts @@ -305,6 +305,23 @@ describe('Router', () => { ); }); + it('throws if route has security declared wrong', () => { + const router = new Router('', logger, enhanceWithContext, routerOptions); + expect(() => + router.get( + // we use 'any' because validate requires valid Type or function usage + { + path: '/', + validate: false, + options: { security: { authz: { requiredPrivileges: [] } } } as any, + }, + (context, req, res) => res.ok({}) + ) + ).toThrowErrorMatchingInlineSnapshot( + `"\`options.security\` is not allowed in route config. Use \`security\` instead."` + ); + }); + it('throws if options.body.output is not a valid value', () => { const router = new Router('', logger, enhanceWithContext, routerOptions); expect(() => diff --git a/packages/core/http/core-http-router-server-internal/src/router.ts b/packages/core/http/core-http-router-server-internal/src/router.ts index c2ea09605c4e..c3e44f8bc9d7 100644 --- a/packages/core/http/core-http-router-server-internal/src/router.ts +++ b/packages/core/http/core-http-router-server-internal/src/router.ts @@ -115,6 +115,11 @@ function validOptions( ); } + // @ts-expect-error to eliminate problems with `security` in the options for route factories abstractions + if (options.security) { + throw new Error('`options.security` is not allowed in route config. Use `security` instead.'); + } + const body = shouldNotHavePayload ? undefined : { diff --git a/packages/core/http/core-http-server/src/router/request.ts b/packages/core/http/core-http-server/src/router/request.ts index 066372faca1e..6fff29eb42b5 100644 --- a/packages/core/http/core-http-server/src/router/request.ts +++ b/packages/core/http/core-http-server/src/router/request.ts @@ -48,9 +48,11 @@ export interface KibanaRequestState extends RequestApplicationState { * Route options: If 'GET' or 'OPTIONS' method, body options won't be returned. * @public */ -export type KibanaRequestRouteOptions = Method extends 'get' | 'options' +export type KibanaRequestRouteOptions = (Method extends + | 'get' + | 'options' ? Required, 'body'>> - : Required>; + : Required>) & { security?: RouteSecurity }; /** * Request specific route information exposed to a handler. diff --git a/packages/core/http/core-http-server/src/router/route.ts b/packages/core/http/core-http-server/src/router/route.ts index da24adcb6802..2efd40527411 100644 --- a/packages/core/http/core-http-server/src/router/route.ts +++ b/packages/core/http/core-http-server/src/router/route.ts @@ -398,13 +398,6 @@ export interface RouteConfigOptions { */ discontinued?: string; - /** - * Defines the security requirements for a route, including authorization and authentication. - * - * @remarks This will be surfaced in OAS documentation. - */ - security?: RouteSecurity; - /** * Whether this endpoint is being used to serve generated or static HTTP resources * like JS, CSS or HTML. _Do not set to `true` for HTTP APIs._ diff --git a/packages/core/http/core-http-server/src/versioning/types.ts b/packages/core/http/core-http-server/src/versioning/types.ts index 63e1e3775480..fa08810ce1fb 100644 --- a/packages/core/http/core-http-server/src/versioning/types.ts +++ b/packages/core/http/core-http-server/src/versioning/types.ts @@ -19,6 +19,7 @@ import type { RequestHandlerContextBase, RouteValidationFunction, LazyValidator, + RouteSecurity, } from '../..'; import type { RouteDeprecationInfo } from '../router/route'; type RqCtx = RequestHandlerContextBase; @@ -35,12 +36,12 @@ export type VersionedRouteConfig = Omit< > & { options?: Omit< RouteConfigOptions, - 'access' | 'description' | 'summary' | 'deprecated' | 'discontinued' | 'security' + 'access' | 'description' | 'summary' | 'deprecated' | 'discontinued' >; /** See {@link RouteConfigOptions['access']} */ access: Exclude['access'], undefined>; /** See {@link RouteConfigOptions['security']} */ - security?: Exclude['security'], undefined>; + security?: RouteSecurity; /** * When enabled, the router will also check for the presence of an `apiVersion` * query parameter to determine the route version to resolve to: @@ -337,7 +338,7 @@ export interface AddVersionOpts { */ validate: false | VersionedRouteValidation | (() => VersionedRouteValidation); // Provide a way to lazily load validation schemas - security?: Exclude['security'], undefined>; + security?: RouteSecurity; options?: { deprecated?: RouteDeprecationInfo; diff --git a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts index 9fe591d9c521..f8a50d39271d 100644 --- a/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts +++ b/packages/core/saved-objects/core-saved-objects-server-internal/src/routes/migrate.ts @@ -19,8 +19,10 @@ export const registerMigrateRoute = ( { path: '/_migrate', validate: false, - options: { - tags: ['access:migrateSavedObjects'], + security: { + authz: { + requiredPrivileges: ['migrateSavedObjects'], + }, }, }, catchAndReturnBoomErrors(async (context, req, res) => { diff --git a/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts b/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts index a29875a733d6..cb2930f5d467 100644 --- a/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts +++ b/packages/core/saved-objects/core-saved-objects-server/src/saved_objects_type.ts @@ -75,8 +75,11 @@ export interface SavedObjectsType { */ mappings: SavedObjectsTypeMappingDefinition; /** - * An optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of {@link SavedObjectMigrationFn | migrations} to be used to migrate the type. - * @deprecated Use {@link SavedObjectsType.modelVersions | modelVersions} instead. + * An optional map of {@link SavedObjectMigrationFn | migrations} or a function returning a map of + * {@link SavedObjectMigrationFn | migrations} to be used to migrate the type. + * + * @deprecated Use {@link SavedObjectsType.modelVersions | modelVersions} for all future migrations instead. We have no plans + * to remove legacy migrations at this point, so there's no need to migrate existing migrations to model versions. */ migrations?: SavedObjectMigrationMap | (() => SavedObjectMigrationMap); /** @@ -89,8 +92,8 @@ export interface SavedObjectsType { */ schemas?: SavedObjectsValidationMap | (() => SavedObjectsValidationMap); /** - * If defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to this - * version. + * If defined, objects of this type will be converted to a 'multiple' or 'multiple-isolated' namespace type when migrating to + * this version. * * Requirements: * diff --git a/packages/core/saved-objects/docs/openapi/bundled.json b/packages/core/saved-objects/docs/openapi/bundled.json index 45cfdd7fa505..c44533281666 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.json +++ b/packages/core/saved-objects/docs/openapi/bundled.json @@ -380,7 +380,7 @@ "post": { "summary": "Export saved objects", "operationId": "exportSavedObjectsDefault", - "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n", "tags": [ "saved objects" ], @@ -639,7 +639,7 @@ "post": { "summary": "Import saved objects", "operationId": "importSavedObjectsDefault", - "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n", "tags": [ "saved objects" ], @@ -759,7 +759,7 @@ "post": { "summary": "Resolve import errors", "operationId": "resolveImportErrors", - "description": "To resolve errors from the Import objects API, you can:\n\n* Retry certain saved objects\n* Overwrite specific saved objects\n* Change references to different saved objects\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "To resolve errors from the Import objects API, you can:\n\n* Retry certain saved objects\n* Overwrite specific saved objects\n* Change references to different saved objects\n", "tags": [ "saved objects" ], @@ -1423,4 +1423,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/core/saved-objects/docs/openapi/bundled.yaml b/packages/core/saved-objects/docs/openapi/bundled.yaml index 9b5aad6e5495..b62424c10a7f 100644 --- a/packages/core/saved-objects/docs/openapi/bundled.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled.yaml @@ -216,7 +216,7 @@ paths: responses: '200': description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. content: application/json: schema: @@ -248,7 +248,7 @@ paths: responses: '200': description: | - Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. + Indicates a successful call. NOTE: This HTTP response code indicates that the bulk operation succeeded. Errors pertaining to individual objects will be returned in the response body. content: application/json: schema: @@ -270,8 +270,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: @@ -431,8 +429,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: @@ -529,8 +525,6 @@ paths: * Retry certain saved objects * Overwrite specific saved objects * Change references to different saved objects - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/bundled_serverless.json b/packages/core/saved-objects/docs/openapi/bundled_serverless.json index 67b8a710b5bc..b225e95b1473 100644 --- a/packages/core/saved-objects/docs/openapi/bundled_serverless.json +++ b/packages/core/saved-objects/docs/openapi/bundled_serverless.json @@ -34,7 +34,7 @@ "post": { "summary": "Export saved objects", "operationId": "exportSavedObjectsDefault", - "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Retrieve sets of saved objects that you want to import into Kibana.\nYou must include `type` or `objects` in the request body.\n\nExported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nNOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported.\n", "tags": [ "saved objects" ], @@ -124,7 +124,7 @@ "post": { "summary": "Import saved objects", "operationId": "importSavedObjectsDefault", - "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n\nThis functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.\n", + "description": "Create sets of Kibana saved objects from a file created by the export API.\nSaved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana.\n", "tags": [ "saved objects" ], @@ -358,4 +358,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml b/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml index b874f0e32361..d6775921a308 100644 --- a/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml +++ b/packages/core/saved-objects/docs/openapi/bundled_serverless.yaml @@ -37,8 +37,6 @@ paths: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: @@ -96,8 +94,6 @@ paths: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml index 93224e4d243b..fd9c24805616 100644 --- a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml +++ b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_export.yaml @@ -8,8 +8,6 @@ post: Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. NOTE: The `savedObjects.maxImportExportSize` configuration setting limits the number of saved objects which may be exported. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml index 3f27987f779f..7bd9b6f801c4 100644 --- a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml +++ b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_import.yaml @@ -4,8 +4,6 @@ post: description: | Create sets of Kibana saved objects from a file created by the export API. Saved objects can be imported only into the same version, a newer minor on the same major, or the next major. Exported saved objects are not backwards compatible and cannot be imported into an older version of Kibana. - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml index bfca82dbe727..c6d2b23ce012 100644 --- a/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml +++ b/packages/core/saved-objects/docs/openapi/paths/api@saved_objects@_resolve_import_errors.yaml @@ -7,8 +7,6 @@ post: * Retry certain saved objects * Overwrite specific saved objects * Change references to different saved objects - - This functionality is in technical preview and may be changed or removed in a future release. Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features. tags: - saved objects parameters: diff --git a/packages/deeplinks/observability/constants.ts b/packages/deeplinks/observability/constants.ts index 25642ba69613..3dcc009481d0 100644 --- a/packages/deeplinks/observability/constants.ts +++ b/packages/deeplinks/observability/constants.ts @@ -35,3 +35,5 @@ export const OBLT_UX_APP_ID = 'ux'; export const OBLT_PROFILING_APP_ID = 'profiling'; export const INVENTORY_APP_ID = 'inventory'; + +export const STREAMS_APP_ID = 'streams'; diff --git a/packages/deeplinks/observability/deep_links.ts b/packages/deeplinks/observability/deep_links.ts index 1253b4e889fc..256350feb2e2 100644 --- a/packages/deeplinks/observability/deep_links.ts +++ b/packages/deeplinks/observability/deep_links.ts @@ -21,6 +21,7 @@ import { OBLT_UX_APP_ID, OBLT_PROFILING_APP_ID, INVENTORY_APP_ID, + STREAMS_APP_ID, } from './constants'; type LogsApp = typeof LOGS_APP_ID; @@ -36,6 +37,7 @@ type AiAssistantApp = typeof AI_ASSISTANT_APP_ID; type ObltUxApp = typeof OBLT_UX_APP_ID; type ObltProfilingApp = typeof OBLT_PROFILING_APP_ID; type InventoryApp = typeof INVENTORY_APP_ID; +type StreamsApp = typeof STREAMS_APP_ID; export type AppId = | LogsApp @@ -50,7 +52,8 @@ export type AppId = | AiAssistantApp | ObltUxApp | ObltProfilingApp - | InventoryApp; + | InventoryApp + | StreamsApp; export type LogsLinkId = 'log-categories' | 'settings' | 'anomalies' | 'stream'; @@ -83,13 +86,16 @@ export type SyntheticsLinkId = 'certificates' | 'overview'; export type ProfilingLinkId = 'stacktraces' | 'flamegraphs' | 'functions'; +export type StreamsLinkId = 'overview'; + export type LinkId = | LogsLinkId | ObservabilityOverviewLinkId | MetricsLinkId | ApmLinkId | SyntheticsLinkId - | ProfilingLinkId; + | ProfilingLinkId + | StreamsLinkId; export type DeepLinkId = | AppId @@ -99,4 +105,5 @@ export type DeepLinkId = | `${ApmApp}:${ApmLinkId}` | `${SyntheticsApp}:${SyntheticsLinkId}` | `${ObltProfilingApp}:${ProfilingLinkId}` - | `${InventoryApp}:${InventoryLinkId}`; + | `${InventoryApp}:${InventoryLinkId}` + | `${StreamsApp}:${StreamsLinkId}`; diff --git a/packages/kbn-alerting-types/search_strategy_types.ts b/packages/kbn-alerting-types/search_strategy_types.ts index 797ca82294b8..9df72e4fa788 100644 --- a/packages/kbn-alerting-types/search_strategy_types.ts +++ b/packages/kbn-alerting-types/search_strategy_types.ts @@ -8,7 +8,6 @@ */ import type { IEsSearchRequest, IEsSearchResponse } from '@kbn/search-types'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { MappingRuntimeFields, QueryDslFieldAndFormat, @@ -18,7 +17,8 @@ import type { import type { Alert } from './alert_type'; export type RuleRegistrySearchRequest = IEsSearchRequest & { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; fields?: QueryDslFieldAndFormat[]; query?: Pick; sort?: SortCombinations[]; diff --git a/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_threshold_schema.ts b/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_threshold_schema.ts new file mode 100644 index 000000000000..2f08e082aebe --- /dev/null +++ b/packages/kbn-alerts-as-data-utils/src/schemas/generated/observability_threshold_schema.ts @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +// ---------------------------------- WARNING ---------------------------------- +// this file was generated, and should not be edited by hand +// ---------------------------------- WARNING ---------------------------------- +import * as rt from 'io-ts'; +import { Either } from 'fp-ts/lib/Either'; +import { AlertSchema } from './alert_schema'; +import { EcsSchema } from './ecs_schema'; +const ISO_DATE_PATTERN = /^d{4}-d{2}-d{2}Td{2}:d{2}:d{2}.d{3}Z$/; +export const IsoDateString = new rt.Type( + 'IsoDateString', + rt.string.is, + (input, context): Either => { + if (typeof input === 'string' && ISO_DATE_PATTERN.test(input)) { + return rt.success(input); + } else { + return rt.failure(input, context); + } + }, + rt.identity +); +export type IsoDateStringC = typeof IsoDateString; +export const schemaUnknown = rt.unknown; +export const schemaUnknownArray = rt.array(rt.unknown); +export const schemaString = rt.string; +export const schemaStringArray = rt.array(schemaString); +export const schemaNumber = rt.number; +export const schemaNumberArray = rt.array(schemaNumber); +export const schemaDate = rt.union([IsoDateString, schemaNumber]); +export const schemaDateArray = rt.array(schemaDate); +export const schemaDateRange = rt.partial({ + gte: schemaDate, + lte: schemaDate, +}); +export const schemaDateRangeArray = rt.array(schemaDateRange); +export const schemaStringOrNumber = rt.union([schemaString, schemaNumber]); +export const schemaStringOrNumberArray = rt.array(schemaStringOrNumber); +export const schemaBoolean = rt.boolean; +export const schemaBooleanArray = rt.array(schemaBoolean); +const schemaGeoPointCoords = rt.type({ + type: schemaString, + coordinates: schemaNumberArray, +}); +const schemaGeoPointString = schemaString; +const schemaGeoPointLatLon = rt.type({ + lat: schemaNumber, + lon: schemaNumber, +}); +const schemaGeoPointLocation = rt.type({ + location: schemaNumberArray, +}); +const schemaGeoPointLocationString = rt.type({ + location: schemaString, +}); +export const schemaGeoPoint = rt.union([ + schemaGeoPointCoords, + schemaGeoPointString, + schemaGeoPointLatLon, + schemaGeoPointLocation, + schemaGeoPointLocationString, +]); +export const schemaGeoPointArray = rt.array(schemaGeoPoint); +// prettier-ignore +const ObservabilityThresholdAlertRequired = rt.type({ +}); +// prettier-ignore +const ObservabilityThresholdAlertOptional = rt.partial({ + 'kibana.alert.context': schemaUnknown, + 'kibana.alert.evaluation.threshold': schemaStringOrNumber, + 'kibana.alert.evaluation.value': schemaStringOrNumber, + 'kibana.alert.evaluation.values': schemaStringOrNumberArray, + 'kibana.alert.group': rt.array( + rt.partial({ + field: schemaStringArray, + value: schemaStringArray, + }) + ), +}); + +// prettier-ignore +export const ObservabilityThresholdAlertSchema = rt.intersection([ObservabilityThresholdAlertRequired, ObservabilityThresholdAlertOptional, AlertSchema, EcsSchema]); +// prettier-ignore +export type ObservabilityThresholdAlert = rt.TypeOf; diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx index 86ae0a54f922..0137953b2313 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping.test.tsx @@ -23,7 +23,8 @@ import { groupingSearchResponse } from '../mocks/grouping_query.mock'; import { useAlertsGroupingState } from '../contexts/alerts_grouping_context'; import { I18nProvider } from '@kbn/i18n-react'; import { - mockFeatureIds, + mockRuleTypeIds, + mockConsumers, mockDate, mockGroupingProps, mockGroupingId, @@ -146,7 +147,8 @@ describe('AlertsGrouping', () => { expect.objectContaining({ params: { aggregations: {}, - featureIds: mockFeatureIds, + ruleTypeIds: mockRuleTypeIds, + consumers: mockConsumers, groupByField: 'kibana.alert.rule.name', filters: [ { diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx index d814d70903a5..5ea010d44214 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping.tsx @@ -66,7 +66,7 @@ const AlertsGroupingInternal = ( const { groupingId, services, - featureIds, + ruleTypeIds, defaultGroupingOptions, defaultFilters, globalFilters, @@ -79,7 +79,7 @@ const AlertsGroupingInternal = ( const { grouping, updateGrouping } = useAlertsGroupingState(groupingId); const { dataView } = useAlertsDataView({ - featureIds, + ruleTypeIds, dataViewsService: dataViews, http, toasts: notifications.toasts, @@ -252,7 +252,7 @@ const typedMemo: (c: T) => T = memo; * * return ( * - * featureIds={[...]} + * ruleTypeIds={[...]} * globalQuery={{ query: ..., language: 'kql' }} * globalFilters={...} * from={...} diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx index 5548c14fcf26..b908b07caf7a 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.test.tsx @@ -55,6 +55,10 @@ const mockGroupingLevelProps: Omit = { describe('AlertsGroupingLevel', () => { let buildEsQuerySpy: jest.SpyInstance; + beforeEach(() => { + jest.clearAllMocks(); + }); + beforeAll(() => { buildEsQuerySpy = jest.spyOn(buildEsQueryModule, 'buildEsQuery'); }); @@ -119,4 +123,58 @@ describe('AlertsGroupingLevel', () => { Object.keys(groupingSearchResponse.aggregations) ); }); + + it('should calls useGetAlertsGroupAggregationsQuery with correct props', () => { + render( + + {() => } + + ); + + expect(mockUseGetAlertsGroupAggregationsQuery.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "enabled": true, + "http": Object { + "get": [MockFunction], + }, + "params": Object { + "aggregations": Object {}, + "consumers": Array [ + "stackAlerts", + ], + "filters": Array [ + Object { + "bool": Object { + "filter": Array [], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + Object { + "range": Object { + "kibana.alert.time_range": Object { + "gte": "2020-07-07T08:20:18.966Z", + "lte": "2020-07-08T08:20:18.966Z", + }, + }, + }, + ], + "groupByField": "selectedGroup", + "pageIndex": 0, + "pageSize": 10, + "ruleTypeIds": Array [ + ".es-query", + ], + }, + "toasts": Object { + "addDanger": [MockFunction], + }, + }, + ], + ] + `); + }); }); diff --git a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx index 7e620276d2e4..02fd5d33e237 100644 --- a/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx +++ b/packages/kbn-alerts-grouping/src/components/alerts_grouping_level.tsx @@ -46,7 +46,8 @@ const DEFAULT_FILTERS: Filter[] = []; const typedMemo: (c: T) => T = memo; export const AlertsGroupingLevel = typedMemo( ({ - featureIds, + ruleTypeIds, + consumers, defaultFilters = DEFAULT_FILTERS, from, getGrouping, @@ -86,7 +87,8 @@ export const AlertsGroupingLevel = typedMemo( const aggregationsQuery = useMemo(() => { return { - featureIds, + ruleTypeIds, + consumers, groupByField: selectedGroup, aggregations: getAggregationsByGroupingField(selectedGroup)?.reduce( (acc, val) => Object.assign(acc, val), @@ -107,12 +109,13 @@ export const AlertsGroupingLevel = typedMemo( pageSize, }; }, [ - featureIds, + consumers, filters, from, getAggregationsByGroupingField, pageIndex, pageSize, + ruleTypeIds, selectedGroup, to, ]); diff --git a/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx b/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx index 925a32fbd9de..510c7c8fdb89 100644 --- a/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx +++ b/packages/kbn-alerts-grouping/src/mocks/grouping_props.mock.tsx @@ -8,12 +8,12 @@ */ import React from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsGroupingProps } from '../types'; export const mockGroupingId = 'test'; -export const mockFeatureIds = [AlertConsumers.STACK_ALERTS]; +export const mockRuleTypeIds = ['.es-query']; +export const mockConsumers = ['stackAlerts']; export const mockDate = { from: '2020-07-07T08:20:18.966Z', @@ -30,7 +30,8 @@ export const mockOptions = [ export const mockGroupingProps: Omit = { ...mockDate, groupingId: mockGroupingId, - featureIds: mockFeatureIds, + ruleTypeIds: mockRuleTypeIds, + consumers: mockConsumers, defaultGroupingOptions: mockOptions, getAggregationsByGroupingField: () => [], getGroupStats: () => [{ title: 'Stat', component: }], diff --git a/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts b/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts index 8820f884928b..486771e70a14 100644 --- a/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts +++ b/packages/kbn-alerts-grouping/src/mocks/grouping_query.mock.ts @@ -11,12 +11,12 @@ export const getQuery = ({ selectedGroup, uniqueValue, timeRange, - featureIds, + ruleTypeIds, }: { selectedGroup: string; uniqueValue: string; timeRange: { from: string; to: string }; - featureIds: string[]; + ruleTypeIds: string[]; }) => ({ _source: false, aggs: { @@ -52,7 +52,7 @@ export const getQuery = ({ }, }, }, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, query: { bool: { filter: [ diff --git a/packages/kbn-alerts-grouping/src/types.ts b/packages/kbn-alerts-grouping/src/types.ts index c6132e94e872..f1eb9ef00fee 100644 --- a/packages/kbn-alerts-grouping/src/types.ts +++ b/packages/kbn-alerts-grouping/src/types.ts @@ -8,7 +8,6 @@ */ import type { Filter, Query } from '@kbn/es-query'; -import { ValidFeatureId } from '@kbn/rule-data-utils'; import type { NotificationsStart } from '@kbn/core-notifications-browser'; import type { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types'; import type { HttpSetup } from '@kbn/core-http-browser'; @@ -63,9 +62,13 @@ export interface AlertsGroupingProps< */ defaultGroupingOptions: GroupOption[]; /** - * The alerting feature ids this grouping covers + * The alerting rule type ids this grouping covers */ - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + /** + * The alerting consumers this grouping covers + */ + consumers?: string[]; /** * Time filter start */ diff --git a/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts index d574aaf9592a..6f362fd34710 100644 --- a/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts +++ b/packages/kbn-alerts-ui-shared/src/action_variables/transforms.test.ts @@ -289,5 +289,6 @@ function getAlertType(actionVariables: ActionVariables): RuleType { producer: ALERTING_FEATURE_ID, minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', }; } diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx index 3c314c62fc28..6c35234b5400 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.test.tsx @@ -10,7 +10,6 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { AlertFilterControls, AlertFilterControlsProps } from './alert_filter_controls'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { DEFAULT_CONTROLS } from './constants'; import { useAlertsDataView } from '../common/hooks/use_alerts_data_view'; import { FilterGroup } from './filter_group'; @@ -56,7 +55,7 @@ const ControlGroupRenderer = (() => ( describe('AlertFilterControls', () => { const props: AlertFilterControlsProps = { - featureIds: [AlertConsumers.STACK_ALERTS], + ruleTypeIds: ['.es-query'], defaultControls: DEFAULT_CONTROLS, dataViewSpec: { id: 'alerts-filters-dv', diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx index e8e7e6385925..f64b02e2ee35 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/alert_filter_controls.tsx @@ -12,7 +12,6 @@ import React, { useCallback, useEffect, useState } from 'react'; import type { Filter } from '@kbn/es-query'; import { EuiFlexItem } from '@elastic/eui'; import type { DataViewSpec, DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { HttpStart } from '@kbn/core-http-browser'; import { NotificationsStart } from '@kbn/core-notifications-browser'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -24,12 +23,12 @@ import { FilterControlConfig } from './types'; export type AlertFilterControlsProps = Omit< ComponentProps, - 'dataViewId' | 'defaultControls' | 'featureIds' | 'Storage' + 'dataViewId' | 'defaultControls' | 'ruleTypeIds' | 'Storage' > & { /** - * The feature ids used to get the correct alert data view(s) + * The rule type ids used to get the correct alert data view(s) */ - featureIds?: AlertConsumers[]; + ruleTypeIds?: string[]; /** * An array of default control configurations */ @@ -57,7 +56,7 @@ export type AlertFilterControlsProps = Omit< * * { const { - featureIds = [AlertConsumers.STACK_ALERTS], + ruleTypeIds = [], defaultControls = DEFAULT_CONTROLS, dataViewSpec, onFiltersChange, @@ -96,7 +95,7 @@ export const AlertFilterControls = (props: AlertFilterControlsProps) => { } = props; const [loadingPageFilters, setLoadingPageFilters] = useState(true); const { dataView, isLoading: isLoadingDataView } = useAlertsDataView({ - featureIds, + ruleTypeIds, dataViewsService: dataViews, http, toasts, @@ -156,7 +155,7 @@ export const AlertFilterControls = (props: AlertFilterControlsProps) => { > = (props) => { ) => { const { - featureIds, dataViewId, onFiltersChange, timeRange, @@ -59,6 +58,7 @@ export const FilterGroup = (props: PropsWithChildren) => { maxControls = Infinity, ControlGroupRenderer, Storage, + ruleTypeIds, storageKey, } = props; @@ -80,8 +80,8 @@ export const FilterGroup = (props: PropsWithChildren) => { const [controlGroup, setControlGroup] = useState(); const localStoragePageFilterKey = useMemo( - () => storageKey ?? `${featureIds.join(',')}.${spaceId}.${URL_PARAM_KEY}`, - [featureIds, spaceId, storageKey] + () => storageKey ?? `${ruleTypeIds.join(',')}.${spaceId}.${URL_PARAM_KEY}`, + [ruleTypeIds, spaceId, storageKey] ); const currentFiltersRef = useRef(); diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/hooks/use_filters_sync_to_local_storage.test.ts b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/hooks/use_filters_sync_to_local_storage.test.ts index cb7a9b7f3c5c..dafc4e16c899 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/hooks/use_filters_sync_to_local_storage.test.ts +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/hooks/use_filters_sync_to_local_storage.test.ts @@ -8,7 +8,7 @@ */ import type { ControlGroupRuntimeState } from '@kbn/controls-plugin/public'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, act, renderHook } from '@testing-library/react'; import { useControlGroupSyncToLocalStorage } from './use_control_group_sync_to_local_storage'; import { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -34,77 +34,97 @@ describe('Filters Sync to Local Storage', () => { writable: true, }); }); + afterEach(() => { mockLocalStorage = {}; }); - it('should not be undefined if localStorage has initial value', () => { + + it('should not be undefined if localStorage has initial value', async () => { global.localStorage.setItem(TEST_STORAGE_KEY, JSON.stringify(DEFAULT_STORED_VALUE)); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useControlGroupSyncToLocalStorage({ Storage, storageKey: TEST_STORAGE_KEY, shouldSync: true, }) ); - waitForNextUpdate(); - expect(result.current.controlGroupState).toMatchObject(DEFAULT_STORED_VALUE); + await waitFor(() => + expect(result.current.controlGroupState).toMatchObject(DEFAULT_STORED_VALUE) + ); }); - it('should be undefined if localstorage as NO initial value', () => { - const { result, waitForNextUpdate } = renderHook(() => + + it('should be undefined if localstorage as NO initial value', async () => { + const { result } = renderHook(() => useControlGroupSyncToLocalStorage({ Storage, storageKey: TEST_STORAGE_KEY, shouldSync: true, }) ); - waitForNextUpdate(); - expect(result.current.controlGroupState).toBeUndefined(); - expect(result.current.setControlGroupState).toBeTruthy(); + await waitFor(() => + expect(result.current).toEqual( + expect.objectContaining({ + controlGroupState: undefined, + setControlGroupState: expect.any(Function), + }) + ) + ); }); - it('should be update values to local storage when sync is ON', () => { - const { result, waitFor } = renderHook(() => + it('should be update values to local storage when sync is ON', async () => { + const { result } = renderHook(() => useControlGroupSyncToLocalStorage({ Storage, storageKey: TEST_STORAGE_KEY, shouldSync: true, }) ); - waitFor(() => { + await waitFor(() => { expect(result.current.controlGroupState).toBeUndefined(); expect(result.current.setControlGroupState).toBeTruthy(); }); - result.current.setControlGroupState(DEFAULT_STORED_VALUE); - waitFor(() => { + act(() => { + result.current.setControlGroupState(DEFAULT_STORED_VALUE); + }); + await waitFor(() => { expect(result.current.controlGroupState).toMatchObject(DEFAULT_STORED_VALUE); expect(global.localStorage.getItem(TEST_STORAGE_KEY)).toBe( JSON.stringify(DEFAULT_STORED_VALUE) ); }); }); - it('should not update values to local storage when sync is OFF', () => { - const { waitFor, result, rerender } = renderHook(() => - useControlGroupSyncToLocalStorage({ - Storage, - storageKey: TEST_STORAGE_KEY, - shouldSync: true, - }) - ); + it('should not update values to local storage when sync is OFF', async () => { + const initialProps = { + Storage, + storageKey: TEST_STORAGE_KEY, + shouldSync: true, + }; + + const { result, rerender } = renderHook(useControlGroupSyncToLocalStorage, { + initialProps, + }); // Sync is ON - waitFor(() => { + await waitFor(() => { expect(result.current.controlGroupState).toBeUndefined(); expect(result.current.setControlGroupState).toBeTruthy(); }); - result.current.setControlGroupState(DEFAULT_STORED_VALUE); - waitFor(() => { + act(() => { + result.current.setControlGroupState(DEFAULT_STORED_VALUE); + }); + + await waitFor(() => { expect(result.current.controlGroupState).toMatchObject(DEFAULT_STORED_VALUE); }); // Sync is OFF - rerender({ storageKey: TEST_STORAGE_KEY, shouldSync: false }); - result.current.setControlGroupState(ANOTHER_SAMPLE_VALUE); - waitFor(() => { + rerender({ ...initialProps, shouldSync: false }); + + act(() => { + result.current.setControlGroupState(ANOTHER_SAMPLE_VALUE); + }); + + await waitFor(() => { expect(result.current.controlGroupState).toMatchObject(ANOTHER_SAMPLE_VALUE); // old value expect(global.localStorage.getItem(TEST_STORAGE_KEY)).toBe( diff --git a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts index 19a76c76ff6f..ed625897a418 100644 --- a/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts +++ b/packages/kbn-alerts-ui-shared/src/alert_filter_controls/types.ts @@ -15,7 +15,6 @@ import type { ControlGroupRendererApi, } from '@kbn/controls-plugin/public'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; -import { AlertConsumers } from '@kbn/rule-data-utils'; export type FilterUrlFormat = Record< string, @@ -46,7 +45,7 @@ export interface FilterGroupProps extends Pick ( - - - - - - first - - - - - - - - - - - middle - - - - - - - - - - - - - - last - - - - - - - - - -`; - -exports[`TableHeader without time column renders correctly 1`] = ` - - - - - first - - - - - - - - - - - middle - - - - - - - - - - - - - - last - - - - - - - - - -`; diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx deleted file mode 100644 index 6640164d76d5..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/helpers.tsx +++ /dev/null @@ -1,86 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { i18n } from '@kbn/i18n'; -import type { DataView } from '@kbn/data-views-plugin/public'; - -export interface ColumnProps { - name: string; - displayName: string; - isSortable: boolean; - isRemoveable: boolean; - colLeftIdx: number; - colRightIdx: number; -} - -/** - * Returns properties necessary to display the time column - * If it's an DataView with timefield, the time column is - * prepended, not moveable and removeable - * @param timeFieldName - */ -export function getTimeColumn(timeFieldName: string): ColumnProps { - return { - name: timeFieldName, - displayName: timeFieldName, - isSortable: true, - isRemoveable: false, - colLeftIdx: -1, - colRightIdx: -1, - }; -} -/** - * A given array of column names returns an array of properties - * necessary to display the columns. If the given dataView - * has a timefield, a time column is prepended - * @param columns - * @param dataView - * @param hideTimeField - * @param isShortDots - */ -export function getDisplayedColumns( - columns: string[], - dataView: DataView, - hideTimeField: boolean, - isShortDots: boolean -) { - if (!Array.isArray(columns) || typeof dataView !== 'object' || !dataView.getFieldByName) { - return []; - } - - const columnProps = - columns.length === 0 - ? [ - { - name: '__document__', - displayName: i18n.translate('discover.docTable.tableHeader.documentHeader', { - defaultMessage: 'Document', - }), - isSortable: false, - isRemoveable: false, - colLeftIdx: -1, - colRightIdx: -1, - }, - ] - : columns.map((column, idx) => { - const field = dataView.getFieldByName(column); - return { - name: column, - displayName: field?.displayName ?? column, - isSortable: !!(field && field.sortable), - isRemoveable: column !== '_source' || columns.length > 1, - colLeftIdx: idx - 1 < 0 ? -1 : idx - 1, - colRightIdx: idx + 1 >= columns.length ? -1 : idx + 1, - }; - }); - - return !hideTimeField && dataView.timeFieldName - ? [getTimeColumn(dataView.timeFieldName), ...columnProps] - : columnProps; -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx deleted file mode 100644 index 7aa398844438..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.test.tsx +++ /dev/null @@ -1,223 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { TableHeader } from './table_header'; -import { findTestSubject } from '@elastic/eui/lib/test'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { DOC_HIDE_TIME_COLUMN_SETTING } from '@kbn/discover-utils'; -import { FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common'; - -const defaultUiSettings = { - get: (key: string) => { - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { - return false; - } else if (key === FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE) { - return false; - } - }, -}; - -function getMockDataView() { - return { - id: 'test', - title: 'Test', - timeFieldName: 'time', - fields: [], - isTimeNanosBased: () => false, - getFieldByName: (name: string) => { - if (name === 'test1') { - return { - name, - displayName: name, - type: 'string', - aggregatable: false, - searchable: true, - sortable: true, - } as DataViewField; - } else { - return { - name, - displayName: name, - type: 'string', - aggregatable: false, - searchable: true, - sortable: false, - } as DataViewField; - } - }, - } as unknown as DataView; -} - -function getMockProps(props = {}) { - const defaultProps = { - dataView: getMockDataView(), - hideTimeColumn: false, - columns: ['first', 'middle', 'last'], - defaultSortOrder: 'desc', - sortOrder: [['time', 'asc']] as SortOrder[], - isShortDots: true, - onRemoveColumn: jest.fn(), - onChangeSortOrder: jest.fn(), - onMoveColumn: jest.fn(), - onPageNext: jest.fn(), - onPagePrevious: jest.fn(), - }; - - return Object.assign({}, defaultProps, props); -} - -describe('TableHeader with time column', () => { - const props = getMockProps(); - - const wrapper = mountWithIntl( - - - - - -
-
- ); - - test('renders correctly', () => { - const docTableHeader = findTestSubject(wrapper, 'docTableHeader'); - expect(docTableHeader.getDOMNode()).toMatchSnapshot(); - }); - - test('time column is sortable with button, cycling sort direction', () => { - findTestSubject(wrapper, 'docTableHeaderFieldSort_time').simulate('click'); - expect(props.onChangeSortOrder).toHaveBeenCalledWith([['time', 'desc']]); - }); - - test('time column is not removeable, no button displayed', () => { - const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-time'); - expect(removeButton.length).toBe(0); - }); - - test('time column is not moveable, no button displayed', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-time'); - expect(moveButtonLeft.length).toBe(0); - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-time'); - expect(moveButtonRight.length).toBe(0); - }); - - test('first column is removeable', () => { - const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-first'); - expect(removeButton.length).toBe(1); - removeButton.simulate('click'); - expect(props.onRemoveColumn).toHaveBeenCalledWith('first'); - }); - - test('first column is not moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-first'); - expect(moveButtonLeft.length).toBe(0); - }); - - test('first column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-first'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('first', 1); - }); - - test('middle column is moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-middle'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 0); - }); - - test('middle column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-middle'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 2); - }); - - test('last column moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-last'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('last', 1); - }); -}); - -describe('TableHeader without time column', () => { - const props = getMockProps({ hideTimeColumn: true }); - - const wrapper = mountWithIntl( - { - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { - return true; - } - }, - }, - }} - > - - - - -
-
- ); - - test('renders correctly', () => { - const docTableHeader = findTestSubject(wrapper, 'docTableHeader'); - expect(docTableHeader.getDOMNode()).toMatchSnapshot(); - }); - - test('first column is removeable', () => { - const removeButton = findTestSubject(wrapper, 'docTableRemoveHeader-first'); - expect(removeButton.length).toBe(1); - removeButton.simulate('click'); - expect(props.onRemoveColumn).toHaveBeenCalledWith('first'); - }); - - test('first column is not moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-first'); - expect(moveButtonLeft.length).toBe(0); - }); - - test('first column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-first'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('first', 1); - }); - - test('middle column is moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-middle'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 0); - }); - - test('middle column is moveable to the right', () => { - const moveButtonRight = findTestSubject(wrapper, 'docTableMoveRightHeader-middle'); - expect(moveButtonRight.length).toBe(1); - moveButtonRight.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('middle', 2); - }); - - test('last column moveable to the left', () => { - const moveButtonLeft = findTestSubject(wrapper, 'docTableMoveLeftHeader-last'); - expect(moveButtonLeft.length).toBe(1); - moveButtonLeft.simulate('click'); - expect(props.onMoveColumn).toHaveBeenCalledWith('last', 1); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx deleted file mode 100644 index 04583c893841..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header.tsx +++ /dev/null @@ -1,71 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { useMemo } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { FORMATS_UI_SETTINGS } from '@kbn/field-formats-plugin/common'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { DOC_HIDE_TIME_COLUMN_SETTING, SORT_DEFAULT_ORDER_SETTING } from '@kbn/discover-utils'; -import { TableHeaderColumn } from './table_header_column'; -import { getDisplayedColumns } from './helpers'; -import { getDefaultSort } from '../../../../utils/sorting'; -import { useDiscoverServices } from '../../../../hooks/use_discover_services'; - -interface Props { - columns: string[]; - dataView: DataView; - onChangeSortOrder?: (sortOrder: SortOrder[]) => void; - onMoveColumn?: (name: string, index: number) => void; - onRemoveColumn?: (name: string) => void; - sortOrder: SortOrder[]; -} - -export function TableHeader({ - columns, - dataView, - onChangeSortOrder, - onMoveColumn, - onRemoveColumn, - sortOrder, -}: Props) { - const { uiSettings } = useDiscoverServices(); - const [defaultSortOrder, hideTimeColumn, isShortDots] = useMemo( - () => [ - uiSettings.get(SORT_DEFAULT_ORDER_SETTING, 'desc'), - uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false), - uiSettings.get(FORMATS_UI_SETTINGS.SHORT_DOTS_ENABLE), - ], - [uiSettings] - ); - const displayedColumns = getDisplayedColumns(columns, dataView, hideTimeColumn, isShortDots); - - return ( - - - {displayedColumns.map((col, index) => { - return ( - - ); - })} - - ); -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx b/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx deleted file mode 100644 index cbb1cb598f2c..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_header/table_header_column.tsx +++ /dev/null @@ -1,234 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { i18n } from '@kbn/i18n'; -import { EuiButtonIcon, EuiToolTip, EuiIconTip } from '@elastic/eui'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { DocViewTableScoreSortWarning } from './score_sort_warning'; - -interface Props { - colLeftIdx: number; // idx of the column to the left, -1 if moving is not possible - colRightIdx: number; // idx of the column to the right, -1 if moving is not possible - displayName?: string; - isRemoveable: boolean; - isSortable: boolean; - isTimeColumn: boolean; - customLabel?: string; - name: string; - onChangeSortOrder?: (sortOrder: SortOrder[]) => void; - onMoveColumn?: (name: string, idx: number) => void; - onRemoveColumn?: (name: string) => void; - sortOrder: SortOrder[]; -} - -interface IconProps { - iconType: string; - color: 'primary' | 'text'; -} - -interface IconButtonProps { - active: boolean; - ariaLabel: string; - className: string; - iconProps: IconProps; - onClick: () => void | undefined; - testSubject: string; - tooltip: string; -} - -const sortDirectionToIcon: Record = { - desc: { iconType: 'sortDown', color: 'primary' }, - asc: { iconType: 'sortUp', color: 'primary' }, - '': { iconType: 'sortable', color: 'text' }, -}; - -const ICON_BUTTON_STYLE = { width: 12, height: 12 }; - -export function TableHeaderColumn({ - colLeftIdx, - colRightIdx, - displayName, - isRemoveable, - isSortable, - isTimeColumn, - customLabel, - name, - onChangeSortOrder, - onMoveColumn, - onRemoveColumn, - sortOrder, -}: Props) { - const [, sortDirection = ''] = sortOrder.find((sortPair) => name === sortPair[0]) || []; - const curSortWithoutCol = sortOrder.filter((pair) => pair[0] !== name); - const curColSort = sortOrder.find((pair) => pair[0] === name); - const curColSortDir = (curColSort && curColSort[1]) || ''; - - const fieldName = customLabel ?? displayName; - const timeAriaLabel = i18n.translate( - 'discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel', - { - defaultMessage: '{timeFieldName} - this field represents the time that events occurred.', - values: { timeFieldName: fieldName }, - } - ); - const timeTooltip = i18n.translate('discover.docTable.tableHeader.timeFieldIconTooltip', { - defaultMessage: 'This field represents the time that events occurred.', - }); - - // If this is the _score column, and _score is not one of the columns inside the sort, show a - // warning that the _score will not be retrieved from Elasticsearch - const showScoreSortWarning = name === '_score' && !curColSort; - - const handleChangeSortOrder = () => { - if (!onChangeSortOrder) return; - - // Cycle goes Unsorted -> Asc -> Desc -> Unsorted - if (curColSort === undefined) { - onChangeSortOrder([...curSortWithoutCol, [name, 'asc']]); - } else if (curColSortDir === 'asc') { - onChangeSortOrder([...curSortWithoutCol, [name, 'desc']]); - } else if (curColSortDir === 'desc' && curSortWithoutCol.length === 0) { - // If we're at the end of the cycle and this is the only existing sort, we switch - // back to ascending sort instead of removing it. - onChangeSortOrder([[name, 'asc']]); - } else { - onChangeSortOrder(curSortWithoutCol); - } - }; - - const getSortButtonAriaLabel = () => { - const sortAscendingMessage = i18n.translate( - 'discover.docTable.tableHeader.sortByColumnAscendingAriaLabel', - { - defaultMessage: 'Sort {columnName} ascending', - values: { columnName: name }, - } - ); - const sortDescendingMessage = i18n.translate( - 'discover.docTable.tableHeader.sortByColumnDescendingAriaLabel', - { - defaultMessage: 'Sort {columnName} descending', - values: { columnName: name }, - } - ); - const stopSortingMessage = i18n.translate( - 'discover.docTable.tableHeader.sortByColumnUnsortedAriaLabel', - { - defaultMessage: 'Stop sorting on {columnName}', - values: { columnName: name }, - } - ); - - if (curColSort === undefined) { - return sortAscendingMessage; - } else if (sortDirection === 'asc') { - return sortDescendingMessage; - } else if (sortDirection === 'desc' && curSortWithoutCol.length === 0) { - return sortAscendingMessage; - } else { - return stopSortingMessage; - } - }; - - // action buttons displayed on the right side of the column name - const buttons: IconButtonProps[] = [ - // Sort Button - { - active: isSortable && typeof onChangeSortOrder === 'function', - ariaLabel: getSortButtonAriaLabel(), - className: !sortDirection ? 'kbnDocTableHeader__sortChange' : '', - iconProps: sortDirectionToIcon[sortDirection], - onClick: handleChangeSortOrder, - testSubject: `docTableHeaderFieldSort_${name}`, - tooltip: getSortButtonAriaLabel(), - }, - // Remove Button - { - active: isRemoveable && typeof onRemoveColumn === 'function', - ariaLabel: i18n.translate('discover.docTable.tableHeader.removeColumnButtonAriaLabel', { - defaultMessage: 'Remove {columnName} column', - values: { columnName: name }, - }), - className: 'kbnDocTableHeader__move', - iconProps: { iconType: 'cross', color: 'text' }, - onClick: () => onRemoveColumn && onRemoveColumn(name), - testSubject: `docTableRemoveHeader-${name}`, - tooltip: i18n.translate('discover.docTable.tableHeader.removeColumnButtonTooltip', { - defaultMessage: 'Remove Column', - }), - }, - // Move Left Button - { - active: colLeftIdx >= 0 && typeof onMoveColumn === 'function', - ariaLabel: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonAriaLabel', { - defaultMessage: 'Move {columnName} column to the left', - values: { columnName: name }, - }), - className: 'kbnDocTableHeader__move', - iconProps: { iconType: 'sortLeft', color: 'text' }, - onClick: () => onMoveColumn && onMoveColumn(name, colLeftIdx), - testSubject: `docTableMoveLeftHeader-${name}`, - tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnLeftButtonTooltip', { - defaultMessage: 'Move column to the left', - }), - }, - // Move Right Button - { - active: colRightIdx >= 0 && typeof onMoveColumn === 'function', - ariaLabel: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonAriaLabel', { - defaultMessage: 'Move {columnName} column to the right', - values: { columnName: name }, - }), - className: 'kbnDocTableHeader__move', - iconProps: { iconType: 'sortRight', color: 'text' }, - onClick: () => onMoveColumn && onMoveColumn(name, colRightIdx), - testSubject: `docTableMoveRightHeader-${name}`, - tooltip: i18n.translate('discover.docTable.tableHeader.moveColumnRightButtonTooltip', { - defaultMessage: 'Move column to the right', - }), - }, - ]; - - return ( - - - {showScoreSortWarning && } - {fieldName} - {isTimeColumn && ( - - )} - {buttons - .filter((button) => button.active) - .map((button, idx) => ( - - - - ))} - - - ); -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx deleted file mode 100644 index 3452da4abc57..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row.test.tsx +++ /dev/null @@ -1,141 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mountWithIntl, findTestSubject } from '@kbn/test-jest-helpers'; -import { TableRow, TableRowProps } from './table_row'; -import { createFilterManagerMock } from '@kbn/data-plugin/public/query/filter_manager/filter_manager.mock'; -import { dataViewWithTimefieldMock } from '../../../__mocks__/data_view_with_timefield'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { discoverServiceMock } from '../../../__mocks__/services'; - -import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '@kbn/discover-utils'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import type { EsHitRecord } from '@kbn/discover-utils/types'; - -jest.mock('../utils/row_formatter', () => { - const originalModule = jest.requireActual('../utils/row_formatter'); - return { - ...originalModule, - formatRow: () => { - return mocked_document_cell; - }, - }; -}); - -const mountComponent = (props: TableRowProps) => { - return mountWithIntl( - { - if (key === DOC_HIDE_TIME_COLUMN_SETTING) { - return true; - } else if (key === MAX_DOC_FIELDS_DISPLAYED) { - return 100; - } - }, - }, - }} - > - - - - -
-
- ); -}; - -const mockHit = { - _index: 'mock_index', - _id: '1', - _score: 1, - _type: '_doc', - fields: [ - { - timestamp: '2020-20-01T12:12:12.123', - }, - ], - _source: { message: 'mock_message', bytes: 20 }, -} as unknown as EsHitRecord; - -const mockFilterManager = createFilterManagerMock(); - -describe('Doc table row component', () => { - const mockInlineFilter = jest.fn(); - const defaultProps = { - columns: ['_source'], - filter: mockInlineFilter, - dataView: dataViewWithTimefieldMock, - row: buildDataTableRecord(mockHit, dataViewWithTimefieldMock), - useNewFieldsApi: true, - filterManager: mockFilterManager, - addBasePath: (path: string) => path, - } as unknown as TableRowProps; - - it('should render __document__ column', () => { - const component = mountComponent({ ...defaultProps, columns: [] }); - const docTableField = findTestSubject(component, 'docTableField'); - expect(docTableField.first().text()).toBe('mocked_document_cell'); - }); - - it('should render message, _index and bytes fields', () => { - const component = mountComponent({ ...defaultProps, columns: ['message', '_index', 'bytes'] }); - - const fields = findTestSubject(component, 'docTableField'); - expect(fields.first().text()).toBe('mock_message'); - expect(fields.last().text()).toBe('20'); - expect(fields.length).toBe(3); - }); - - it('should apply filter when pressed', () => { - const component = mountComponent({ ...defaultProps, columns: ['bytes'] }); - - const fields = findTestSubject(component, 'docTableField'); - expect(fields.first().text()).toBe('20'); - - const filterInButton = findTestSubject(component, 'docTableCellFilter'); - filterInButton.simulate('click'); - expect(mockInlineFilter).toHaveBeenCalledWith( - dataViewWithTimefieldMock.getFieldByName('bytes'), - 20, - '+' - ); - }); - - describe('details row', () => { - it('should be empty by default', () => { - const component = mountComponent(defaultProps); - expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeFalsy(); - }); - - it('should expand the detail row when the toggle arrow is clicked', () => { - const component = mountComponent(defaultProps); - const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn'); - - expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeFalsy(); - toggleButton.simulate('click'); - expect(findTestSubject(component, 'docViewerRowDetailsTitle').exists()).toBeTruthy(); - }); - - it('should hide the single/surrounding views for ES|QL mode', () => { - const props = { - ...defaultProps, - isEsqlMode: true, - }; - const component = mountComponent(props); - const toggleButton = findTestSubject(component, 'docTableExpandToggleColumn'); - toggleButton.simulate('click'); - expect(findTestSubject(component, 'docViewerRowDetailsTitle').text()).toBe('Expanded result'); - expect(findTestSubject(component, 'docTableRowAction').length).toBeFalsy(); - }); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/components/table_row.tsx b/src/plugins/discover/public/components/doc_table/components/table_row.tsx deleted file mode 100644 index 40a3a81499a1..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row.tsx +++ /dev/null @@ -1,239 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment, useCallback, useMemo, useState } from 'react'; -import classNames from 'classnames'; -import { i18n } from '@kbn/i18n'; -import { EuiButtonEmpty, EuiIcon } from '@elastic/eui'; -import { DataView } from '@kbn/data-views-plugin/public'; -import { Filter } from '@kbn/es-query'; -import type { - DataTableRecord, - EsHitRecord, - ShouldShowFieldInTableHandler, -} from '@kbn/discover-utils/types'; -import { formatFieldValue } from '@kbn/discover-utils'; -import { DOC_HIDE_TIME_COLUMN_SETTING, MAX_DOC_FIELDS_DISPLAYED } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { UnifiedDocViewer } from '@kbn/unified-doc-viewer-plugin/public'; -import { TableCell } from './table_row/table_cell'; -import { formatRow, formatTopLevelObject } from '../utils/row_formatter'; -import { TableRowDetails } from './table_row_details'; -import { useDiscoverServices } from '../../../hooks/use_discover_services'; - -export type DocTableRow = EsHitRecord & { - isAnchor?: boolean; -}; - -export interface TableRowProps { - columns: string[]; - filter?: DocViewFilterFn; - filters?: Filter[]; - isEsqlMode?: boolean; - savedSearchId?: string; - row: DataTableRecord; - rows: DataTableRecord[]; - dataView: DataView; - useNewFieldsApi: boolean; - shouldShowFieldHandler: ShouldShowFieldInTableHandler; - onAddColumn?: (column: string) => void; - onRemoveColumn?: (column: string) => void; -} - -export const TableRow = ({ - filters, - isEsqlMode, - columns, - filter, - savedSearchId, - row, - rows, - dataView, - useNewFieldsApi, - shouldShowFieldHandler, - onAddColumn, - onRemoveColumn, -}: TableRowProps) => { - const { uiSettings, fieldFormats } = useDiscoverServices(); - const [maxEntries, hideTimeColumn] = useMemo( - () => [ - uiSettings.get(MAX_DOC_FIELDS_DISPLAYED), - uiSettings.get(DOC_HIDE_TIME_COLUMN_SETTING, false), - ], - [uiSettings] - ); - const [open, setOpen] = useState(false); - const docTableRowClassName = classNames('kbnDocTable__row', { - 'kbnDocTable__row--highlight': row.isAnchor, - }); - const anchorDocTableRowSubj = row.isAnchor ? ' docTableAnchorRow' : ''; - - const mapping = useMemo(() => dataView.fields.getByName, [dataView]); - - // toggle display of the rows details, a full list of the fields from each row - const toggleRow = () => setOpen((prevOpen) => !prevOpen); - - /** - * Fill an element with the value of a field - */ - const displayField = (fieldName: string) => { - // If we're formatting the _source column, don't use the regular field formatter, - // but our Discover mechanism to format a hit in a better human-readable way. - if (fieldName === '_source') { - return formatRow(row, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); - } - - const formattedField = formatFieldValue( - row.flattened[fieldName], - row.raw, - fieldFormats, - dataView, - mapping(fieldName) - ); - - return ( - // formatFieldValue always returns sanitized HTML - // eslint-disable-next-line react/no-danger -
- ); - }; - const inlineFilter = useCallback( - (column: string, type: '+' | '-') => { - const field = dataView.fields.getByName(column); - filter?.(field!, row.flattened[column], type); - }, - [filter, dataView.fields, row.flattened] - ); - - const rowCells = [ - - - {open ? ( - - ) : ( - - )} - - , - ]; - - if (dataView.timeFieldName && !hideTimeColumn) { - rowCells.push( - - ); - } - - if (columns.length === 0 && useNewFieldsApi) { - const formatted = formatRow(row, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); - - rowCells.push( - - ); - } else { - columns.forEach(function (column: string, index) { - const cellKey = `${column}-${index}`; - if (useNewFieldsApi && !mapping(column) && row.raw.fields && !row.raw.fields[column]) { - const innerColumns = Object.fromEntries( - Object.entries(row.raw.fields).filter(([key]) => { - return key.indexOf(`${column}.`) === 0; - }) - ); - - rowCells.push( - - ); - } else { - // Check whether the field is defined as filterable in the mapping and does - // NOT have ignored values in it to determine whether we want to allow filtering. - // We should improve this and show a helpful tooltip why the filter buttons are not - // there/disabled when there are ignored values. - const isFilterable = Boolean( - mapping(column)?.filterable && - typeof filter === 'function' && - !row.raw._ignored?.includes(column) - ); - rowCells.push( - - ); - } - }); - } - - return ( - - - {rowCells} - - - {open && ( - - - - )} - - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap b/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap deleted file mode 100644 index b4f03267ec81..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/__snapshots__/table_cell.test.tsx.snap +++ /dev/null @@ -1,369 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Doc table cell component renders a cell with filter buttons if it is filterable 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={false} - timefield={true} -> - - - formatted content - - - - - - - - - - , - "ctr": 2, - "insertionPoint": undefined, - "isSpeedy": false, - "key": "css", - "nonce": undefined, - "prepend": undefined, - "tags": Array [ - , - , - ], - }, - } - } - isStringTag={true} - serialized={ - Object { - "map": undefined, - "name": "jcaat8-euiToolTipAnchor-inlineBlock", - "next": undefined, - "styles": "*[disabled]{pointer-events:none;};label:euiToolTipAnchor;;;display:inline-block;label:inlineBlock;;;", - "toString": [Function], - } - } - /> - - - - - - - - - - - - - , - "ctr": 2, - "insertionPoint": undefined, - "isSpeedy": false, - "key": "css", - "nonce": undefined, - "prepend": undefined, - "tags": Array [ - , - , - ], - }, - } - } - isStringTag={true} - serialized={ - Object { - "map": undefined, - "name": "jcaat8-euiToolTipAnchor-inlineBlock", - "next": undefined, - "styles": "*[disabled]{pointer-events:none;};label:euiToolTipAnchor;;;display:inline-block;label:inlineBlock;;;", - "toString": [Function], - } - } - /> - - - - - - - - - - -`; - -exports[`Doc table cell component renders a cell without filter buttons if it is not filterable 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={false} - timefield={true} -> - - - formatted content - - - - -`; - -exports[`Doc table cell component renders a field that is neither a timefield or sourcefield 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={false} - timefield={false} -> - - - formatted content - - - - -`; - -exports[`Doc table cell component renders a sourcefield 1`] = ` - - formatted content - - } - inlineFilter={[Function]} - sourcefield={true} - timefield={false} -> - - - formatted content - - - - -`; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_cell.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_cell.scss deleted file mode 100644 index 2e643c195208..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_cell.scss +++ /dev/null @@ -1,47 +0,0 @@ -.kbnDocTableCell__dataField { - white-space: pre-wrap; -} - -.kbnDocTableCell__toggleDetails { - padding: $euiSizeXS 0 0 0 !important; -} - -/** - * Fixes time column width in Firefox after toggle display of the rows details. - * Described issue - https://github.com/elastic/kibana/pull/104361#issuecomment-894271241 - */ -.kbnDocTableCell--extraWidth { - width: 1%; -} - -.kbnDocTableCell__filter { - position: absolute; - white-space: nowrap; - right: 0; -} - -.kbnDocTableCell__filterButton { - font-size: $euiFontSizeXS; - padding: $euiSizeXS; -} - -/** - * 1. Align icon with text in cell. - * 2. Use opacity to make this element accessible to screen readers and keyboard. - * 3. Show on focus to enable keyboard accessibility. - */ - -.kbnDocTableRowFilterButton { - appearance: none; - background-color: $euiColorEmptyShade; - border: none; - padding: 0 $euiSizeXS; - font-size: $euiFontSizeS; - line-height: 1; /* 1 */ - display: inline-block; - opacity: 0; /* 2 */ - - &:focus { - opacity: 1; /* 3 */ - } -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_details.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_details.scss deleted file mode 100644 index cc6ccfe9fd29..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_details.scss +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 1. Visually align the actions with the tabs. We can improve this by using flexbox instead, at a later point. - */ -.kbnDocTableDetails__actions { - float: right; - padding-top: $euiSizeS; /* 1 */ -} - -// Overwrite the border on the bootstrap table -.kbnDocTableDetails__row { - - > td { - // Offsets negative margins from an inner flex group - padding: $euiSizeL !important; - - tr:hover td { - background: tintOrShade($euiColorLightestShade, 50%, 20%); - } - } - - td { - border-top: none !important; - } -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_index.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_index.scss deleted file mode 100644 index c7ccdaa39ff6..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'cell'; -@import 'details'; -@import 'open'; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/_open.scss b/src/plugins/discover/public/components/doc_table/components/table_row/_open.scss deleted file mode 100644 index 659481e0968b..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/_open.scss +++ /dev/null @@ -1,14 +0,0 @@ -/** - * 1. When switching between open and closed, the toggle changes size - * slightly which is a problem because it forces the entire table to - * re-render which is SLOW. - */ - -.kbnDocTableOpen__button { - appearance: none; - background-color: transparent; - padding: 0; - border: none; - width: 14px; /* 1 */ - height: 14px; -} diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.test.tsx b/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.test.tsx deleted file mode 100644 index ed8d05d87949..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.test.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mount } from 'enzyme'; -import { CellProps, TableCell } from './table_cell'; - -const mountComponent = (props: Omit) => { - return mount( {}} />); -}; - -describe('Doc table cell component', () => { - test('renders a cell without filter buttons if it is not filterable', () => { - const component = mountComponent({ - filterable: false, - column: 'foo', - timefield: true, - sourcefield: false, - formatted: formatted content, - }); - expect(component).toMatchSnapshot(); - }); - - it('renders a cell with filter buttons if it is filterable', () => { - expect( - mountComponent({ - filterable: true, - column: 'foo', - timefield: true, - sourcefield: false, - formatted: formatted content, - }) - ).toMatchSnapshot(); - }); - - it('renders a sourcefield', () => { - expect( - mountComponent({ - filterable: false, - column: 'foo', - timefield: false, - sourcefield: true, - formatted: formatted content, - }) - ).toMatchSnapshot(); - }); - - it('renders a field that is neither a timefield or sourcefield', () => { - expect( - mountComponent({ - filterable: false, - column: 'foo', - timefield: false, - sourcefield: false, - formatted: formatted content, - }) - ).toMatchSnapshot(); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.tsx b/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.tsx deleted file mode 100644 index 83f60dd50587..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell.tsx +++ /dev/null @@ -1,43 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import classNames from 'classnames'; -import { TableCellActions } from './table_cell_actions'; -export interface CellProps { - timefield: boolean; - sourcefield?: boolean; - formatted: JSX.Element; - filterable: boolean; - column: string; - inlineFilter: (column: string, type: '+' | '-') => void; -} - -export const TableCell = (props: CellProps) => { - const classes = classNames({ - ['eui-textNoWrap kbnDocTableCell--extraWidth']: props.timefield, - ['eui-textBreakAll eui-textBreakWord']: props.sourcefield, - ['kbnDocTableCell__dataField eui-textBreakAll eui-textBreakWord']: - !props.timefield && !props.sourcefield, - }); - - const handleFilterFor = () => props.inlineFilter(props.column, '+'); - const handleFilterOut = () => props.inlineFilter(props.column, '-'); - - return ( - - {props.formatted} - {props.filterable ? ( - - ) : ( - - )} - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell_actions.tsx b/src/plugins/discover/public/components/doc_table/components/table_row/table_cell_actions.tsx deleted file mode 100644 index cc096bd1cafd..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row/table_cell_actions.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiIcon, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -interface TableCellActionsProps { - handleFilterFor: () => void; - handleFilterOut: () => void; -} - -export const TableCellActions = ({ handleFilterFor, handleFilterOut }: TableCellActionsProps) => { - return ( - - - - - - - - - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx b/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx deleted file mode 100644 index eefb0f638935..000000000000 --- a/src/plugins/discover/public/components/doc_table/components/table_row_details.tsx +++ /dev/null @@ -1,127 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiButtonEmpty, EuiTitle } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import type { Filter } from '@kbn/es-query'; -import { useNavigationProps } from '../../../hooks/use_navigation_props'; - -interface TableRowDetailsProps { - children: JSX.Element; - colLength: number; - rowIndex: string | undefined; - rowId: string | undefined; - columns: string[]; - isTimeBased: boolean; - dataView: DataView; - filters?: Filter[]; - savedSearchId?: string; - isEsqlMode?: boolean; -} - -export const TableRowDetails = ({ - colLength, - isTimeBased, - children, - dataView, - rowIndex, - rowId, - columns, - filters, - savedSearchId, - isEsqlMode, -}: TableRowDetailsProps) => { - const { singleDocHref, contextViewHref, onOpenSingleDoc, onOpenContextView } = useNavigationProps( - { - dataView, - rowIndex, - rowId, - columns, - filters, - savedSearchId, - } - ); - - return ( - - - - - - - - - -

- {isEsqlMode && ( - - )} - {!isEsqlMode && ( - - )} -

-
-
-
-
- {!isEsqlMode && ( - - - - {isTimeBased && ( - /* eslint-disable-next-line @elastic/eui/href-or-on-click */ - - - - )} - - - {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} - - - - - - - )} -
-
{children}
- - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/create_doc_table_embeddable.tsx b/src/plugins/discover/public/components/doc_table/create_doc_table_embeddable.tsx deleted file mode 100644 index 9d12c2fba337..000000000000 --- a/src/plugins/discover/public/components/doc_table/create_doc_table_embeddable.tsx +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { DocTableEmbeddable, DocTableEmbeddableProps } from './doc_table_embeddable'; - -export function DiscoverDocTableEmbeddable(renderProps: DocTableEmbeddableProps) { - return ( - - ); -} diff --git a/src/plugins/discover/public/components/doc_table/doc_table_context.tsx b/src/plugins/discover/public/components/doc_table/doc_table_context.tsx deleted file mode 100644 index c1e685d1d804..000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_context.tsx +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment } from 'react'; -import './index.scss'; -import { SkipBottomButton } from '../../application/main/components/skip_bottom_button'; -import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper'; - -const DocTableWrapperMemoized = React.memo(DocTableWrapper); - -const renderDocTable = (tableProps: DocTableRenderProps) => { - return ( - - - - {tableProps.renderHeader()} - {tableProps.renderRows(tableProps.rows)} -
- - ​ - -
- ); -}; - -export const DocTableContext = (props: DocTableProps) => { - return ; -}; diff --git a/src/plugins/discover/public/components/doc_table/doc_table_embeddable.tsx b/src/plugins/discover/public/components/doc_table/doc_table_embeddable.tsx deleted file mode 100644 index 1c1274a739f1..000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_embeddable.tsx +++ /dev/null @@ -1,141 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { memo, useCallback, useMemo, useRef } from 'react'; -import './index.scss'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiText } from '@elastic/eui'; -import { usePager } from '@kbn/discover-utils'; -import type { SearchResponseWarning } from '@kbn/search-response-warnings'; -import { - ToolBarPagination, - MAX_ROWS_PER_PAGE_OPTION, -} from './components/pager/tool_bar_pagination'; -import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper'; -import { SavedSearchEmbeddableBase } from '../../embeddable/components/saved_search_embeddable_base'; - -export interface DocTableEmbeddableProps extends Omit { - totalHitCount?: number; - rowsPerPageState?: number; - sampleSizeState: number; - interceptedWarnings?: SearchResponseWarning[]; - onUpdateRowsPerPage?: (rowsPerPage?: number) => void; -} - -export type DocTableEmbeddableSearchProps = Omit< - DocTableEmbeddableProps, - 'sampleSizeState' | 'isEsqlMode' ->; - -const DocTableWrapperMemoized = memo(DocTableWrapper); - -export const DocTableEmbeddable = (props: DocTableEmbeddableProps) => { - const onUpdateRowsPerPage = props.onUpdateRowsPerPage; - const tableWrapperRef = useRef(null); - const { - curPageIndex, - pageSize, - totalPages, - startIndex, - hasNextPage, - changePageIndex, - changePageSize, - } = usePager({ - initialPageSize: - typeof props.rowsPerPageState === 'number' && props.rowsPerPageState > 0 - ? Math.min(props.rowsPerPageState, MAX_ROWS_PER_PAGE_OPTION) - : 50, - totalItems: props.rows.length, - }); - const showPagination = totalPages !== 0; - - const scrollTop = useCallback(() => { - if (tableWrapperRef.current) { - tableWrapperRef.current.scrollTo(0, 0); - } - }, []); - - const pageOfItems = useMemo( - () => props.rows.slice(startIndex, pageSize + startIndex), - [pageSize, startIndex, props.rows] - ); - - const onPageChange = useCallback( - (page: number) => { - scrollTop(); - changePageIndex(page); - }, - [changePageIndex, scrollTop] - ); - - const onPageSizeChange = useCallback( - (size: number) => { - scrollTop(); - changePageSize(size); - onUpdateRowsPerPage?.(size); // to update `rowsPerPage` input param for the embeddable - }, - [changePageSize, scrollTop, onUpdateRowsPerPage] - ); - - const shouldShowLimitedResultsWarning = useMemo( - () => !hasNextPage && props.totalHitCount && props.rows.length < props.totalHitCount, - [hasNextPage, props.rows.length, props.totalHitCount] - ); - - const renderDocTable = useCallback( - (renderProps: DocTableRenderProps) => { - return ( -
- - {renderProps.renderHeader()} - {renderProps.renderRows(pageOfItems)} -
-
- ); - }, - [pageOfItems] - ); - - return ( - - - - ) : undefined - } - append={ - showPagination ? ( - - ) : undefined - } - > - - - ); -}; diff --git a/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx b/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx deleted file mode 100644 index 5a667ea6f70d..000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_infinite.tsx +++ /dev/null @@ -1,155 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment, memo, useCallback, useEffect, useRef, useState } from 'react'; -import './index.scss'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { debounce } from 'lodash'; -import { EuiButtonEmpty } from '@elastic/eui'; -import { DocTableProps, DocTableRenderProps, DocTableWrapper } from './doc_table_wrapper'; -import { SkipBottomButton } from '../../application/main/components/skip_bottom_button'; -import { shouldLoadNextDocPatch } from './utils/should_load_next_doc_patch'; -import { useDiscoverServices } from '../../hooks/use_discover_services'; -import { getAllowedSampleSize } from '../../utils/get_allowed_sample_size'; -import { useAppStateSelector } from '../../application/main/state_management/discover_app_state_container'; - -const FOOTER_PADDING = { padding: 0 }; - -const DocTableWrapperMemoized = memo(DocTableWrapper); - -interface DocTableInfiniteContentProps extends DocTableRenderProps { - limit: number; - onSetMaxLimit: () => void; - onBackToTop: () => void; -} - -const DocTableInfiniteContent = ({ - rows, - columnLength, - limit, - onSkipBottomButtonClick, - renderHeader, - renderRows, - onSetMaxLimit, - onBackToTop, -}: DocTableInfiniteContentProps) => { - const { uiSettings } = useDiscoverServices(); - const sampleSize = useAppStateSelector((state) => - getAllowedSampleSize(state.sampleSize, uiSettings) - ); - - const onSkipBottomButton = useCallback(() => { - onSetMaxLimit(); - onSkipBottomButtonClick(); - }, [onSetMaxLimit, onSkipBottomButtonClick]); - - return ( - - - - {renderHeader()} - {renderRows(rows.slice(0, limit))} - - - - - -
- {rows.length === sampleSize ? ( -
- - - - -
- ) : ( - - ​ - - )} -
-
- ); -}; - -export const DocTableInfinite = (props: DocTableProps) => { - const tableWrapperRef = useRef(null); - const [limit, setLimit] = useState(50); - - /** - * depending on which version of Discover is displayed, different elements are scrolling - * and have therefore to be considered for calculation of infinite scrolling - */ - useEffect(() => { - // After mounting table wrapper should be initialized - const scrollDiv = tableWrapperRef.current as HTMLDivElement; - const scrollMobileElem = document.documentElement; - - const scheduleCheck = debounce(() => { - const isMobileView = document.getElementsByClassName('dscSidebar__mobile').length > 0; - - const usedScrollDiv = isMobileView ? scrollMobileElem : scrollDiv; - if (shouldLoadNextDocPatch(usedScrollDiv)) { - setLimit((prevLimit) => prevLimit + 50); - } - }, 50); - - scrollDiv.addEventListener('scroll', scheduleCheck); - window.addEventListener('scroll', scheduleCheck); - - scheduleCheck(); - - return () => { - scrollDiv.removeEventListener('scroll', scheduleCheck); - window.removeEventListener('scroll', scheduleCheck); - }; - }, []); - - const onBackToTop = useCallback(() => { - const isMobileView = document.getElementsByClassName('dscSidebar__mobile').length > 0; - const focusElem = document.querySelector('.dscSkipButton') as HTMLElement; - focusElem.focus(); - - // Only the desktop one needs to target a specific container - if (!isMobileView && tableWrapperRef.current) { - tableWrapperRef.current.scrollTo(0, 0); - } else if (window) { - window.scrollTo(0, 0); - } - }, []); - - const setMaxLimit = useCallback(() => setLimit(props.rows.length), [props.rows.length]); - - const renderDocTable = useCallback( - (tableProps: DocTableRenderProps) => ( - - ), - [limit, onBackToTop, setMaxLimit] - ); - - return ; -}; diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx deleted file mode 100644 index fbbe460320cd..000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.test.tsx +++ /dev/null @@ -1,81 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { EuiIcon, EuiLoadingSpinner } from '@elastic/eui'; -import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; -import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; -import { DocTableWrapper, DocTableWrapperProps } from './doc_table_wrapper'; -import { discoverServiceMock } from '../../__mocks__/services'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import type { EsHitRecord } from '@kbn/discover-utils/types'; - -describe('Doc table component', () => { - const mountComponent = (customProps?: Partial) => { - const props = { - columns: ['_source'], - dataView: dataViewMock, - rows: [ - { - _index: 'mock_index', - _id: '1', - _score: 1, - fields: [ - { - timestamp: '2020-20-01T12:12:12.123', - }, - ], - _source: { message: 'mock_message', bytes: 20 }, - } as EsHitRecord, - ].map((row) => buildDataTableRecord(row, dataViewMock)), - sort: [['order_date', 'desc']], - isLoading: false, - searchDescription: '', - onAddColumn: () => {}, - onFilter: () => {}, - onMoveColumn: () => {}, - onRemoveColumn: () => {}, - onSort: () => {}, - useNewFieldsApi: true, - dataTestSubj: 'discoverDocTable', - render: () => { - return
mock
; - }, - ...(customProps || {}), - }; - - return mountWithIntl( - - - - ); - }; - - it('should render infinite table correctly', () => { - const component = mountComponent(); - expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy(); - expect(findTestSubject(component, 'docTable').exists()).toBeTruthy(); - expect(component.find('.kbnDocTable__error').exists()).toBeFalsy(); - }); - - it('should render error fallback if rows array is empty', () => { - const component = mountComponent({ rows: [], isLoading: false }); - expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy(); - expect(findTestSubject(component, 'docTable').exists()).toBeFalsy(); - expect(component.find('.kbnDocTable__error').find(EuiIcon).exists()).toBeTruthy(); - }); - - it('should render loading indicator', () => { - const component = mountComponent({ rows: [], isLoading: true }); - expect(findTestSubject(component, 'discoverDocTable').exists()).toBeTruthy(); - expect(findTestSubject(component, 'docTable').exists()).toBeFalsy(); - expect(component.find('.kbnDocTable__error').find(EuiLoadingSpinner).exists()).toBeTruthy(); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx b/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx deleted file mode 100644 index b9fb8b6681e2..000000000000 --- a/src/plugins/discover/public/components/doc_table/doc_table_wrapper.tsx +++ /dev/null @@ -1,253 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { forwardRef, useCallback, useMemo } from 'react'; -import { EuiIcon, EuiLoadingSpinner, EuiSpacer, EuiText } from '@elastic/eui'; -import type { DataView, DataViewField } from '@kbn/data-views-plugin/public'; -import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { Filter } from '@kbn/es-query'; -import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { SHOW_MULTIFIELDS, getShouldShowFieldHandler } from '@kbn/discover-utils'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { TableHeader } from './components/table_header/table_header'; -import { TableRow } from './components/table_row'; -import { useDiscoverServices } from '../../hooks/use_discover_services'; - -export interface DocTableProps { - /** - * Rows of classic table - */ - rows: DataTableRecord[]; - /** - * Columns of classic table - */ - columns: string[]; - /** - * Current DataView - */ - dataView: DataView; - /** - * Current sorting - */ - sort: string[][]; - /** - * New fields api switch - */ - useNewFieldsApi: boolean; - /** - * Current search description - */ - searchDescription?: string; - /** - * Current shared item title - */ - sharedItemTitle?: string; - /** - * Current data test subject - */ - dataTestSubj: string; - /** - * Loading state - */ - isLoading: boolean; - /** - * Filters applied by embeddalbe - */ - filters?: Filter[]; - /** - * Flag which identifies if Discover operates - * in ES|QL mode - */ - isEsqlMode?: boolean; - /** - * Saved search id - */ - savedSearchId?: string; - /** - * Filter callback - */ - onFilter?: DocViewFilterFn; - /** - * Sorting callback - */ - onSort?: (sort: string[][]) => void; - /** - * Add columns callback - */ - onAddColumn?: (column: string) => void; - /** - * Reordering column callback - */ - onMoveColumn?: (columns: string, newIdx: number) => void; - /** - * Remove column callback - */ - onRemoveColumn?: (column: string) => void; -} - -export interface DocTableRenderProps { - columnLength: number; - rows: DataTableRecord[]; - renderRows: (row: DataTableRecord[]) => JSX.Element[]; - renderHeader: () => JSX.Element; - onSkipBottomButtonClick: () => void; -} - -export interface DocTableWrapperProps extends DocTableProps { - /** - * Renders Doc table content - */ - render: (params: DocTableRenderProps) => JSX.Element; -} - -const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -export const DocTableWrapper = forwardRef( - ( - { - render, - columns, - filters, - isEsqlMode, - savedSearchId, - rows, - dataView, - onSort, - onAddColumn, - onMoveColumn, - onRemoveColumn, - sort, - onFilter, - useNewFieldsApi, - searchDescription, - sharedItemTitle, - dataTestSubj, - isLoading, - }: DocTableWrapperProps, - ref - ) => { - const { uiSettings } = useDiscoverServices(); - const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS, false), [uiSettings]); - - const onSkipBottomButtonClick = useCallback(async () => { - // delay scrolling to after the rows have been rendered - const bottomMarker = document.getElementById('discoverBottomMarker'); - - while (rows.length !== document.getElementsByClassName('kbnDocTable__row').length) { - await wait(50); - } - bottomMarker!.focus(); - await wait(50); - bottomMarker!.blur(); - }, [rows]); - - const shouldShowFieldHandler = useMemo( - () => - getShouldShowFieldHandler( - dataView.fields.map((field: DataViewField) => field.name), - dataView, - showMultiFields - ), - [dataView, showMultiFields] - ); - - const renderHeader = useCallback( - () => ( - - ), - [columns, dataView, onMoveColumn, onRemoveColumn, onSort, sort] - ); - - const renderRows = useCallback( - (rowsToRender: DataTableRecord[]) => { - return rowsToRender.map((current) => ( - - )); - }, - [ - columns, - filters, - savedSearchId, - onFilter, - dataView, - useNewFieldsApi, - shouldShowFieldHandler, - onAddColumn, - onRemoveColumn, - isEsqlMode, - rows, - ] - ); - - return ( -
} - > - {rows.length !== 0 && - render({ - columnLength: columns.length, - rows, - onSkipBottomButtonClick, - renderHeader, - renderRows, - })} - {!rows.length && ( -
- - {isLoading ? ( - <> - - - - - ) : ( - <> - - - - - )} - -
- )} -
- ); - } -); diff --git a/src/plugins/discover/public/components/doc_table/index.scss b/src/plugins/discover/public/components/doc_table/index.scss deleted file mode 100644 index 3663d807851c..000000000000 --- a/src/plugins/discover/public/components/doc_table/index.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import 'doc_table'; -@import 'components/index'; diff --git a/src/plugins/discover/public/components/doc_table/utils/row_formatter.scss b/src/plugins/discover/public/components/doc_table/utils/row_formatter.scss deleted file mode 100644 index ede39feed30b..000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/row_formatter.scss +++ /dev/null @@ -1,7 +0,0 @@ -// Special handling for images coming from the image field formatter -// See discover_grid.scss for more explanation on those values -.rowFormatter__value img { - vertical-align: middle; - max-height: lineHeightFromBaseline(2) !important; - max-width: ($euiSizeXXL * 12.5) !important; -} diff --git a/src/plugins/discover/public/components/doc_table/utils/row_formatter.test.ts b/src/plugins/discover/public/components/doc_table/utils/row_formatter.test.ts deleted file mode 100644 index d7cb720b7881..000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/row_formatter.test.ts +++ /dev/null @@ -1,313 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import ReactDOM from 'react-dom/server'; -import { formatRow, formatTopLevelObject } from './row_formatter'; -import { DataView } from '@kbn/data-views-plugin/public'; -import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; -import { DiscoverServices } from '../../../build_services'; -import { stubbedSavedObjectIndexPattern } from '@kbn/data-plugin/common/stubs'; -import { buildDataTableRecord } from '@kbn/discover-utils'; - -describe('Row formatter', () => { - let services: DiscoverServices; - - const createIndexPattern = () => { - const id = 'my-index'; - const { - type, - version, - attributes: { timeFieldName, fields, title }, - } = stubbedSavedObjectIndexPattern(id); - - return new DataView({ - spec: { id, type, version, timeFieldName, fields: JSON.parse(fields), title }, - fieldFormats: fieldFormatsMock, - shortDotsEnable: false, - metaFields: ['_id', '_type', '_score'], - }); - }; - - const dataView = createIndexPattern(); - const rawHit = { - _id: 'a', - _index: 'foo', - _score: 1, - _source: { - foo: 'bar', - number: 42, - hello: '

World

', - also: 'with "quotes" or \'single quotes\'', - }, - }; - const hit = buildDataTableRecord(rawHit, dataView); - - const shouldShowField = (fieldName: string) => - dataView.fields.getAll().some((fld) => fld.name === fieldName); - - beforeEach(() => { - services = { - fieldFormats: { - getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })), - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - }, - } as unknown as DiscoverServices; - }); - - it('formats document properly', () => { - expect(formatRow(hit, dataView, shouldShowField, 100, services.fieldFormats)) - .toMatchInlineSnapshot(` - World", - "hello", - ], - Array [ - "number", - 42, - "number", - ], - Array [ - "_id", - "a", - "_id", - ], - Array [ - "_score", - 1, - "_score", - ], - ] - } - /> - `); - }); - - it('limits number of rendered items', () => { - services = { - uiSettings: { - get: () => 1, - }, - fieldFormats: { - getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })), - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - }, - } as unknown as DiscoverServices; - expect(formatRow(hit, dataView, () => false, 1, services.fieldFormats)).toMatchInlineSnapshot(` - - `); - }); - - it('formats document with highlighted fields first', () => { - const highLightHit = buildDataTableRecord( - { ...rawHit, highlight: { number: ['42'] } }, - dataView - ); - - expect(formatRow(highLightHit, dataView, shouldShowField, 100, services.fieldFormats)) - .toMatchInlineSnapshot(` - World", - "hello", - ], - Array [ - "_id", - "a", - "_id", - ], - Array [ - "_score", - 1, - "_score", - ], - ] - } - /> - `); - }); - - it('formats top level objects using formatter', () => { - dataView.getFieldByName = jest.fn().mockReturnValue({ - name: 'subfield', - }); - dataView.getFormatterForField = jest.fn().mockReturnValue({ - convert: () => 'formatted', - }); - expect( - formatTopLevelObject( - { - fields: { - 'object.value': [5, 10], - }, - }, - { - 'object.value': [5, 10], - getByName: jest.fn(), - }, - dataView, - 100 - ) - ).toMatchInlineSnapshot(` - - `); - }); - - it('formats top level objects in alphabetical order', () => { - dataView.getFieldByName = jest.fn().mockReturnValue({ - name: 'subfield', - }); - dataView.getFormatterForField = jest.fn().mockReturnValue({ - convert: () => 'formatted', - }); - const formatted = ReactDOM.renderToStaticMarkup( - formatTopLevelObject( - { fields: { 'a.zzz': [100], 'a.ccc': [50] } }, - { 'a.zzz': [100], 'a.ccc': [50], getByName: jest.fn() }, - dataView, - 100 - ) - ); - expect(formatted.indexOf('
a.ccc:
')).toBeLessThan(formatted.indexOf('
a.zzz:
')); - }); - - it('formats top level objects with subfields and highlights', () => { - dataView.getFieldByName = jest.fn().mockReturnValue({ - name: 'subfield', - }); - dataView.getFormatterForField = jest.fn().mockReturnValue({ - convert: () => 'formatted', - }); - expect( - formatTopLevelObject( - { - fields: { - 'object.value': [5, 10], - 'object.keys': ['a', 'b'], - }, - highlight: { - 'object.keys': 'a', - }, - }, - { - 'object.value': [5, 10], - 'object.keys': ['a', 'b'], - getByName: jest.fn(), - }, - dataView, - 100 - ) - ).toMatchInlineSnapshot(` - - `); - }); - - it('formats top level objects, converting unknown fields to string', () => { - dataView.getFieldByName = jest.fn(); - dataView.getFormatterForField = jest.fn(); - expect( - formatTopLevelObject( - { - fields: { - 'object.value': [5, 10], - }, - }, - { - 'object.value': [5, 10], - getByName: jest.fn(), - }, - dataView, - 100 - ) - ).toMatchInlineSnapshot(` - - `); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/utils/row_formatter.tsx b/src/plugins/discover/public/components/doc_table/utils/row_formatter.tsx deleted file mode 100644 index ec33f5c16be0..000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/row_formatter.tsx +++ /dev/null @@ -1,87 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React, { Fragment } from 'react'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { - DataTableRecord, - ShouldShowFieldInTableHandler, - FormattedHit, -} from '@kbn/discover-utils/types'; -import { formatHit } from '@kbn/discover-utils'; - -import './row_formatter.scss'; - -interface Props { - defPairs: FormattedHit; -} -const TemplateComponent = ({ defPairs }: Props) => { - return ( -
- {defPairs.map((pair, idx) => ( - -
- {pair[0]} - {!!pair[1] && ':'} -
-
{' '} - - ))} -
- ); -}; - -export const formatRow = ( - hit: DataTableRecord, - dataView: DataView, - shouldShowFieldHandler: ShouldShowFieldInTableHandler, - maxEntries: number, - fieldFormats: FieldFormatsStart -) => { - const pairs = formatHit(hit, dataView, shouldShowFieldHandler, maxEntries, fieldFormats); - return ; -}; - -export const formatTopLevelObject = ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - row: Record, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - fields: Record, - dataView: DataView, - maxEntries: number -) => { - const highlights = row.highlight ?? {}; - const highlightPairs: FormattedHit = []; - const sourcePairs: FormattedHit = []; - const sorted = Object.entries(fields).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)); - sorted.forEach(([key, values]) => { - const field = dataView.getFieldByName(key); - const displayKey = fields.getByName ? fields.getByName(key)?.displayName : undefined; - const formatter = field - ? dataView.getFormatterForField(field) - : { convert: (v: unknown, ..._: unknown[]) => String(v) }; - if (!values.map) return; - const formatted = values - .map((val: unknown) => - formatter.convert(val, 'html', { - field, - hit: row, - }) - ) - .join(', '); - const pairs = highlights[key] ? highlightPairs : sourcePairs; - pairs.push([displayKey ? displayKey : key, formatted, key]); - }); - return ; -}; diff --git a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.test.ts b/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.test.ts deleted file mode 100644 index 25d5ef59c5f4..000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { shouldLoadNextDocPatch } from './should_load_next_doc_patch'; - -describe('shouldLoadNextDocPatch', () => { - test('next patch should not be loaded', () => { - const scrollingDomEl = { - scrollHeight: 500, - scrollTop: 100, - clientHeight: 100, - } as HTMLElement; - - expect(shouldLoadNextDocPatch(scrollingDomEl)).toBeFalsy(); - }); - - test('next patch should be loaded', () => { - const scrollingDomEl = { - scrollHeight: 500, - scrollTop: 350, - clientHeight: 100, - } as HTMLElement; - - expect(shouldLoadNextDocPatch(scrollingDomEl)).toBeTruthy(); - }); - - test("next patch should be loaded even there's a decimal scroll height", () => { - const scrollingDomEl = { - scrollHeight: 500, - scrollTop: 350.34234234, - clientHeight: 100, - } as HTMLElement; - - expect(shouldLoadNextDocPatch(scrollingDomEl)).toBeTruthy(); - }); -}); diff --git a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.ts b/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.ts deleted file mode 100644 index cfb4f93a2adb..000000000000 --- a/src/plugins/discover/public/components/doc_table/utils/should_load_next_doc_patch.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// use a buffer to start rendering more documents before the user completely scrolles down -const verticalScrollBuffer = 100; - -/** - * Helper function to determine if the next patch of 50 documents should be loaded - */ -export function shouldLoadNextDocPatch(domEl: HTMLElement) { - // the height of the scrolling div, including content not visible on the screen due to overflow. - const scrollHeight = domEl.scrollHeight; - // the number of pixels that the div is is scrolled vertically - const scrollTop = domEl.scrollTop; - // the inner height of the scrolling div, excluding content that's visible on the screen - const clientHeight = domEl.clientHeight; - - const consumedHeight = scrollTop + clientHeight; - const remainingHeight = scrollHeight - consumedHeight; - return remainingHeight < verticalScrollBuffer; -} diff --git a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx index 43960f98ea2b..5b77a184d925 100644 --- a/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx +++ b/src/plugins/discover/public/components/view_mode_toggle/view_mode_toggle.tsx @@ -11,7 +11,7 @@ import React, { useMemo, useEffect, useState, type ReactElement, useCallback } f import { EuiFlexGroup, EuiFlexItem, EuiTab, EuiTabs, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/react'; -import { isLegacyTableEnabled, SHOW_FIELD_STATISTICS } from '@kbn/discover-utils'; +import { SHOW_FIELD_STATISTICS } from '@kbn/discover-utils'; import type { DataView } from '@kbn/data-views-plugin/common'; import useMountedState from 'react-use/lib/useMountedState'; import { VIEW_MODE } from '../../../common/constants'; @@ -42,10 +42,6 @@ export const DocumentViewModeToggle = ({ dataVisualizer: dataVisualizerService, aiops: aiopsService, } = useDiscoverServices(); - const isLegacy = useMemo( - () => isLegacyTableEnabled({ uiSettings, isEsqlMode }), - [uiSettings, isEsqlMode] - ); const [showPatternAnalysisTab, setShowPatternAnalysisTab] = useState(null); const showFieldStatisticsTab = useMemo( @@ -93,7 +89,7 @@ export const DocumentViewModeToggle = ({ } }, [showPatternAnalysisTab, viewMode, setDiscoverViewMode]); - const includesNormalTabsStyle = viewMode === VIEW_MODE.AGGREGATED_LEVEL || isLegacy; + const includesNormalTabsStyle = viewMode === VIEW_MODE.AGGREGATED_LEVEL; const containerPadding = includesNormalTabsStyle ? euiTheme.size.s : 0; const containerCss = css` diff --git a/src/plugins/discover/public/context_awareness/__mocks__/index.tsx b/src/plugins/discover/public/context_awareness/__mocks__/index.tsx index 153d401cc980..ab179a87778a 100644 --- a/src/plugins/discover/public/context_awareness/__mocks__/index.tsx +++ b/src/plugins/discover/public/context_awareness/__mocks__/index.tsx @@ -25,6 +25,7 @@ import { ProfileProviderServices } from '../profile_providers/profile_provider_s import { ProfilesManager } from '../profiles_manager'; import { DiscoverEBTManager } from '../../services/discover_ebt_manager'; import { createLogsContextServiceMock } from '@kbn/discover-utils/src/__mocks__'; +import { discoverSharedPluginMock } from '@kbn/discover-shared-plugin/public/mocks'; export const createContextAwarenessMocks = ({ shouldRegisterProviders = true, @@ -84,6 +85,7 @@ export const createContextAwarenessMocks = ({ }, ], rowHeight: 3, + breakdownField: 'extension', })), getAdditionalCellActions: jest.fn((prev) => () => [ ...prev(), @@ -180,5 +182,6 @@ export const createContextAwarenessMocks = ({ const createProfileProviderServicesMock = () => { return { logsContextService: createLogsContextServiceMock(), + discoverShared: discoverSharedPluginMock.createStartContract(), } as ProfileProviderServices; }; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx index 46ecce387e87..07c836b12784 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/example/example_data_source_profile/profile.tsx @@ -220,6 +220,7 @@ export const createExampleDataSourceProfileProvider = (): DataSourceProfileProvi ]; }, getDefaultAppState: () => () => ({ + breakdownField: 'log.level', columns: [ { name: '@timestamp', diff --git a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts index d9c08af91f5d..11d5aab2763c 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/accessors/get_default_app_state.ts @@ -7,6 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import { LOG_LEVEL_FIELD } from '@kbn/discover-utils'; import type { DataSourceProfileProvider } from '../../../../profiles'; import { DefaultAppStateColumn } from '../../../../types'; @@ -14,10 +15,12 @@ export const createGetDefaultAppState = ({ defaultColumns, }: { defaultColumns?: DefaultAppStateColumn[]; -}): DataSourceProfileProvider['profile']['getDefaultAppState'] => { +} = {}): DataSourceProfileProvider['profile']['getDefaultAppState'] => { return (prev) => (params) => { const appState = { ...prev(params) }; + appState.breakdownField = LOG_LEVEL_FIELD; + if (defaultColumns) { appState.columns = []; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts index bebd340acfb3..7601680d6155 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts +++ b/src/plugins/discover/public/context_awareness/profile_providers/observability/logs_data_source_profile/profile.ts @@ -13,6 +13,7 @@ import { getCellRenderers, getRowIndicatorProvider, getRowAdditionalLeadingControls, + createGetDefaultAppState, } from './accessors'; import { extractIndexPatternFrom } from '../../extract_index_pattern_from'; import { OBSERVABILITY_ROOT_PROFILE_ID } from '../consts'; @@ -22,6 +23,7 @@ export const createLogsDataSourceProfileProvider = ( ): DataSourceProfileProvider => ({ profileId: 'observability-logs-data-source-profile', profile: { + getDefaultAppState: createGetDefaultAppState(), getCellRenderers, getRowIndicatorProvider, getRowAdditionalLeadingControls, diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/create_app_wrapper_accessor.ts b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/create_app_wrapper_accessor.ts new file mode 100644 index 000000000000..42382f088b7a --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/create_app_wrapper_accessor.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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { SecuritySolutionAppWrapperFeature } from '@kbn/discover-shared-plugin/public'; + +export const createAppWrapperAccessor = async ( + appWrapperFeature?: SecuritySolutionAppWrapperFeature +) => { + if (!appWrapperFeature) return undefined; + return appWrapperFeature.getWrapper(); +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.test.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.test.tsx new file mode 100644 index 000000000000..9774bafdb69b --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.test.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import type { SecuritySolutionCellRendererFeature } from '@kbn/discover-shared-plugin/public'; +import { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import { createCellRendererAccessor } from './get_cell_renderer_accessor'; +import { render } from '@testing-library/react'; + +const cellRendererFeature: SecuritySolutionCellRendererFeature = { + id: 'security-solution-cell-renderer', + getRenderer: async () => (fieldName: string) => { + if (fieldName === 'host.name') { + return (props: DataGridCellValueElementProps) => { + return
{props.columnId}
; + }; + } + }, +}; + +const mockCellProps = { + columnId: 'host.name', + row: { + id: '1', + raw: {}, + flattened: {}, + }, +} as DataGridCellValueElementProps; + +describe('getCellRendererAccessort', () => { + it('should return a cell renderer', async () => { + const getCellRenderer = await createCellRendererAccessor(cellRendererFeature); + expect(getCellRenderer).toBeDefined(); + const CellRenderer = getCellRenderer?.('host.name') as React.FC; + expect(CellRenderer).toBeDefined(); + const { getByTestId } = render(); + expect(getByTestId('cell-render-feature')).toBeVisible(); + expect(getByTestId('cell-render-feature')).toHaveTextContent('host.name'); + }); + + it('should return undefined if cellRendererFeature is not defined', async () => { + const getCellRenderer = await createCellRendererAccessor(); + expect(getCellRenderer).toBeUndefined(); + }); + + it('should return undefined if cellRendererGetter returns undefined', async () => { + const getCellRenderer = await createCellRendererAccessor(cellRendererFeature); + const cellRenderer = getCellRenderer?.('user.name'); + expect(cellRenderer).toBeUndefined(); + }); +}); diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.tsx new file mode 100644 index 000000000000..9f1d18d4a4d9 --- /dev/null +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/accessors/get_cell_renderer_accessor.tsx @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React from 'react'; +import type { SecuritySolutionCellRendererFeature } from '@kbn/discover-shared-plugin/public'; +import { DataGridCellValueElementProps } from '@kbn/unified-data-table'; + +export const createCellRendererAccessor = async ( + cellRendererFeature?: SecuritySolutionCellRendererFeature +) => { + if (!cellRendererFeature) return undefined; + const cellRendererGetter = await cellRendererFeature.getRenderer(); + function getCellRenderer(fieldName: string) { + const CellRenderer = cellRendererGetter(fieldName); + if (!CellRenderer) return undefined; + return React.memo(function SecuritySolutionCellRenderer(props: DataGridCellValueElementProps) { + return ; + }); + } + + return getCellRenderer; +}; diff --git a/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx index 602879125a33..572c86a0e515 100644 --- a/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx +++ b/src/plugins/discover/public/context_awareness/profile_providers/security/security_root_profile/profile.tsx @@ -7,25 +7,71 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import React, { FunctionComponent, PropsWithChildren } from 'react'; +import { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { RootProfileProvider, SolutionType } from '../../../profiles'; import { ProfileProviderServices } from '../../profile_provider_services'; import { SecurityProfileProviderFactory } from '../types'; +import { createCellRendererAccessor } from '../accessors/get_cell_renderer_accessor'; +import { createAppWrapperAccessor } from '../accessors/create_app_wrapper_accessor'; + +interface SecurityRootProfileContext { + appWrapper?: FunctionComponent>; + getCellRenderer?: ( + fieldName: string + ) => FunctionComponent | undefined; +} + +const EmptyAppWrapper: FunctionComponent> = ({ children }) => <>{children}; export const createSecurityRootProfileProvider: SecurityProfileProviderFactory< - RootProfileProvider -> = (services: ProfileProviderServices) => ({ - profileId: 'security-root-profile', - isExperimental: true, - profile: { - getCellRenderers: (prev) => (params) => ({ - ...prev(params), - }), - }, - resolve: (params) => { - if (params.solutionNavId === SolutionType.Security) { - return { isMatch: true, context: { solutionType: SolutionType.Security } }; - } + RootProfileProvider +> = (services: ProfileProviderServices) => { + const { discoverShared } = services; + const discoverFeaturesRegistry = discoverShared.features.registry; + const cellRendererFeature = discoverFeaturesRegistry.getById('security-solution-cell-renderer'); + const appWrapperFeature = discoverFeaturesRegistry.getById('security-solution-app-wrapper'); + + return { + profileId: 'security-root-profile', + isExperimental: true, + profile: { + getRenderAppWrapper: (PrevWrapper, params) => { + const AppWrapper = params.context.appWrapper ?? EmptyAppWrapper; + return ({ children }) => ( + + {children} + + ); + }, + getCellRenderers: + (prev, { context }) => + (params) => { + const entries = prev(params); + ['host.name', 'user.name', 'source.ip', 'destination.ip'].forEach((fieldName) => { + entries[fieldName] = context.getCellRenderer?.(fieldName) ?? entries[fieldName]; + }); + return entries; + }, + }, + resolve: async (params) => { + if (params.solutionNavId !== SolutionType.Security) { + return { + isMatch: false, + }; + } + + const getAppWrapper = await createAppWrapperAccessor(appWrapperFeature); + const getCellRenderer = await createCellRendererAccessor(cellRendererFeature); - return { isMatch: false }; - }, -}); + return { + isMatch: true, + context: { + solutionType: SolutionType.Security, + appWrapper: getAppWrapper?.(), + getCellRenderer, + }, + }; + }, + }; +}; diff --git a/src/plugins/discover/public/context_awareness/types.ts b/src/plugins/discover/public/context_awareness/types.ts index 4b75e6473aaf..70e40df3f8f6 100644 --- a/src/plugins/discover/public/context_awareness/types.ts +++ b/src/plugins/discover/public/context_awareness/types.ts @@ -20,7 +20,7 @@ import type { EuiIconType } from '@elastic/eui/src/components/icon/icon'; import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; import type { OmitIndexSignature } from 'type-fest'; import type { Trigger } from '@kbn/ui-actions-plugin/public'; -import type { PropsWithChildren, ReactElement } from 'react'; +import type { FunctionComponent, PropsWithChildren } from 'react'; import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import type { DiscoverDataSource } from '../../common/data_sources'; import type { DiscoverAppState } from '../application/main/state_management/discover_app_state_container'; @@ -123,6 +123,10 @@ export interface DefaultAppStateExtension { * * 1-20: number of lines to display */ rowHeight?: number; + /** + * The field to apply for the histogram breakdown + */ + breakdownField?: string; } /** @@ -264,7 +268,7 @@ export interface Profile { * @param props The app wrapper props * @returns The custom app wrapper component */ - getRenderAppWrapper: (props: PropsWithChildren<{}>) => ReactElement; + getRenderAppWrapper: FunctionComponent>; /** * Gets default Discover app state that should be used when the profile is resolved diff --git a/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx b/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx index deea7aa43c9f..f723ae1ea749 100644 --- a/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx +++ b/src/plugins/discover/public/embeddable/components/saved_search_embeddable_base.tsx @@ -69,7 +69,7 @@ export const SavedSearchEmbeddableBase: FC )} - {children} + {children} {Boolean(append) && {append}} diff --git a/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx b/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx index f6c77dc6cddf..0a2919fe1540 100644 --- a/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx +++ b/src/plugins/discover/public/embeddable/components/saved_search_grid.tsx @@ -36,12 +36,13 @@ interface DiscoverGridEmbeddableProps extends Omit void; onRemoveColumn: (column: string) => void; savedSearchId?: string; + enableDocumentViewer: boolean; } export const DiscoverGridMemoized = React.memo(DiscoverGrid); export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) { - const { interceptedWarnings, ...gridProps } = props; + const { interceptedWarnings, enableDocumentViewer, ...gridProps } = props; const [expandedDoc, setExpandedDoc] = useState(undefined); @@ -131,7 +132,7 @@ export function DiscoverGridEmbeddable(props: DiscoverGridEmbeddableProps) { expandedDoc={expandedDoc} showMultiFields={props.services.uiSettings.get(SHOW_MULTIFIELDS)} maxDocFieldsDisplayed={props.services.uiSettings.get(MAX_DOC_FIELDS_DISPLAYED)} - renderDocumentView={renderDocumentView} + renderDocumentView={enableDocumentViewer ? renderDocumentView : undefined} renderCustomToolbar={renderCustomToolbarWithElements} externalCustomRenderers={cellRenderers} enableComparisonMode diff --git a/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx b/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx index 44d3c1685cbf..8375e72aa34d 100644 --- a/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx +++ b/src/plugins/discover/public/embeddable/components/search_embeddable_grid_component.tsx @@ -15,7 +15,6 @@ import { DOC_HIDE_TIME_COLUMN_SETTING, SEARCH_FIELDS_FROM_SOURCE, SORT_DEFAULT_ORDER_SETTING, - isLegacyTableEnabled, } from '@kbn/discover-utils'; import { FetchContext, @@ -28,7 +27,6 @@ import { DataGridDensity, DataLoadingState, useColumns } from '@kbn/unified-data import { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; import { DiscoverGridSettings } from '@kbn/saved-search-plugin/common'; import useObservable from 'react-use/lib/useObservable'; -import { DiscoverDocTableEmbeddable } from '../../components/doc_table/create_doc_table_embeddable'; import { useDiscoverServices } from '../../hooks/use_discover_services'; import { getSortForEmbeddable } from '../../utils'; import { getAllowedSampleSize, getMaxAllowedSampleSize } from '../../utils/get_allowed_sample_size'; @@ -49,16 +47,17 @@ interface SavedSearchEmbeddableComponentProps { }; dataView: DataView; onAddFilter?: DocViewFilterFn; + enableDocumentViewer: boolean; stateManager: SearchEmbeddableStateManager; } -const DiscoverDocTableEmbeddableMemoized = React.memo(DiscoverDocTableEmbeddable); const DiscoverGridEmbeddableMemoized = React.memo(DiscoverGridEmbeddable); export function SearchEmbeddableGridComponent({ api, dataView, onAddFilter, + enableDocumentViewer, stateManager, }: SavedSearchEmbeddableComponentProps) { const discoverServices = useDiscoverServices(); @@ -103,14 +102,6 @@ export function SearchEmbeddableGridComponent({ ); const isEsql = useMemo(() => isEsqlMode(savedSearch), [savedSearch]); - const useLegacyTable = useMemo( - () => - isLegacyTableEnabled({ - uiSettings: discoverServices.uiSettings, - isEsqlMode: isEsql, - }), - [discoverServices, isEsql] - ); const sort = useMemo(() => { return getSortForEmbeddable(savedSearch.sort, dataView, discoverServices.uiSettings, isEsql); @@ -231,19 +222,6 @@ export function SearchEmbeddableGridComponent({ useNewFieldsApi, }; - if (useLegacyTable) { - return ( - - ); - } - return ( ); } diff --git a/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx b/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx index 37213b17c377..4117a36a4e04 100644 --- a/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx +++ b/src/plugins/discover/public/embeddable/get_search_embeddable_factory.tsx @@ -37,6 +37,7 @@ import { initializeEditApi } from './initialize_edit_api'; import { initializeFetch, isEsqlMode } from './initialize_fetch'; import { initializeSearchEmbeddableApi } from './initialize_search_embeddable_api'; import { + NonPersistedDisplayOptions, SearchEmbeddableApi, SearchEmbeddableRuntimeState, SearchEmbeddableSerializedState, @@ -84,6 +85,11 @@ export const getSearchEmbeddableFactory = ({ initialState?.savedObjectDescription ); + /** By-value SavedSearchComponent package (non-dashboard contexts) state, to adhere to the comparator contract of an embeddable. */ + const nonPersistedDisplayOptions$ = new BehaviorSubject< + NonPersistedDisplayOptions | undefined + >(initialState?.nonPersistedDisplayOptions); + /** All other state */ const blockingError$ = new BehaviorSubject(undefined); const dataLoading$ = new BehaviorSubject(true); @@ -201,6 +207,10 @@ export const getSearchEmbeddableFactory = ({ defaultPanelDescription$, (value) => defaultPanelDescription$.next(value), ], + nonPersistedDisplayOptions: [ + nonPersistedDisplayOptions$, + (value) => nonPersistedDisplayOptions$.next(value), + ], } ); @@ -304,7 +314,18 @@ export const getSearchEmbeddableFactory = ({ diff --git a/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx b/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx index e824fb6fdc02..7b6f20927d34 100644 --- a/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx +++ b/src/plugins/discover/public/embeddable/initialize_search_embeddable_api.tsx @@ -15,8 +15,8 @@ import { ISearchSource, SerializedSearchSourceFields } from '@kbn/data-plugin/co import { DataView } from '@kbn/data-views-plugin/common'; import { DataTableRecord } from '@kbn/discover-utils/types'; import type { - PublishesDataViews, - PublishesUnifiedSearch, + PublishesWritableUnifiedSearch, + PublishesWritableDataViews, StateComparators, } from '@kbn/presentation-publishing'; import { DiscoverGridSettings, SavedSearch } from '@kbn/saved-search-plugin/common'; @@ -71,7 +71,7 @@ export const initializeSearchEmbeddableApi = async ( discoverServices: DiscoverServices; } ): Promise<{ - api: PublishesSavedSearch & PublishesDataViews & Partial; + api: PublishesSavedSearch & PublishesWritableDataViews & Partial; stateManager: SearchEmbeddableStateManager; comparators: StateComparators; cleanup: () => void; @@ -110,6 +110,8 @@ export const initializeSearchEmbeddableApi = async ( searchSource.getField('query') ); + const canEditUnifiedSearch = () => false; + /** This is the state that has to be fetched */ const rows$ = new BehaviorSubject([]); const columnsMeta$ = new BehaviorSubject(undefined); @@ -144,6 +146,25 @@ export const initializeSearchEmbeddableApi = async ( pick(stateManager, EDITABLE_SAVED_SEARCH_KEYS) ); + /** APIs for updating search source properties */ + const setDataViews = (nextDataViews: DataView[]) => { + searchSource.setField('index', nextDataViews[0]); + dataViews.next(nextDataViews); + searchSource$.next(searchSource); + }; + + const setFilters = (filters: Filter[] | undefined) => { + searchSource.setField('filter', filters); + filters$.next(filters); + searchSource$.next(searchSource); + }; + + const setQuery = (query: Query | AggregateQuery | undefined) => { + searchSource.setField('query', query); + query$.next(query); + searchSource$.next(searchSource); + }; + /** Keep the saved search in sync with any state changes */ const syncSavedSearch = combineLatest([onAnyStateChange, searchSource$]) .pipe( @@ -163,10 +184,14 @@ export const initializeSearchEmbeddableApi = async ( syncSavedSearch.unsubscribe(); }, api: { + setDataViews, dataViews, savedSearch$, filters$, + setFilters, query$, + setQuery, + canEditUnifiedSearch, }, stateManager, comparators: { diff --git a/src/plugins/discover/public/embeddable/types.ts b/src/plugins/discover/public/embeddable/types.ts index 1b7ab4a96c2d..64cf5a390da3 100644 --- a/src/plugins/discover/public/embeddable/types.ts +++ b/src/plugins/discover/public/embeddable/types.ts @@ -15,10 +15,9 @@ import { HasInPlaceLibraryTransforms, PublishesBlockingError, PublishesDataLoading, - PublishesDataViews, PublishesSavedObjectId, - PublishesUnifiedSearch, PublishesWritablePanelTitle, + PublishesWritableUnifiedSearch, PublishingSubject, SerializedTimeRange, SerializedTitles, @@ -30,6 +29,7 @@ import { } from '@kbn/saved-search-plugin/common/types'; import { DataTableColumnsMeta } from '@kbn/unified-data-table'; import { BehaviorSubject } from 'rxjs'; +import { PublishesWritableDataViews } from '@kbn/presentation-publishing/interfaces/publishes_data_views'; import { EDITABLE_SAVED_SEARCH_KEYS } from './constants'; export type SearchEmbeddableState = Pick< @@ -59,6 +59,13 @@ export type SearchEmbeddableSerializedAttributes = Omit< > & Pick; +// These are options that are not persisted in the saved object, but can be used by solutions +// when utilising the SavedSearchComponent package outside of dashboard contexts. +export interface NonPersistedDisplayOptions { + enableDocumentViewer?: boolean; + enableFilters?: boolean; +} + export type SearchEmbeddableSerializedState = SerializedTitles & SerializedTimeRange & Partial> & { @@ -66,6 +73,7 @@ export type SearchEmbeddableSerializedState = SerializedTitles & attributes?: SavedSearchAttributes & { references: SavedSearch['references'] }; // by reference savedObjectId?: string; + nonPersistedDisplayOptions?: NonPersistedDisplayOptions; }; export type SearchEmbeddableRuntimeState = SearchEmbeddableSerializedAttributes & @@ -74,20 +82,20 @@ export type SearchEmbeddableRuntimeState = SearchEmbeddableSerializedAttributes savedObjectTitle?: string; savedObjectId?: string; savedObjectDescription?: string; + nonPersistedDisplayOptions?: NonPersistedDisplayOptions; }; export type SearchEmbeddableApi = DefaultEmbeddableApi< SearchEmbeddableSerializedState, SearchEmbeddableRuntimeState > & - PublishesDataViews & PublishesSavedObjectId & PublishesDataLoading & PublishesBlockingError & PublishesWritablePanelTitle & PublishesSavedSearch & - PublishesDataViews & - PublishesUnifiedSearch & + PublishesWritableDataViews & + PublishesWritableUnifiedSearch & HasInPlaceLibraryTransforms & HasTimeRange & Partial; diff --git a/src/plugins/discover/public/embeddable/utils/serialization_utils.ts b/src/plugins/discover/public/embeddable/utils/serialization_utils.ts index 191a37fe3326..f193d52054a3 100644 --- a/src/plugins/discover/public/embeddable/utils/serialization_utils.ts +++ b/src/plugins/discover/public/embeddable/utils/serialization_utils.ts @@ -67,6 +67,7 @@ export const deserializeState = async ({ return { ...savedSearch, ...panelState, + nonPersistedDisplayOptions: serializedState.rawState.nonPersistedDisplayOptions, }; } }; diff --git a/src/plugins/discover/public/index.ts b/src/plugins/discover/public/index.ts index b5d4308010f1..b54665bdc50a 100644 --- a/src/plugins/discover/public/index.ts +++ b/src/plugins/discover/public/index.ts @@ -35,6 +35,10 @@ export { type PublishesSavedSearch, type HasTimeRange, type SearchEmbeddableSerializedState, + type SearchEmbeddableRuntimeState, + type SearchEmbeddableApi, + type NonPersistedDisplayOptions, } from './embeddable'; export { loadSharingDataHelpers } from './utils'; export { LogsExplorerTabs, type LogsExplorerTabsProps } from './components/logs_explorer_tabs'; +export type { DiscoverServices } from './build_services'; diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 0ee80da03a7d..e29922d05f2c 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -21,14 +21,13 @@ import { import { DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { ENABLE_ESQL } from '@kbn/esql-utils'; import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; -import { SEARCH_EMBEDDABLE_TYPE, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; +import { SEARCH_EMBEDDABLE_TYPE } from '@kbn/discover-utils'; import { SavedSearchAttributes, SavedSearchType } from '@kbn/saved-search-plugin/common'; import { i18n } from '@kbn/i18n'; import { PLUGIN_ID } from '../common'; import { registerFeature } from './register_feature'; import { buildServices, UrlTracker } from './build_services'; import { ViewSavedSearchAction } from './embeddable/actions/view_saved_search_action'; -import { injectTruncateStyles } from './utils/truncate_styles'; import { initializeKbnUrlTracking } from './utils/initialize_kbn_url_tracking'; import { DiscoverContextAppLocator, @@ -285,7 +284,6 @@ export class DiscoverPlugin plugins.uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', viewSavedSearchAction); plugins.uiActions.registerTrigger(SEARCH_EMBEDDABLE_CELL_ACTIONS_TRIGGER); plugins.uiActions.registerTrigger(DISCOVER_CELL_ACTIONS_TRIGGER); - injectTruncateStyles(core.uiSettings.get(TRUNCATE_MAX_HEIGHT)); const isEsqlEnabled = core.uiSettings.get(ENABLE_ESQL); diff --git a/src/plugins/discover/public/types.ts b/src/plugins/discover/public/types.ts index 2ef380db9870..4b16e3e58df7 100644 --- a/src/plugins/discover/public/types.ts +++ b/src/plugins/discover/public/types.ts @@ -42,7 +42,7 @@ import type { AiopsPluginStart } from '@kbn/aiops-plugin/public'; import type { DataVisualizerPluginStart } from '@kbn/data-visualizer-plugin/public'; import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; import type { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; -import { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; +import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; import { DiscoverAppLocator } from '../common'; import { DiscoverCustomizationContext } from './customizations'; import { type DiscoverContainerProps } from './components/discover_container'; diff --git a/src/plugins/discover/public/utils/truncate_styles.ts b/src/plugins/discover/public/utils/truncate_styles.ts deleted file mode 100644 index 953144c4b90c..000000000000 --- a/src/plugins/discover/public/utils/truncate_styles.ts +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import createCache from '@emotion/cache'; -import { cache } from '@emotion/css'; -import { serializeStyles } from '@emotion/serialize'; - -/** - * The following emotion cache management was introduced here - * https://ntsim.uk/posts/how-to-update-or-remove-global-styles-in-emotion/ - */ -const TRUNCATE_GRADIENT_HEIGHT = 15; -const globalThemeCache = createCache({ key: 'truncation' }); - -const buildStylesheet = (maxHeight: number) => { - if (!maxHeight) { - return [ - ` - .dscTruncateByHeight { - max-height: none; - }`, - ]; - } - return [ - ` - .dscTruncateByHeight { - overflow: hidden; - max-height: ${maxHeight}px !important; - } - .dscTruncateByHeight:before { - top: ${maxHeight - TRUNCATE_GRADIENT_HEIGHT}px; - } - `, - ]; -}; - -export const injectTruncateStyles = (maxHeight: number) => { - const serialized = serializeStyles(buildStylesheet(maxHeight), cache.registered); - if (!globalThemeCache.inserted[serialized.name]) { - globalThemeCache.insert('', serialized, globalThemeCache.sheet, true); - } -}; diff --git a/src/plugins/discover/server/ui_settings.ts b/src/plugins/discover/server/ui_settings.ts index 9d0905b27bfa..7dd84c972869 100644 --- a/src/plugins/discover/server/ui_settings.ts +++ b/src/plugins/discover/server/ui_settings.ts @@ -23,13 +23,10 @@ import { CONTEXT_DEFAULT_SIZE_SETTING, CONTEXT_STEP_SETTING, CONTEXT_TIE_BREAKER_FIELDS_SETTING, - DOC_TABLE_LEGACY, MODIFY_COLUMNS_ON_SWITCH, SEARCH_FIELDS_FROM_SOURCE, MAX_DOC_FIELDS_DISPLAYED, SHOW_MULTIFIELDS, - TRUNCATE_MAX_HEIGHT, - TRUNCATE_MAX_HEIGHT_DEFAULT_VALUE, SHOW_FIELD_STATISTICS, ROW_HEIGHT_OPTION, } from '@kbn/discover-utils'; @@ -183,42 +180,6 @@ export const getUiSettings: ( category: ['discover'], schema: schema.arrayOf(schema.string()), }, - [DOC_TABLE_LEGACY]: { - name: i18n.translate('discover.advancedSettings.disableDocumentExplorer', { - defaultMessage: 'Document Explorer or classic view', - }), - value: false, - description: i18n.translate('discover.advancedSettings.disableDocumentExplorerDescription', { - defaultMessage: - 'To use the new {documentExplorerDocs} instead of the classic view, turn off this option. ' + - 'The Document Explorer offers better data sorting, resizable columns, and a full screen view.', - values: { - documentExplorerDocs: - `` + - i18n.translate('discover.advancedSettings.documentExplorerLinkText', { - defaultMessage: 'Document Explorer', - }) + - '', - }, - }), - requiresPageReload: true, - category: ['discover'], - schema: schema.boolean(), - metric: { - type: METRIC_TYPE.CLICK, - name: 'discover:useLegacyDataGrid', - }, - deprecation: { - message: i18n.translate( - 'discover.advancedSettings.discover.disableDocumentExplorerDeprecation', - { - defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', - } - ), - docLinksKey: 'discoverSettings', - }, - }, [MODIFY_COLUMNS_ON_SWITCH]: { name: i18n.translate('discover.advancedSettings.discover.modifyColumnsOnSwitchTitle', { defaultMessage: 'Modify columns when changing data views', @@ -316,23 +277,4 @@ export const getUiSettings: ( }), schema: schema.number({ min: -1 }), }, - [TRUNCATE_MAX_HEIGHT]: { - name: i18n.translate('discover.advancedSettings.params.maxCellHeightTitle', { - defaultMessage: 'Maximum cell height in the classic table', - }), - value: TRUNCATE_MAX_HEIGHT_DEFAULT_VALUE, - category: ['discover'], - description: i18n.translate('discover.advancedSettings.params.maxCellHeightText', { - defaultMessage: - 'The maximum height that a cell in a table should occupy. Set to 0 to disable truncation.', - }), - schema: schema.number({ min: 0 }), - requiresPageReload: true, - deprecation: { - message: i18n.translate('discover.advancedSettings.discover.maxCellHeightDeprecation', { - defaultMessage: 'This setting is deprecated and will be removed in Kibana 9.0.', - }), - docLinksKey: 'discoverSettings', - }, - }, }); diff --git a/src/plugins/discover/tsconfig.json b/src/plugins/discover/tsconfig.json index 1bb3aa10acce..36655983db13 100644 --- a/src/plugins/discover/tsconfig.json +++ b/src/plugins/discover/tsconfig.json @@ -95,9 +95,9 @@ "@kbn/presentation-containers", "@kbn/observability-ai-assistant-plugin", "@kbn/fields-metadata-plugin", + "@kbn/discover-contextual-components", "@kbn/logs-data-access-plugin", "@kbn/core-lifecycle-browser", - "@kbn/discover-contextual-components", "@kbn/esql-ast", "@kbn/discover-shared-plugin" ], diff --git a/src/plugins/discover_shared/public/index.ts b/src/plugins/discover_shared/public/index.ts index f58a9eaf44f8..4be7a75c817a 100644 --- a/src/plugins/discover_shared/public/index.ts +++ b/src/plugins/discover_shared/public/index.ts @@ -17,5 +17,9 @@ export type { DiscoverSharedPublicSetup, DiscoverSharedPublicStart } from './typ export type { ObservabilityLogsAIAssistantFeatureRenderDeps, ObservabilityLogsAIAssistantFeature, + SecuritySolutionCellRendererFeature, + SecuritySolutionAppWrapperFeature, DiscoverFeature, -} from './services/discover_features'; + DiscoverFeaturesServiceSetup, + DiscoverFeaturesServiceStart, +} from './services/discover_features/types'; diff --git a/src/plugins/discover_shared/public/services/discover_features/types.ts b/src/plugins/discover_shared/public/services/discover_features/types.ts index cdf78b333550..a40a4f87a3eb 100644 --- a/src/plugins/discover_shared/public/services/discover_features/types.ts +++ b/src/plugins/discover_shared/public/services/discover_features/types.ts @@ -7,7 +7,9 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { DataTableRecord } from '@kbn/discover-utils'; +import type { DataTableRecord } from '@kbn/discover-utils'; +import type { FunctionComponent, PropsWithChildren } from 'react'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; import { FeaturesRegistry } from '../../../common'; /** @@ -38,8 +40,31 @@ export interface ObservabilityCreateSLOFeature { }) => React.ReactNode; } +/** **************** Security Solution ****************/ + +export interface SecuritySolutionCellRendererFeature { + id: 'security-solution-cell-renderer'; + getRenderer: () => Promise< + (fieldName: string) => FunctionComponent | undefined + >; +} + +export interface SecuritySolutionAppWrapperFeature { + id: 'security-solution-app-wrapper'; + getWrapper: () => Promise<() => FunctionComponent>>; +} + +export type SecuritySolutionFeature = + | SecuritySolutionCellRendererFeature + | SecuritySolutionAppWrapperFeature; + +/** ****************************************************************************************/ + // This should be a union of all the available client features. -export type DiscoverFeature = ObservabilityLogsAIAssistantFeature | ObservabilityCreateSLOFeature; +export type DiscoverFeature = + | ObservabilityLogsAIAssistantFeature + | ObservabilityCreateSLOFeature + | SecuritySolutionFeature; /** * Service types diff --git a/src/plugins/discover_shared/tsconfig.json b/src/plugins/discover_shared/tsconfig.json index 9d2b07eb7aae..d8bda5214c74 100644 --- a/src/plugins/discover_shared/tsconfig.json +++ b/src/plugins/discover_shared/tsconfig.json @@ -13,5 +13,6 @@ "kbn_references": [ "@kbn/discover-utils", "@kbn/core", + "@kbn/unified-data-table", ] } diff --git a/src/plugins/embeddable/public/react_embeddable_system/phase_tracker.test.ts b/src/plugins/embeddable/public/react_embeddable_system/phase_tracker.test.ts new file mode 100644 index 000000000000..700c90f08ce5 --- /dev/null +++ b/src/plugins/embeddable/public/react_embeddable_system/phase_tracker.test.ts @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { BehaviorSubject, skip } from 'rxjs'; +import { PhaseTracker } from './phase_tracker'; + +describe('PhaseTracker', () => { + describe('api does not implement PublishesDataLoading or PublishesRendered', () => { + test(`should emit 'rendered' event`, (done) => { + const phaseTracker = new PhaseTracker(); + phaseTracker + .getPhase$() + .pipe(skip(1)) + .subscribe((phaseEvent) => { + expect(phaseEvent?.status).toBe('rendered'); + done(); + }); + phaseTracker.trackPhaseEvents('1', {}); + }); + }); + + describe('api implements PublishesDataLoading', () => { + test(`should emit 'loading' event when dataLoading is true`, (done) => { + const phaseTracker = new PhaseTracker(); + phaseTracker + .getPhase$() + .pipe(skip(1)) + .subscribe((phaseEvent) => { + expect(phaseEvent?.status).toBe('loading'); + done(); + }); + phaseTracker.trackPhaseEvents('1', { dataLoading: new BehaviorSubject(true) }); + }); + + test(`should emit 'rendered' event when dataLoading is false`, (done) => { + const phaseTracker = new PhaseTracker(); + phaseTracker + .getPhase$() + .pipe(skip(1)) + .subscribe((phaseEvent) => { + expect(phaseEvent?.status).toBe('rendered'); + done(); + }); + phaseTracker.trackPhaseEvents('1', { dataLoading: new BehaviorSubject(false) }); + }); + }); + + describe('api implements PublishesDataLoading and PublishesRendered', () => { + test(`should emit 'loading' event when dataLoading is true`, (done) => { + const phaseTracker = new PhaseTracker(); + phaseTracker + .getPhase$() + .pipe(skip(1)) + .subscribe((phaseEvent) => { + expect(phaseEvent?.status).toBe('loading'); + done(); + }); + phaseTracker.trackPhaseEvents('1', { + dataLoading: new BehaviorSubject(true), + rendered$: new BehaviorSubject(false), + }); + }); + + test(`should emit 'loading' event when dataLoading is false but rendered is false`, (done) => { + const phaseTracker = new PhaseTracker(); + phaseTracker + .getPhase$() + .pipe(skip(1)) + .subscribe((phaseEvent) => { + expect(phaseEvent?.status).toBe('loading'); + done(); + }); + phaseTracker.trackPhaseEvents('1', { + dataLoading: new BehaviorSubject(false), + rendered$: new BehaviorSubject(false), + }); + }); + + test(`should emit 'rendered' event only when rendered is true`, (done) => { + const phaseTracker = new PhaseTracker(); + phaseTracker + .getPhase$() + .pipe(skip(1)) + .subscribe((phaseEvent) => { + expect(phaseEvent?.status).toBe('rendered'); + done(); + }); + phaseTracker.trackPhaseEvents('1', { + dataLoading: new BehaviorSubject(false), + rendered$: new BehaviorSubject(true), + }); + }); + }); +}); diff --git a/src/plugins/embeddable/public/react_embeddable_system/phase_tracker.ts b/src/plugins/embeddable/public/react_embeddable_system/phase_tracker.ts new file mode 100644 index 000000000000..037599ab646c --- /dev/null +++ b/src/plugins/embeddable/public/react_embeddable_system/phase_tracker.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { + PhaseEvent, + apiPublishesDataLoading, + apiPublishesRendered, +} from '@kbn/presentation-publishing'; +import { BehaviorSubject, Subscription, combineLatest } from 'rxjs'; + +export class PhaseTracker { + private firstLoadCompleteTime: number | undefined; + private embeddableStartTime = performance.now(); + private subscriptions = new Subscription(); + private phase$ = new BehaviorSubject(undefined); + + getPhase$() { + return this.phase$; + } + + public trackPhaseEvents(uuid: string, api: unknown) { + const dataLoading$ = apiPublishesDataLoading(api) + ? api.dataLoading + : new BehaviorSubject(false); + const rendered$ = apiPublishesRendered(api) ? api.rendered$ : new BehaviorSubject(true); + + this.subscriptions.add( + combineLatest([dataLoading$, rendered$]).subscribe(([dataLoading, rendered]) => { + if (!this.firstLoadCompleteTime) { + this.firstLoadCompleteTime = performance.now(); + } + const duration = this.firstLoadCompleteTime - this.embeddableStartTime; + const status = dataLoading || !rendered ? 'loading' : 'rendered'; + this.phase$.next({ id: uuid, status, timeToEvent: duration }); + }) + ); + } + + public cleanup() { + this.subscriptions.unsubscribe(); + } +} diff --git a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx index c3dc06e198cd..edf52244c2d4 100644 --- a/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx +++ b/src/plugins/embeddable/public/react_embeddable_system/react_embeddable_renderer.tsx @@ -16,12 +16,7 @@ import { SerializedPanelState, } from '@kbn/presentation-containers'; import { PresentationPanel, PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; -import { - apiPublishesDataLoading, - ComparatorDefinition, - PhaseEvent, - StateComparators, -} from '@kbn/presentation-publishing'; +import { ComparatorDefinition, StateComparators } from '@kbn/presentation-publishing'; import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react'; import { BehaviorSubject, combineLatest, debounceTime, skip, Subscription, switchMap } from 'rxjs'; import { v4 as generateId } from 'uuid'; @@ -31,6 +26,7 @@ import { DefaultEmbeddableApi, SetReactEmbeddableApiRegistration, } from './types'; +import { PhaseTracker } from './phase_tracker'; const ON_STATE_CHANGE_DEBOUNCE = 100; @@ -69,6 +65,7 @@ export const ReactEmbeddableRenderer = < | 'hideLoader' | 'hideHeader' | 'hideInspector' + | 'getActions' >; hidePanelChrome?: boolean; /** @@ -78,25 +75,12 @@ export const ReactEmbeddableRenderer = < onAnyStateChange?: (state: SerializedPanelState) => void; }) => { const cleanupFunction = useRef<(() => void) | null>(null); - const firstLoadCompleteTime = useRef(null); + const phaseTracker = useRef(new PhaseTracker()); const componentPromise = useMemo( () => { const uuid = maybeId ?? generateId(); - /** - * Phase tracking instrumentation for telemetry - */ - const phase$ = new BehaviorSubject(undefined); - const embeddableStartTime = performance.now(); - const reportPhaseChange = (loading: boolean) => { - if (firstLoadCompleteTime.current === null) { - firstLoadCompleteTime.current = performance.now(); - } - const duration = firstLoadCompleteTime.current - embeddableStartTime; - phase$.next({ id: uuid, status: loading ? 'loading' : 'rendered', timeToEvent: duration }); - }; - /** * Build the embeddable promise */ @@ -126,7 +110,7 @@ export const ReactEmbeddableRenderer = < return { ...apiRegistration, uuid, - phase$, + phase$: phaseTracker.current.getPhase$(), parentApi, hasLockedHoverActions$, lockHoverActions: (lock: boolean) => { @@ -186,6 +170,7 @@ export const ReactEmbeddableRenderer = < cleanupFunction.current = () => { subscriptions.unsubscribe(); + phaseTracker.current.cleanup(); unsavedChanges.cleanup(); }; return fullApi as Api & HasSnapshottableState; @@ -200,13 +185,8 @@ export const ReactEmbeddableRenderer = < lastSavedRuntimeState ); - if (apiPublishesDataLoading(api)) { - subscriptions.add( - api.dataLoading.subscribe((loading) => reportPhaseChange(Boolean(loading))) - ); - } else { - reportPhaseChange(false); - } + phaseTracker.current.trackPhaseEvents(uuid, api); + return { api, Component }; }; diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx index 82516423424f..e48e5192f189 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/dynamic_fields.mdx @@ -65,7 +65,7 @@ export const DynamicFields = () => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label="Remove item" - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> @@ -155,7 +155,7 @@ export const DynamicFieldsValidation = () => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label="Remove item" - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> @@ -218,7 +218,7 @@ export const DynamicFieldsReorder = () => { return ( -
+
@@ -245,7 +245,7 @@ export const DynamicFieldsReorder = () => { onClick={() => removeItem(item.id)} iconType="minusInCircle" aria-label="Remove item" - style={{ marginTop: '28px' }} + css={{ marginTop: '28px' }} /> @@ -273,4 +273,4 @@ export const DynamicFieldsReorder = () => { ); }; -``` \ No newline at end of file +``` diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx index 7e7cce5e8133..085144040081 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/fields_composition.mdx @@ -7,8 +7,8 @@ tags: ['forms', 'kibana', 'dev'] date: 2021-04-14 --- -If your form does not have a fix set of fields (single interface) and you need to add/remove fields dynamically, you can leverage the power of field composition with the form lib. It let's you swap fields in your form whenever needed. Any field that **is not in the DOM** is automatically cleared when unmounting and its value won't be returned in the form data. -If you _do_ need to keep a field value, but hide the field in the UI, then you need to use CSS (`
...
`) +If your form does not have a fix set of fields (single interface) and you need to add/remove fields dynamically, you can leverage the power of field composition with the form lib. It let's you swap fields in your form whenever needed. Any field that **is not in the DOM** is automatically cleared when unmounting and its value won't be returned in the form data. +If you _do_ need to keep a field value, but hide the field in the UI, then you need to use CSS (`
...
`) Imagine you're building an app that lets people buy a car online. You want to build a form that lets the user select the model of the car (`sedan`, `golf cart`, `clown mobile`), and based on their selection you'll show a different form for configuring the selected model's options. diff --git a/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx b/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx index dd3b402e85e3..3ab849d262db 100644 --- a/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx +++ b/src/plugins/es_ui_shared/static/forms/docs/examples/serializers_deserializers.mdx @@ -90,7 +90,7 @@ export const SerializersAndDeserializers = () => { {/* We don't remove it from the DOM as we would lose the value entered in the field. */} -
+
diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx index f920eb91ea3c..b777ecd4a85b 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_complex.tsx @@ -43,7 +43,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -51,7 +51,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -59,7 +59,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -70,7 +70,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -78,7 +78,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -86,7 +86,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -188,7 +188,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, @@ -303,7 +303,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -311,7 +311,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -319,7 +319,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -330,7 +330,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -338,7 +338,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -346,7 +346,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -448,7 +448,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx index 83beef1fc838..098919fb96c2 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_dynamic_data.tsx @@ -46,7 +46,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -54,7 +54,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -62,7 +62,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -73,7 +73,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -81,7 +81,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -89,7 +89,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -223,7 +223,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, @@ -384,7 +384,7 @@ const percentageOptions = [ { value: 'percentage_config_1', inputDisplay: ( - + Percentage 1 ), @@ -392,7 +392,7 @@ const percentageOptions = [ { value: 'percentage_config_2', inputDisplay: ( - + Percentage 2 ), @@ -400,7 +400,7 @@ const percentageOptions = [ { value: 'percentage_config_3', inputDisplay: ( - + Percentage 3 ), @@ -411,7 +411,7 @@ const valueOptions = [ { value: 'value_config_1', inputDisplay: ( - + Value 1 ), @@ -419,7 +419,7 @@ const valueOptions = [ { value: 'value_config_2', inputDisplay: ( - + Value 2 ), @@ -427,7 +427,7 @@ const valueOptions = [ { value: 'value_config_3', inputDisplay: ( - + Value 3 ), @@ -561,7 +561,7 @@ const ProcessorsConfigurator: FC<{ ruleType: string }> = ({ ruleType }) => { component={TextField} componentProps={{ euiFieldProps: { - style: { + css: { maxWidth: '180px', }, }, diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx index fb56fded77e3..807412a33a92 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_array_reorder.tsx @@ -87,7 +87,7 @@ export function Reorder() {
@@ -214,7 +214,7 @@ const MyFormComponent = () => {
diff --git a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx index c24df488ce8a..18b4cf2fd1d4 100644 --- a/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx +++ b/src/plugins/es_ui_shared/static/forms/hook_form_lib/components/__stories__/use_field_field_types.tsx @@ -98,7 +98,7 @@ const getPropsForType = (type: FieldType) => { { value: 'warning', inputDisplay: ( - + Warning ), @@ -107,7 +107,7 @@ const getPropsForType = (type: FieldType) => { { value: 'minor', inputDisplay: ( - + Minor ), @@ -115,7 +115,7 @@ const getPropsForType = (type: FieldType) => { { value: 'critical', inputDisplay: ( - + Critical ), diff --git a/src/plugins/esql_datagrid/public/create_datagrid.tsx b/src/plugins/esql_datagrid/public/create_datagrid.tsx index 7df7d84fb808..4c281519edfb 100644 --- a/src/plugins/esql_datagrid/public/create_datagrid.tsx +++ b/src/plugins/esql_datagrid/public/create_datagrid.tsx @@ -44,7 +44,7 @@ export const ESQLDataGrid = (props: ESQLDataGridProps) => { }, []); const getWrapper = (children: JSX.Element) => { - return props.fullHeight ?
{children}
: <>{children}; + return props.fullHeight ?
{children}
: <>{children}; }; const deps = value?.[0]; diff --git a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx index 41f1fd16148f..cac179d45f94 100644 --- a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx +++ b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.test.tsx @@ -20,6 +20,7 @@ import { EmbeddableComponent, FieldBasedIndexPatternColumn, TypedLensByValueInput, + LensByValueInput, } from '@kbn/lens-plugin/public'; import { Datatable } from '@kbn/expressions-plugin/common'; import { render, screen, waitFor } from '@testing-library/react'; @@ -27,7 +28,6 @@ import '@testing-library/jest-dom'; import userEvent from '@testing-library/user-event'; import { I18nProvider } from '@kbn/i18n-react'; import { GroupPreview } from './group_preview'; -import { LensByValueInput } from '@kbn/lens-plugin/public/embeddable'; import { DATA_LAYER_ID, DATE_HISTOGRAM_COLUMN_ID, getCurrentTimeField } from './lens_attributes'; import { EuiSuperDatePickerTestHarness } from '@kbn/test-eui-helpers'; diff --git a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.tsx b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.tsx index 3f1c47f3a72b..5f03d6709233 100644 --- a/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.tsx +++ b/src/plugins/event_annotation_listing/public/components/group_editor_flyout/group_preview.tsx @@ -198,28 +198,25 @@ export const GroupPreview = ({ justifyContent="center" > -
div { height: 400px; width: 100%; } `} - > - - setChartTimeRange({ - from: new Date(range[0]).toISOString(), - to: new Date(range[1]).toISOString(), - }) - } - searchSessionId={searchSessionId} - /> -
+ data-test-subj="chart" + id="annotation-library-preview" + timeRange={chartTimeRange} + attributes={lensAttributes} + onBrushEnd={({ range }) => + setChartTimeRange({ + from: new Date(range[0]).toISOString(), + to: new Date(range[1]).toISOString(), + }) + } + searchSessionId={searchSessionId} + />
) : ( diff --git a/src/plugins/expression_error/public/components/error/error.tsx b/src/plugins/expression_error/public/components/error/error.tsx index fac0ee484fb0..93e10470c320 100644 --- a/src/plugins/expression_error/public/components/error/error.tsx +++ b/src/plugins/expression_error/public/components/error/error.tsx @@ -40,14 +40,14 @@ export const Error: FC = ({ payload, onClose }) => { return (

{message ? strings.getDescription() : ''}

{message && ( -

+

{message}

)} diff --git a/src/plugins/expression_error/public/components/error/show_debugging.tsx b/src/plugins/expression_error/public/components/error/show_debugging.tsx index ddb9cbeea7a1..49ef1acb90d3 100644 --- a/src/plugins/expression_error/public/components/error/show_debugging.tsx +++ b/src/plugins/expression_error/public/components/error/show_debugging.tsx @@ -24,7 +24,7 @@ export const ShowDebugging: FC = ({ payload }) => { See Details {expanded && ( -
+
)} diff --git a/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx b/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx index bdc28e714cd8..82b21e60c845 100644 --- a/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx +++ b/src/plugins/expression_repeat_image/public/components/repeat_image_component.tsx @@ -94,7 +94,7 @@ export function RepeatImageComponent({ } return ( -
+
{imagesToRender}
); 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 32c7d85fa569..eb9bc34d40b3 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 @@ -61,7 +61,7 @@ export function ReactExpressionRenderer({
{isEmpty && } {isLoading && ( - + )} {!isLoading && error && renderError?.(error.message, error)}
diff --git a/src/plugins/expressions/public/react_expression_renderer/use_debounced_value.test.ts b/src/plugins/expressions/public/react_expression_renderer/use_debounced_value.test.ts index ebbe6e412901..8f32edaac50a 100644 --- a/src/plugins/expressions/public/react_expression_renderer/use_debounced_value.test.ts +++ b/src/plugins/expressions/public/react_expression_renderer/use_debounced_value.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useDebouncedValue } from './use_debounced_value'; describe('useDebouncedValue', () => { diff --git a/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.test.ts b/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.test.ts index ac9ff31730f0..9dc3ab684ccb 100644 --- a/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.test.ts +++ b/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.test.ts @@ -8,7 +8,7 @@ */ import type { RefObject } from 'react'; -import { act, renderHook, RenderHookResult } from '@testing-library/react-hooks'; +import { renderHook, act, RenderHookResult } from '@testing-library/react'; import { Subject } from 'rxjs'; import type { IInterpreterRenderHandlers } from '../../common'; import { ExpressionRendererParams, useExpressionRenderer } from './use_expression_renderer'; @@ -23,7 +23,7 @@ describe('useExpressionRenderer', () => { loading$: Subject; render$: Subject; }; - let hook: RenderHookResult>; + let hook: RenderHookResult, ExpressionRendererParams>; beforeEach(() => { nodeRef = { current: document.createElement('div') }; diff --git a/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts b/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts index 2d5f5d6ddd49..06d588263869 100644 --- a/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts +++ b/src/plugins/expressions/public/react_expression_renderer/use_expression_renderer.ts @@ -26,7 +26,7 @@ export interface ExpressionRendererParams extends IExpressionLoaderParams { debounce?: number; expression: string | ExpressionAstExpression; hasCustomErrorRenderer?: boolean; - onData$?( + onData$?( data: TData, adapters?: TInspectorAdapters, partial?: boolean diff --git a/src/plugins/expressions/public/react_expression_renderer/use_shallow_memo.test.ts b/src/plugins/expressions/public/react_expression_renderer/use_shallow_memo.test.ts index acfa528c932b..9e073c86dbee 100644 --- a/src/plugins/expressions/public/react_expression_renderer/use_shallow_memo.test.ts +++ b/src/plugins/expressions/public/react_expression_renderer/use_shallow_memo.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useShallowMemo } from './use_shallow_memo'; describe('useShallowMemo', () => { diff --git a/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts b/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts index 16fd2e535763..f0b33953caf2 100644 --- a/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts +++ b/src/plugins/files/server/file_client/integration_tests/es_file_client.test.ts @@ -19,8 +19,8 @@ describe('ES-index-backed file client', () => { let esClient: TestEnvironmentUtils['esClient']; let fileClient: FileClient; let testHarness: TestEnvironmentUtils; - const blobStorageIndex = '.kibana-test-blob'; - const metadataIndex = '.kibana-test-metadata'; + const blobStorageIndex = 'kibana-files-test-blob'; + const metadataIndex = 'kibana-files-test-metadata'; const deleteFile = async ({ id, diff --git a/src/plugins/files/server/test_utils/setup_integration_environment.ts b/src/plugins/files/server/test_utils/setup_integration_environment.ts index e5a9ff9ffd33..369f39867f60 100644 --- a/src/plugins/files/server/test_utils/setup_integration_environment.ts +++ b/src/plugins/files/server/test_utils/setup_integration_environment.ts @@ -21,7 +21,7 @@ export type TestEnvironmentUtils = Awaited )} - + {description &&

{description}

}
diff --git a/src/plugins/home/public/application/components/recently_accessed.js b/src/plugins/home/public/application/components/recently_accessed.js index e873b5eda599..be9d8d0ac192 100644 --- a/src/plugins/home/public/application/components/recently_accessed.js +++ b/src/plugins/home/public/application/components/recently_accessed.js @@ -58,7 +58,7 @@ export class RecentlyAccessed extends Component { for (let i = NUM_LONG_LINKS; i < this.props.recentlyAccessed.length; i++) { dropdownLinks.push(
  • diff --git a/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap b/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap index 5235392121ab..b11a936807c9 100644 --- a/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap +++ b/src/plugins/home/public/application/components/tutorial/__snapshots__/instruction_set.test.js.snap @@ -7,7 +7,7 @@ exports[`render 1`] = ` paddingSize="none" > - {this.renderTabs()} + {this.renderTabs()} {this.renderHeader()} diff --git a/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx b/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx index 1a5ee3bc64e1..0a680e317dc7 100644 --- a/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx +++ b/src/plugins/image_embeddable/public/components/image_editor/image_editor_flyout.tsx @@ -205,7 +205,7 @@ export function ImageEditorFlyout(props: ImageEditorFlyoutProps) {
  • } /> -

    +

    setIsFilePickerOpen(true)} data-test-subj="imageEmbeddableEditorSelectFiles" diff --git a/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx b/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx index 4eb8edc0a069..ff4b2233a97d 100644 --- a/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx +++ b/src/plugins/image_embeddable/public/components/image_viewer/image_viewer.tsx @@ -126,7 +126,7 @@ export function ImageViewer({ )} {onClear && ( { } return ( - + {controlComponent} ); diff --git a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap index e063ccea48cc..42b8d1a99c1d 100644 --- a/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap +++ b/src/plugins/inspector/public/views/requests/components/details/clusters_view/clusters_table/__snapshots__/cluster_view.test.tsx.snap @@ -2,13 +2,13 @@ exports[`render partial should display callout when request timed out 1`] = ` + {clusterDetails.timed_out ? ( - + {host} diff --git a/src/plugins/interactive_setup/public/enrollment_token_form.tsx b/src/plugins/interactive_setup/public/enrollment_token_form.tsx index 65765291fb79..3cfc7d3fe33a 100644 --- a/src/plugins/interactive_setup/public/enrollment_token_form.tsx +++ b/src/plugins/interactive_setup/public/enrollment_token_form.tsx @@ -184,7 +184,7 @@ const EnrollmentTokenDetails: FunctionComponent = ( defaultMessage="Connect to" /> - + {token.adr[0]} diff --git a/src/plugins/interactive_setup/public/single_chars_field.tsx b/src/plugins/interactive_setup/public/single_chars_field.tsx index 27bb6ce3e60a..13af3f1f7ba3 100644 --- a/src/plugins/interactive_setup/public/single_chars_field.tsx +++ b/src/plugins/interactive_setup/public/single_chars_field.tsx @@ -73,13 +73,13 @@ export const SingleCharsField: FunctionComponent = ({ ); } children.push( - + { inputRefs.current[i] = el; @@ -125,7 +125,7 @@ export const SingleCharsField: FunctionComponent = ({ }} maxLength={1} isInvalid={isInvalid} - style={{ textAlign: 'center' }} + css={{ textAlign: 'center' }} aria-label={i18n.translate('interactiveSetup.singleCharsField.digitLabel', { defaultMessage: 'Digit {index}', values: { index: i + 1 }, diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx index 3631ae86e1ec..228e6d5f8cb1 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/action_cards/action_cards.tsx @@ -23,7 +23,7 @@ export const ActionCards = ({ actionCards }: ActionCardsProps) => { )); return ( - + {cards} ); diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap index 9782a4cf1da6..fdee5059e787 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/__snapshots__/elastic_agent_card.test.tsx.snap @@ -27,8 +27,7 @@ exports[`ElasticAgentCard props button 1`] = ` image={ } @@ -78,8 +78,7 @@ exports[`ElasticAgentCard props category 1`] = ` image={ } @@ -129,8 +129,7 @@ exports[`ElasticAgentCard props href 1`] = ` image={ } @@ -185,8 +185,7 @@ exports[`ElasticAgentCard props recommended 1`] = ` image={ } @@ -236,8 +236,7 @@ exports[`ElasticAgentCard renders 1`] = ` image={ } diff --git a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx index c4849e814edd..1c8169ac5a73 100644 --- a/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx +++ b/src/plugins/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx @@ -43,7 +43,7 @@ export const ElasticAgentCard: FunctionComponent = ({ const image = ( = { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, }, - 'truncate:maxHeight': { - type: 'long', - _meta: { description: 'Non-default value of setting.' }, - }, 'timepicker:timeDefaults': { type: 'keyword', _meta: { description: 'Non-default value of setting.' }, @@ -424,10 +420,6 @@ export const stackManagementSchema: MakeSchemaFrom = { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, }, - 'doc_table:legacy': { - type: 'boolean', - _meta: { description: 'Non-default value of setting.' }, - }, 'discover:modifyColumnsOnSwitch': { type: 'boolean', _meta: { description: 'Non-default value of setting.' }, diff --git a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts index 979643600735..4c6f17a85914 100644 --- a/src/plugins/kibana_usage_collection/server/collectors/management/types.ts +++ b/src/plugins/kibana_usage_collection/server/collectors/management/types.ts @@ -30,7 +30,6 @@ export interface UsageStats { 'autocomplete:valueSuggestionMethod': string; 'search:timeout': number; 'visualization:visualize:legacyHeatmapChartsLibrary': boolean; - 'doc_table:legacy': boolean; 'discover:modifyColumnsOnSwitch': boolean; 'discover:searchFieldsFromSource': boolean; 'discover:showFieldStatistics': boolean; @@ -101,7 +100,6 @@ export interface UsageStats { 'fileUpload:maxFileSize': string; 'ml:anomalyDetection:results:enableTimeDefaults': boolean; 'ml:anomalyDetection:results:timeDefaults': string; - 'truncate:maxHeight': number; 'timepicker:timeDefaults': string; 'timepicker:refreshIntervalDefaults': string; 'timepicker:quickRanges': string; diff --git a/src/plugins/navigation/public/mocks.ts b/src/plugins/navigation/public/mocks.tsx similarity index 54% rename from src/plugins/navigation/public/mocks.ts rename to src/plugins/navigation/public/mocks.tsx index b9977daf5622..5f9f1476b464 100644 --- a/src/plugins/navigation/public/mocks.ts +++ b/src/plugins/navigation/public/mocks.tsx @@ -6,13 +6,24 @@ * your election, the "Elastic License 2.0", the "GNU Affero General Public * License v3.0 only", or the "Server Side Public License, v 1". */ - +import React from 'react'; import { of } from 'rxjs'; +import { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { Plugin } from '.'; +import { createTopNav } from './top_nav_menu'; export type Setup = jest.Mocked>; export type Start = jest.Mocked>; +// mock mountPointPortal +jest.mock('@kbn/react-kibana-mount', () => { + const original = jest.requireActual('@kbn/react-kibana-mount'); + return { + ...original, + MountPointPortal: jest.fn(({ children }) => children), + }; +}); + const createSetupContract = (): jest.Mocked => { const setupContract = { registerMenuItem: jest.fn(), @@ -21,12 +32,21 @@ const createSetupContract = (): jest.Mocked => { return setupContract; }; +export const unifiedSearchMock = { + ui: { + SearchBar: () =>

    , + AggregateQuerySearchBar: () =>
    , + }, +} as unknown as UnifiedSearchPublicPluginStart; + const createStartContract = (): jest.Mocked => { const startContract = { ui: { - TopNavMenu: jest.fn(), - createTopNavWithCustomContext: jest.fn().mockImplementation(() => jest.fn()), - AggregateQueryTopNavMenu: jest.fn(), + TopNavMenu: jest.fn().mockImplementation(createTopNav(unifiedSearchMock, [])), + AggregateQueryTopNavMenu: jest.fn().mockImplementation(createTopNav(unifiedSearchMock, [])), + createTopNavWithCustomContext: jest + .fn() + .mockImplementation(createTopNav(unifiedSearchMock, [])), }, addSolutionNavigation: jest.fn(), isSolutionNavEnabled$: of(false), diff --git a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx index dff09fa0bac3..5ad6e2bbe5dd 100644 --- a/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx +++ b/src/plugins/navigation/public/top_nav_menu/top_nav_menu.test.tsx @@ -14,16 +14,9 @@ import { MountPoint } from '@kbn/core/public'; import { TopNavMenu } from './top_nav_menu'; import { TopNavMenuData } from './top_nav_menu_data'; import { findTestSubject, mountWithIntl } from '@kbn/test-jest-helpers'; -import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import { EuiToolTipProps } from '@elastic/eui'; import type { TopNavMenuBadgeProps } from './top_nav_menu_badges'; - -const unifiedSearch = { - ui: { - SearchBar: () =>
    , - AggregateQuerySearchBar: () =>
    , - }, -} as unknown as UnifiedSearchPublicPluginStart; +import { unifiedSearchMock } from '../mocks'; describe('TopNavMenu', () => { const WRAPPER_SELECTOR = '.kbnTopNavMenu__wrapper'; @@ -97,7 +90,7 @@ describe('TopNavMenu', () => { it('Should render search bar', () => { const component = mountWithIntl( - + ); expect(component.find(WRAPPER_SELECTOR).length).toBe(1); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); @@ -110,7 +103,7 @@ describe('TopNavMenu', () => { appName={'test'} config={menuItems} showSearchBar={true} - unifiedSearch={unifiedSearch} + unifiedSearch={unifiedSearchMock} /> ); expect(component.find(WRAPPER_SELECTOR).length).toBe(1); @@ -124,7 +117,7 @@ describe('TopNavMenu', () => { appName={'test'} config={menuItems} showSearchBar={true} - unifiedSearch={unifiedSearch} + unifiedSearch={unifiedSearchMock} className={'myCoolClass'} /> ); @@ -172,7 +165,7 @@ describe('TopNavMenu', () => { appName={'test'} config={menuItems} showSearchBar={true} - unifiedSearch={unifiedSearch} + unifiedSearch={unifiedSearchMock} setMenuMountPoint={setMountPoint} /> ); @@ -195,7 +188,7 @@ describe('TopNavMenu', () => { appName={'test'} badges={badges} showSearchBar={true} - unifiedSearch={unifiedSearch} + unifiedSearch={unifiedSearchMock} setMenuMountPoint={setMountPoint} /> ); diff --git a/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx b/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx index b29563713d36..7954a7f7dfc6 100644 --- a/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx +++ b/src/plugins/presentation_panel/public/panel_component/panel_header/presentation_panel_hover_actions.tsx @@ -393,7 +393,7 @@ export const PresentationPanelHoverActions = ({ notification.execute({ embeddable: api, trigger: panelNotificationTrigger }) } diff --git a/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx b/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx index b48a4eca7ae1..795fd6b566a9 100644 --- a/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx +++ b/src/plugins/presentation_panel/public/panel_component/panel_header/use_presentation_panel_header_actions.tsx @@ -167,7 +167,7 @@ export const usePresentationPanelHeaderActions = < notification.execute({ embeddable: api, trigger: panelNotificationTrigger }) } diff --git a/src/plugins/presentation_util/public/components/floating_actions/floating_actions.tsx b/src/plugins/presentation_util/public/components/floating_actions/floating_actions.tsx index 3c03e6571490..ade106ae1109 100644 --- a/src/plugins/presentation_util/public/components/floating_actions/floating_actions.tsx +++ b/src/plugins/presentation_util/public/components/floating_actions/floating_actions.tsx @@ -10,6 +10,7 @@ import classNames from 'classnames'; import React, { FC, ReactElement, useEffect, useState } from 'react'; import { v4 } from 'uuid'; +import { Subscription } from 'rxjs'; import { PANEL_HOVER_TRIGGER, @@ -19,7 +20,7 @@ import { } from '@kbn/embeddable-plugin/public'; import { apiHasUniqueId } from '@kbn/presentation-publishing'; import { Action } from '@kbn/ui-actions-plugin/public'; - +import { AnyApiAction } from '@kbn/presentation-panel-plugin/public/panel_actions/types'; import { uiActionsService } from '../../services/kibana_services'; import './floating_actions.scss'; @@ -33,6 +34,10 @@ export interface FloatingActionsProps { disabledActions?: EmbeddableInput['disabledActions']; } +export type FloatingActionItem = AnyApiAction & { + MenuItem: React.FC<{ context: unknown }>; +}; + export const FloatingActions: FC = ({ children, viewMode, @@ -41,59 +46,88 @@ export const FloatingActions: FC = ({ className = '', disabledActions, }) => { - const [floatingActions, setFloatingActions] = useState(undefined); + const [floatingActions, setFloatingActions] = useState([]); useEffect(() => { if (!api) return; - const getActions = async () => { - let mounted = true; - const context = { - embeddable: api, - trigger: panelHoverTrigger, - }; + let mounted = true; + const context = { + embeddable: api, + trigger: panelHoverTrigger, + }; + + const sortByOrder = (a: Action | FloatingActionItem, b: Action | FloatingActionItem) => { + return (a.order || 0) - (b.order || 0); + }; + + const getActions: () => Promise = async () => { const actions = ( await uiActionsService.getTriggerCompatibleActions(PANEL_HOVER_TRIGGER, context) ) - .filter((action): action is Action & { MenuItem: React.FC<{ context: unknown }> } => { + .filter((action) => { return action.MenuItem !== undefined && (disabledActions ?? []).indexOf(action.id) === -1; }) - .sort((a, b) => (a.order || 0) - (b.order || 0)); + .sort(sortByOrder); + return actions as FloatingActionItem[]; + }; + + const subscriptions = new Subscription(); + const handleActionCompatibilityChange = (isCompatible: boolean, action: Action) => { if (!mounted) return; - if (actions.length > 0) { - setFloatingActions( - <> - {actions.map((action) => - React.createElement(action.MenuItem, { - key: action.id, - context, - }) - )} - + setFloatingActions((currentActions) => { + const newActions: FloatingActionItem[] = currentActions + ?.filter((current) => current.id !== action.id) + .sort(sortByOrder) as FloatingActionItem[]; + if (isCompatible) { + return [action as FloatingActionItem, ...newActions]; + } + return newActions; + }); + }; + + (async () => { + const actions = await getActions(); + if (!mounted) return; + setFloatingActions(actions); + + const frequentlyChangingActions = uiActionsService.getFrequentlyChangingActionsForTrigger( + PANEL_HOVER_TRIGGER, + context + ); + + for (const action of frequentlyChangingActions) { + subscriptions.add( + action.subscribeToCompatibilityChanges(context, handleActionCompatibilityChange) ); - } else { - setFloatingActions(undefined); } - return () => { - mounted = false; - }; - }; + })(); - getActions(); + return () => { + mounted = false; + subscriptions.unsubscribe(); + }; }, [api, viewMode, disabledActions]); return (
    {children} - {isEnabled && floatingActions && ( + {isEnabled && floatingActions.length > 0 && (
    - {floatingActions} + <> + {floatingActions.map((action) => + React.createElement(action.MenuItem, { + key: action.id, + context: { embeddable: api }, + }) + )} +
    )}
    diff --git a/src/plugins/presentation_util/public/components/labs/environment_switch.tsx b/src/plugins/presentation_util/public/components/labs/environment_switch.tsx index 94e71fe432fc..d8727b4e2dba 100644 --- a/src/plugins/presentation_util/public/components/labs/environment_switch.tsx +++ b/src/plugins/presentation_util/public/components/labs/environment_switch.tsx @@ -44,13 +44,13 @@ export const EnvironmentSwitch = ({ env, isChecked, onChange, name }: Props) => const canSet = env === 'kibana' ? canSetAdvancedSettings : true; return ( - + @@ -63,7 +63,7 @@ export const EnvironmentSwitch = ({ env, isChecked, onChange, name }: Props) => compressed /> - + diff --git a/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx b/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx index 1d454050963d..8da1fe97455a 100644 --- a/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx +++ b/src/plugins/presentation_util/public/components/labs/labs_beaker_button.tsx @@ -34,7 +34,7 @@ export const LabsBeakerButton = ({ solutions, ...props }: Props) => { {overrideCount > 0 ? ( - + {overrideCount} ) : null} diff --git a/src/plugins/presentation_util/tsconfig.json b/src/plugins/presentation_util/tsconfig.json index 4e18f2e8bce2..a794829d9ba5 100644 --- a/src/plugins/presentation_util/tsconfig.json +++ b/src/plugins/presentation_util/tsconfig.json @@ -37,6 +37,7 @@ "@kbn/field-utils", "@kbn/presentation-publishing", "@kbn/core-ui-settings-browser", + "@kbn/presentation-panel-plugin", ], "exclude": ["target/**/*"] } diff --git a/src/plugins/saved_objects_finder/common/types.ts b/src/plugins/saved_objects_finder/common/types.ts index c451be83fd0e..a37a3abec1ff 100644 --- a/src/plugins/saved_objects_finder/common/types.ts +++ b/src/plugins/saved_objects_finder/common/types.ts @@ -14,4 +14,5 @@ export type SavedObjectCommon = S export interface FinderAttributes { title?: string; name?: string; + description?: string; } diff --git a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx index ace6f6a9d366..87482f4151fa 100644 --- a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx +++ b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.test.tsx @@ -41,17 +41,19 @@ describe('SavedObjectsFinder', () => { const doc = { id: '1', type: 'search', - attributes: { title: 'Example title' }, + attributes: { title: 'Example title', description: 'example description' }, }; const doc2 = { id: '2', type: 'search', - attributes: { title: 'Another title' }, + attributes: { title: 'Another title', description: 'another description' }, }; const doc3 = { type: 'vis', id: '3', attributes: { title: 'Vis' } }; + const doc4 = { type: 'search', id: '4', attributes: { title: 'Search' } }; + const searchMetaData = [ { type: 'search', @@ -234,6 +236,30 @@ describe('SavedObjectsFinder', () => { `); }); + + it('render description if provided', async () => { + (contentClient.mSearch as any as jest.SpyInstance).mockImplementation(() => + Promise.resolve({ hits: [doc, doc2, doc4] }) + ); + + const wrapper = shallow( + + ); + + wrapper.instance().componentDidMount!(); + await nextTick(); + expect( + wrapper + .find(EuiInMemoryTable) + .prop('items') + .filter((item: any) => item.attributes.description) + .map((item: any) => item.attributes.description) + ).toEqual([doc.attributes.description, doc2.attributes.description]); + }); }); describe('sorting', () => { diff --git a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx index 9ea3472e59d3..f9e74ca829fa 100644 --- a/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx +++ b/src/plugins/saved_objects_finder/public/finder/saved_object_finder.tsx @@ -146,7 +146,7 @@ class SavedObjectFinderUiClass extends React.Component< const savedObjects = response.hits .map((savedObject) => { const { - attributes: { name, title }, + attributes: { name, title, description }, } = savedObject; const titleToUse = typeof title === 'string' ? title : ''; const nameToUse = name ? name : titleToUse; @@ -156,6 +156,7 @@ class SavedObjectFinderUiClass extends React.Component< title: titleToUse, name: nameToUse, simple: savedObject, + description, }; }) .filter((savedObject) => { @@ -317,13 +318,23 @@ class SavedObjectFinderUiClass extends React.Component< ); const tooltipText = this.props.getTooltipText?.(item); - + const description = !!item.simple.attributes.description && ( + + {item.simple.attributes.description} + + ); return tooltipText ? ( - - {link} - + + + {link} + + {description} + ) : ( - link + + {link} + {description} + ); }, }, diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index 4e29f34dedb7..575f13b66b59 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -326,7 +326,7 @@ export class FlyoutClass extends Component< ), render: (list: any[]) => { return ( -
      +
        {take(list, 3).map((obj, key) => (
      • {obj.title}
      • ))} diff --git a/src/plugins/share/public/components/context/index.test.tsx b/src/plugins/share/public/components/context/index.test.tsx new file mode 100644 index 000000000000..162518e505b1 --- /dev/null +++ b/src/plugins/share/public/components/context/index.test.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { renderHook } from '@testing-library/react-hooks'; +import { useShareTabsContext } from '.'; + +describe('share menu context', () => { + describe('useShareTabsContext', () => { + it('throws an error if used outside of ShareMenuProvider tree', () => { + const { result } = renderHook(() => useShareTabsContext()); + + expect(result.error?.message).toEqual( + expect.stringContaining( + 'Failed to call `useShareTabsContext` because the context from ShareMenuProvider is missing.' + ) + ); + }); + }); +}); diff --git a/src/plugins/share/public/components/context/index.tsx b/src/plugins/share/public/components/context/index.tsx index b75df40aaa41..13d6138e42a6 100644 --- a/src/plugins/share/public/components/context/index.tsx +++ b/src/plugins/share/public/components/context/index.tsx @@ -9,7 +9,7 @@ import { ThemeServiceSetup } from '@kbn/core-theme-browser'; import { I18nStart } from '@kbn/core/public'; -import { createContext, useContext } from 'react'; +import React, { type PropsWithChildren, createContext, useContext } from 'react'; import { AnonymousAccessServiceContract } from '../../../common'; import type { @@ -35,6 +35,23 @@ export interface IShareContext extends ShareContext { anchorElement?: HTMLElement; } -export const ShareTabsContext = createContext(null); +const ShareTabsContext = createContext(null); -export const useShareTabsContext = () => useContext(ShareTabsContext); +export const ShareMenuProvider = ({ + shareContext, + children, +}: PropsWithChildren<{ shareContext: IShareContext }>) => { + return {children}; +}; + +export const useShareTabsContext = () => { + const context = useContext(ShareTabsContext); + + if (!context) { + throw new Error( + 'Failed to call `useShareTabsContext` because the context from ShareMenuProvider is missing. Ensure the component or React root is wrapped with ShareMenuProvider' + ); + } + + return context; +}; diff --git a/src/plugins/share/public/components/share_tabs.test.tsx b/src/plugins/share/public/components/share_tabs.test.tsx index b4ad92fce84f..6b04a28304fd 100644 --- a/src/plugins/share/public/components/share_tabs.test.tsx +++ b/src/plugins/share/public/components/share_tabs.test.tsx @@ -9,7 +9,7 @@ import React from 'react'; import { ShareMenuTabs } from './share_tabs'; -import { ShareTabsContext } from './context'; +import { ShareMenuProvider } from './context'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import { KibanaLocation, LocatorGetUrlParams, UrlService } from '../../common/url_service'; import { @@ -77,9 +77,9 @@ describe('Share modal tabs', () => { }, ]; const wrapper = mountWithIntl( - + - + ); expect(wrapper.find('[data-test-subj="export"]').exists()).toBeTruthy(); }); @@ -92,11 +92,13 @@ describe('Share modal tabs', () => { generateExportUrl: mockGenerateExportUrl, }, ]; + const wrapper = mountWithIntl( - + - + ); + expect(wrapper.find('[data-test-subj="export"]').exists()).toBeFalsy(); }); @@ -116,9 +118,9 @@ describe('Share modal tabs', () => { }, ]; const wrapper = mountWithIntl( - + - + ); expect(wrapper.find('[data-test-subj="export"]').exists()).toBeTruthy(); }); diff --git a/src/plugins/share/public/components/share_tabs.tsx b/src/plugins/share/public/components/share_tabs.tsx index 0ed540a61200..94c4ab8655dc 100644 --- a/src/plugins/share/public/components/share_tabs.tsx +++ b/src/plugins/share/public/components/share_tabs.tsx @@ -8,16 +8,16 @@ */ import React, { type FC } from 'react'; -import { TabbedModal } from '@kbn/shared-ux-tabbed-modal'; +import { TabbedModal, type IModalTabDeclaration } from '@kbn/shared-ux-tabbed-modal'; -import { ShareTabsContext, useShareTabsContext, type IShareContext } from './context'; +import { ShareMenuProvider, useShareTabsContext, type IShareContext } from './context'; import { linkTab, embedTab, exportTab } from './tabs'; export const ShareMenu: FC<{ shareContext: IShareContext }> = ({ shareContext }) => { return ( - + - + ); }; @@ -25,15 +25,9 @@ export const ShareMenu: FC<{ shareContext: IShareContext }> = ({ shareContext }) export const ShareMenuTabs = () => { const shareContext = useShareTabsContext(); - if (!shareContext) { - return null; - } - const { allowEmbed, objectTypeMeta, onClose, shareMenuItems, anchorElement } = shareContext; - const tabs = []; - - tabs.push(linkTab); + const tabs: Array> = [linkTab]; const enabledItems = shareMenuItems.filter(({ shareMenuItem }) => !shareMenuItem?.disabled); diff --git a/src/plugins/share/public/components/tabs/link/link_content.test.tsx b/src/plugins/share/public/components/tabs/link/link_content.test.tsx new file mode 100644 index 000000000000..77fac4afc8ce --- /dev/null +++ b/src/plugins/share/public/components/tabs/link/link_content.test.tsx @@ -0,0 +1,191 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import React, { type ComponentProps } from 'react'; +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; +import userEvent from '@testing-library/user-event'; +import { render, screen, waitFor } from '@testing-library/react'; + +import { urlServiceTestSetup } from '../../../../common/url_service/__tests__/setup'; +import { MockLocatorDefinition } from '../../../../common/url_service/mocks'; +import { BrowserShortUrlClientFactory } from '../../../url_service/short_urls/short_url_client_factory'; +import { + BrowserShortUrlClientHttp, + BrowserShortUrlClient, +} from '../../../url_service/short_urls/short_url_client'; +import { BrowserUrlService } from '../../../types'; +import { LinkContent } from './link_content'; + +const renderComponent = (props: ComponentProps) => { + render( + + + + ); +}; + +describe('LinkContent', () => { + const shareableUrl = 'http://localhost:5601/app/dashboards#/view/123'; + + const http: BrowserShortUrlClientHttp = { + basePath: { + get: () => '/xyz', + }, + fetch: jest.fn(async () => { + return {} as any; + }), + }; + + let urlService: BrowserUrlService; + + // @ts-expect-error there is a type because we override the shortUrls implementation + // eslint-disable-next-line prefer-const + ({ service: urlService } = urlServiceTestSetup({ + shortUrls: ({ locators }) => + new BrowserShortUrlClientFactory({ + http, + locators, + }), + })); + + beforeAll(() => { + Object.defineProperty(document, 'execCommand', { + value: jest.fn(() => true), + }); + }); + + it('uses the delegatedShareUrlHandler to generate the shareable URL when it is provided', async () => { + const user = userEvent.setup(); + const objectType = 'dashboard'; + const objectId = '123'; + const isDirty = false; + + const delegatedShareUrlHandler = jest.fn(); + + renderComponent({ + objectType, + objectId, + isDirty, + shareableUrl, + urlService, + allowShortUrl: true, + delegatedShareUrlHandler, + }); + + await user.click(screen.getByTestId('copyShareUrlButton')); + + expect(delegatedShareUrlHandler).toHaveBeenCalled(); + }); + + it('returns the shareable URL when the delegatedShareUrlHandler is not provided and shortURLs are not allowed', async () => { + const user = userEvent.setup(); + const objectType = 'dashboard'; + const objectId = '123'; + const isDirty = false; + + renderComponent({ + objectType, + objectId, + isDirty, + shareableUrl, + urlService, + allowShortUrl: false, + }); + + const copyButton = screen.getByTestId('copyShareUrlButton'); + + await user.click(copyButton); + + waitFor(() => { + expect(copyButton.getAttribute('data-share-url')).toBe(shareableUrl); + }); + }); + + it('invokes the createWithLocator method on the shortURL service if a locator is present when the copy button is clicked', async () => { + const user = userEvent.setup(); + const objectType = 'dashboard'; + const objectId = '123'; + const isDirty = false; + const shareableUrlLocatorParams = { + locator: new MockLocatorDefinition('TEST_LOCATOR'), + params: {}, + }; + + const shortURL = 'http://localhost:5601/xyz/r/s/yellow-orange-tomato'; + + const createWithLocatorSpy = jest.spyOn(BrowserShortUrlClient.prototype, 'createWithLocator'); + + createWithLocatorSpy.mockResolvedValue({ + // @ts-expect-error we only return locator property, as that's all we need for this test + locator: { + getUrl: jest.fn(() => Promise.resolve(shortURL)), + }, + }); + + renderComponent({ + objectType, + objectId, + isDirty, + shareableUrl, + urlService, + allowShortUrl: true, + // @ts-ignore this locator is passed mainly to test the code path that invokes createWithLocator + shareableUrlLocatorParams, + }); + + const copyButton = screen.getByTestId('copyShareUrlButton'); + + const numberOfClicks = 4; + + for (const _click of Array.from({ length: numberOfClicks })) { + await user.click(copyButton); + } + + // should only invoke once no matter how many times the button is clicked + expect(createWithLocatorSpy).toHaveBeenCalledTimes(1); + expect(copyButton.getAttribute('data-share-url')).toBe(shortURL); + }); + + it('invokes the createFromLongUrl method on the shortURL service if a locator is not present when the copy button is clicked', async () => { + const user = userEvent.setup(); + const objectType = 'dashboard'; + const objectId = '123'; + const isDirty = false; + + const shortURL = 'http://localhost:5601/xyz/r/s/yellow-orange-tomato'; + + const createFromLongUrlSpy = jest.spyOn(BrowserShortUrlClient.prototype, 'createFromLongUrl'); + + // @ts-expect-error we only return url property, as that's all we need for this test + createFromLongUrlSpy.mockResolvedValue({ + url: shortURL, + }); + + renderComponent({ + objectType, + objectId, + isDirty, + shareableUrl, + urlService, + allowShortUrl: true, + }); + + const copyButton = screen.getByTestId('copyShareUrlButton'); + + const numberOfClicks = 4; + + for (const _click of Array.from({ length: numberOfClicks })) { + await user.click(copyButton); + } + + // should only invoke once no matter how many times the button is clicked + expect(createFromLongUrlSpy).toHaveBeenCalledTimes(1); + expect(copyButton.getAttribute('data-share-url')).toBe(shortURL); + }); +}); diff --git a/src/plugins/share/public/components/tabs/link/link_content.tsx b/src/plugins/share/public/components/tabs/link/link_content.tsx index 0871599a524b..6c0d8e6e988e 100644 --- a/src/plugins/share/public/components/tabs/link/link_content.tsx +++ b/src/plugins/share/public/components/tabs/link/link_content.tsx @@ -20,8 +20,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import React, { useCallback, useMemo, useState } from 'react'; -import { IShareContext } from '../../context'; +import React, { useCallback, useState, useRef, useEffect } from 'react'; +import type { IShareContext } from '../../context'; type LinkProps = Pick< IShareContext, @@ -42,87 +42,80 @@ interface UrlParams { } export const LinkContent = ({ - objectType, isDirty, + objectType, shareableUrl, urlService, shareableUrlLocatorParams, allowShortUrl, delegatedShareUrlHandler, }: LinkProps) => { - const [url, setUrl] = useState(''); - const [urlParams] = useState(undefined); + const [snapshotUrl, setSnapshotUrl] = useState(''); const [isTextCopied, setTextCopied] = useState(false); - const [shortUrlCache, setShortUrlCache] = useState(undefined); const [isLoading, setIsLoading] = useState(false); + const urlParamsRef = useRef(undefined); + const urlToCopy = useRef(undefined); + const copiedTextToolTipCleanupIdRef = useRef>(); - const getUrlWithUpdatedParams = useCallback( - (tempUrl: string): string => { - const urlWithUpdatedParams = urlParams - ? Object.keys(urlParams).reduce((urlAccumulator, key) => { - const urlParam = urlParams[key]; - return urlParam - ? Object.keys(urlParam).reduce((queryAccumulator, queryParam) => { - const isQueryParamEnabled = urlParam[queryParam]; - return isQueryParamEnabled - ? queryAccumulator + `&${queryParam}=true` - : queryAccumulator; - }, urlAccumulator) - : urlAccumulator; - }, tempUrl) - : tempUrl; + const getUrlWithUpdatedParams = useCallback((tempUrl: string): string => { + const urlWithUpdatedParams = urlParamsRef.current + ? Object.keys(urlParamsRef.current).reduce((urlAccumulator, key) => { + const urlParam = urlParamsRef.current?.[key]; + return urlParam + ? Object.keys(urlParam).reduce((queryAccumulator, queryParam) => { + const isQueryParamEnabled = urlParam[queryParam]; + return isQueryParamEnabled + ? queryAccumulator + `&${queryParam}=true` + : queryAccumulator; + }, urlAccumulator) + : urlAccumulator; + }, tempUrl) + : tempUrl; - // persist updated url to state - setUrl(urlWithUpdatedParams); - return urlWithUpdatedParams; - }, - [urlParams] - ); + return urlWithUpdatedParams; + }, []); - const getSnapshotUrl = useCallback(() => { - return getUrlWithUpdatedParams(shareableUrl || window.location.href); + useEffect(() => { + setSnapshotUrl(getUrlWithUpdatedParams(shareableUrl || window.location.href)); }, [getUrlWithUpdatedParams, shareableUrl]); const createShortUrl = useCallback(async () => { + const shortUrlService = urlService.shortUrls.get(null); + if (shareableUrlLocatorParams) { - const shortUrls = urlService.shortUrls.get(null); - const shortUrl = await shortUrls.createWithLocator(shareableUrlLocatorParams); - const urlWithLoc = await shortUrl.locator.getUrl(shortUrl.params, { absolute: true }); - setShortUrlCache(urlWithLoc); - return urlWithLoc; + const shortUrl = await shortUrlService.createWithLocator(shareableUrlLocatorParams); + return shortUrl.locator.getUrl(shortUrl.params, { absolute: true }); } else { - const snapshotUrl = getSnapshotUrl(); - const shortUrl = await urlService.shortUrls.get(null).createFromLongUrl(snapshotUrl); - setShortUrlCache(shortUrl.url); - - return shortUrl.url; + return (await shortUrlService.createFromLongUrl(snapshotUrl)).url; } - }, [shareableUrlLocatorParams, urlService.shortUrls, getSnapshotUrl, setShortUrlCache]); + }, [shareableUrlLocatorParams, urlService.shortUrls, snapshotUrl]); const copyUrlHelper = useCallback(async () => { setIsLoading(true); - let urlToCopy = url; - if (!urlToCopy || delegatedShareUrlHandler) { - urlToCopy = delegatedShareUrlHandler - ? delegatedShareUrlHandler?.() + if (!urlToCopy.current) { + urlToCopy.current = delegatedShareUrlHandler + ? delegatedShareUrlHandler() : allowShortUrl ? await createShortUrl() - : getSnapshotUrl(); + : snapshotUrl; } - copyToClipboard(urlToCopy); - setUrl(urlToCopy); - setTextCopied(true); + copyToClipboard(urlToCopy.current); + setTextCopied(() => { + if (copiedTextToolTipCleanupIdRef.current) { + clearInterval(copiedTextToolTipCleanupIdRef.current); + } + + // set up timer to revert copied state to false after specified duration + copiedTextToolTipCleanupIdRef.current = setTimeout(() => setTextCopied(false), 1000); + + // set copied state to true for now + return true; + }); setIsLoading(false); - return urlToCopy; - }, [url, delegatedShareUrlHandler, allowShortUrl, createShortUrl, getSnapshotUrl]); + }, [snapshotUrl, delegatedShareUrlHandler, allowShortUrl, createShortUrl]); - const handleTestUrl = useMemo(() => { - if (objectType !== 'search' || !allowShortUrl) return getSnapshotUrl(); - else if (objectType === 'search' && allowShortUrl) return shortUrlCache; - return copyUrlHelper(); - }, [objectType, getSnapshotUrl, allowShortUrl, shortUrlCache, copyUrlHelper]); return ( <> @@ -157,14 +150,14 @@ export const LinkContent = ({ (objectType === 'lens' && isDirty ? null : setTextCopied(false))} onClick={copyUrlHelper} color={objectType === 'lens' && isDirty ? 'warning' : 'primary'} diff --git a/src/plugins/telemetry/schema/README.md b/src/plugins/telemetry/schema/README.md index fb02d5fc49af..38212d73c259 100644 --- a/src/plugins/telemetry/schema/README.md +++ b/src/plugins/telemetry/schema/README.md @@ -2,16 +2,18 @@ This list of `.json` files describes the format of the payloads sent to the Remote Telemetry Service. All the files should follow the schema convention as defined in the `usage_collection` plugin and `@kbn/telemetry-tools`, with the addition of the type `pass_through`. This additional `type` indicates Kibana sends the payload as-is from the output of an external ES query. -There are currently 2 files: +There are currently 4 files: - `oss_root.json`: Defines the schema for the payload from the root keys. Manually maintained for now because the frequency it changes should be pretty low. - `oss_plugins.json`: The schema for the content that will be nested in `stack_stats.kibana.plugins`. It is automatically generated by `@kbn/telemetry-tools` based on the `schema` property provided by all the registered Usage Collectors via the `usageCollection.makeUsageCollector` API. More details in the [Schema field](../../usage_collection/README.md#schema-field) chapter in the UsageCollection's docs. +- `kbn_packages.json`: Same as `oss_plugins` but for collectors defined in `/packages/*`. +- `oss_platform.json`: Same as `oss_plugins` but for collectors defined in `/src/platform/*`. NOTE: Despite its similarities to ES mappings, the intention of these files is not to define any index mappings. They should be considered as a tool to understand the format of the payload that will be sent when reporting telemetry to the Remote Service. ## Testing -Functional tests are defined at `test/api_integration/apis/telemetry/telemetry_local.ts`. They merge both files, and validates the actual output of the telemetry endpoint against the final schema. \ No newline at end of file +Functional tests are defined at `x-pack/test/api_integration/apis/telemetry/telemetry_local.ts`. They merge all files and [the x-pack counterparts](../../../../x-pack/plugins/telemetry_collection_xpack/schema), and validates the actual output of the telemetry endpoint against the final schema. \ No newline at end of file diff --git a/src/plugins/telemetry/schema/oss_platform.json b/src/plugins/telemetry/schema/oss_platform.json new file mode 100644 index 000000000000..d5b0514b6491 --- /dev/null +++ b/src/plugins/telemetry/schema/oss_platform.json @@ -0,0 +1,3 @@ +{ + "properties": {} +} diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json index 44fcda4f2858..35e0242b5762 100644 --- a/src/plugins/telemetry/schema/oss_plugins.json +++ b/src/plugins/telemetry/schema/oss_plugins.json @@ -7731,6 +7731,137 @@ } } }, + "streams": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "Always `main`" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen over the last 90 days" + } + }, + "views": { + "type": "array", + "items": { + "properties": { + "appId": { + "type": "keyword", + "_meta": { + "description": "The application being tracked" + } + }, + "viewId": { + "type": "keyword", + "_meta": { + "description": "The application view being tracked" + } + }, + "clicks_total": { + "type": "long", + "_meta": { + "description": "General number of clicks in the application sub view since we started counting them" + } + }, + "clicks_7_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 7 days" + } + }, + "clicks_30_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 30 days" + } + }, + "clicks_90_days": { + "type": "long", + "_meta": { + "description": "General number of clicks in the active application sub view over the last 90 days" + } + }, + "minutes_on_screen_total": { + "type": "float", + "_meta": { + "description": "Minutes the application sub view is active and on-screen since we started counting them." + } + }, + "minutes_on_screen_7_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 7 days" + } + }, + "minutes_on_screen_30_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 30 days" + } + }, + "minutes_on_screen_90_days": { + "type": "float", + "_meta": { + "description": "Minutes the application is active and on-screen active application sub view over the last 90 days" + } + } + } + } + } + } + }, "uptime": { "properties": { "appId": { @@ -10361,12 +10492,6 @@ "description": "Non-default value of setting." } }, - "truncate:maxHeight": { - "type": "long", - "_meta": { - "description": "Non-default value of setting." - } - }, "timepicker:timeDefaults": { "type": "keyword", "_meta": { @@ -10634,12 +10759,6 @@ "description": "Non-default value of setting." } }, - "doc_table:legacy": { - "type": "boolean", - "_meta": { - "description": "Non-default value of setting." - } - }, "discover:modifyColumnsOnSwitch": { "type": "boolean", "_meta": { diff --git a/src/plugins/telemetry/server/fetcher.ts b/src/plugins/telemetry/server/fetcher.ts index 445f780c07c5..82db03ed08ed 100644 --- a/src/plugins/telemetry/server/fetcher.ts +++ b/src/plugins/telemetry/server/fetcher.ts @@ -29,9 +29,8 @@ import type { TelemetryCollectionManagerPluginStart } from '@kbn/telemetry-colle import { type PluginInitializerContext, type Logger, - type SavedObjectsClientContract, - SavedObjectsClient, type CoreStart, + type ISavedObjectsRepository, } from '@kbn/core/server'; import { getTelemetryChannelEndpoint } from '../common/telemetry_config'; import { @@ -77,7 +76,7 @@ export class FetcherTask { private readonly subscriptions = new Subscription(); private readonly isOnline$ = new BehaviorSubject(false); // Let's initially assume we are not online private readonly lastReported$ = new BehaviorSubject(0); - private internalRepository?: SavedObjectsClientContract; + private internalRepository?: ISavedObjectsRepository; private telemetryCollectionManager?: TelemetryCollectionManagerPluginStart; constructor(initializerContext: PluginInitializerContext) { @@ -87,9 +86,7 @@ export class FetcherTask { } public start({ savedObjects }: CoreStart, { telemetryCollectionManager }: FetcherTaskDepsStart) { - this.internalRepository = new SavedObjectsClient( - savedObjects.createInternalRepository([TELEMETRY_SAVED_OBJECT_TYPE]) - ); + this.internalRepository = savedObjects.createInternalRepository([TELEMETRY_SAVED_OBJECT_TYPE]); this.telemetryCollectionManager = telemetryCollectionManager; this.subscriptions.add(this.validateConnectivity()); diff --git a/src/plugins/telemetry/tsconfig.json b/src/plugins/telemetry/tsconfig.json index a8538b4a0b18..c23b4fea26b8 100644 --- a/src/plugins/telemetry/tsconfig.json +++ b/src/plugins/telemetry/tsconfig.json @@ -9,9 +9,7 @@ "server/**/**/*", "common/**/*", "../../../typings/**/*", - "schema/oss_plugins.json", - "schema/oss_root.json", - "schema/kbn_packages.json" + "schema/*.json", ], "kbn_references": [ "@kbn/core", diff --git a/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx b/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx index db3a0b884542..009016a63a90 100644 --- a/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx +++ b/src/plugins/ui_actions_enhanced/public/components/action_wizard/action_wizard.tsx @@ -187,7 +187,7 @@ const TriggerPicker: React.FC = ({ ), }} - style={{ maxWidth: `80%` }} + css={{ maxWidth: `80%` }} > {triggers.map((trigger) => ( diff --git a/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx b/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx index cfe7784ec99f..7b48712ff7d6 100644 --- a/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx +++ b/src/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx @@ -263,7 +263,7 @@ export function Demo({ getTriggerInfo={mockGetTriggerInfo} triggers={[VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER, SELECT_RANGE_TRIGGER]} /> -
        +

        Action Factory Id: {state.currentActionFactory?.id}
        Action Factory Config: {JSON.stringify(state.config)}
        diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx index 1859067212cb..17c9aa98aa6e 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_table/drilldown_table.tsx @@ -81,7 +81,7 @@ export const DrilldownTable: React.FC = ({ title={drilldown.error} aria-label={drilldown.error} data-test-subj={`drilldownError-${drilldown.id}`} - style={{ marginLeft: '4px' }} /* a bit of spacing from text */ + css={{ marginLeft: '4px' }} /* a bit of spacing from text */ /> )} diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx index c918dbdef215..cb23fa2d576d 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/drilldown_template_table/drilldown_template_table.tsx @@ -58,8 +58,8 @@ export const DrilldownTemplateTable: React.FC = ({ name: txtNameColumnTitle, sortable: true, render: (omit, item: DrilldownTemplateTableItem) => ( -
        -
        {item.name}
        +
        +
        {item.name}
        {item.description} diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx index 246cf5d7362b..23633a52be35 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/flyout_frame/flyout_frame.tsx @@ -45,7 +45,7 @@ export const FlyoutFrame: FC> = ({ {onBack && ( -
        +
        > = ({ )} {!!children && ( - + {tooltip ? ( {children} diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx index 35bdcbe4d2c9..1c4653b3e863 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/drilldown_manager/components/trigger_picker/trigger_picker.tsx @@ -74,7 +74,7 @@ export const TriggerPicker: React.FC = ({ ), }} - style={{ maxWidth: `80%` }} + css={{ maxWidth: `80%` }} > {items.map((trigger) => ( data-test-subj="urlDrilldownAdditionalOptions" > - + { diff --git a/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx b/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx index 656ff07623dc..e30896988142 100644 --- a/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx +++ b/src/plugins/ui_actions_enhanced/public/drilldowns/url_drilldown/components/variable_popover/index.tsx @@ -74,7 +74,7 @@ export const VariablePopover: React.FC = ({ variables, onSelect, variable }} > {(list, search) => ( -
        +
        {search} {list} {variablesHelpLink && ( diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx index 5e97ff9cc55d..a3f70c2badc0 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.test.tsx @@ -32,31 +32,17 @@ describe('getHeight', () => { test('when using document explorer, returning the available height in the flyout', () => { const monacoMock = getMonacoMock(500, 0); - const height = getHeight(monacoMock, true, DEFAULT_MARGIN_BOTTOM); + const height = getHeight(monacoMock, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(484); - const heightCustom = getHeight(monacoMock, true, 80); + const heightCustom = getHeight(monacoMock, 80); expect(heightCustom).toBe(420); }); test('when using document explorer, returning the available height in the flyout has a minimun guarenteed height', () => { const monacoMock = getMonacoMock(500); - const height = getHeight(monacoMock, true, DEFAULT_MARGIN_BOTTOM); + const height = getHeight(monacoMock, DEFAULT_MARGIN_BOTTOM); expect(height).toBe(400); }); - - test('when using classic table, its displayed inline without scrolling', () => { - const monacoMock = getMonacoMock(100); - - const height = getHeight(monacoMock, false, DEFAULT_MARGIN_BOTTOM); - expect(height).toBe(1020); - }); - - test('when using classic table, limited height > 500 lines to allow scrolling', () => { - const monacoMock = getMonacoMock(1000); - - const height = getHeight(monacoMock, false, DEFAULT_MARGIN_BOTTOM); - expect(height).toBe(5020); - }); }); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx index 514c994e5d42..68619b604833 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/get_height.tsx @@ -8,7 +8,7 @@ */ import { monaco } from '@kbn/monaco'; -import { MAX_LINES_CLASSIC_TABLE, MIN_HEIGHT } from './source'; +import { MIN_HEIGHT } from './source'; // Displayed margin of the tab content to the window bottom export const DEFAULT_MARGIN_BOTTOM = 16; @@ -28,7 +28,6 @@ export function getTabContentAvailableHeight( export function getHeight( editor: monaco.editor.IStandaloneCodeEditor, - useDocExplorer: boolean, decreaseAvailableHeightBy: number ) { const editorElement = editor?.getDomNode(); @@ -36,17 +35,6 @@ export function getHeight( return 0; } - let result; - if (useDocExplorer) { - result = getTabContentAvailableHeight(editorElement, decreaseAvailableHeightBy); - } else { - // takes care of the classic table, display a maximum of 500 lines - // why not display it all? Due to performance issues when the browser needs to render it all - const lineHeight = editor.getOption(monaco.editor.EditorOption.lineHeight); - const lineCount = editor.getModel()?.getLineCount() || 1; - const displayedLineCount = - lineCount > MAX_LINES_CLASSIC_TABLE ? MAX_LINES_CLASSIC_TABLE : lineCount; - result = editor.getTopForLineNumber(displayedLineCount + 1) + lineHeight; - } + const result = getTabContentAvailableHeight(editorElement, decreaseAvailableHeightBy); return Math.max(result, MIN_HEIGHT); } diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx index 5b4ba36cd03f..3bd1137cabcc 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_source/source.tsx @@ -17,7 +17,7 @@ import { i18n } from '@kbn/i18n'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { DataTableRecord } from '@kbn/discover-utils/types'; import { ElasticRequestState } from '@kbn/unified-doc-viewer'; -import { isLegacyTableEnabled, SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; +import { SEARCH_FIELDS_FROM_SOURCE } from '@kbn/discover-utils'; import { omit } from 'lodash'; import { getUnifiedDocViewerServices } from '../../plugin'; import { useEsDocSearch } from '../../hooks'; @@ -36,9 +36,6 @@ interface SourceViewerProps { onRefresh: () => void; } -// Ihe number of lines displayed without scrolling used for classic table, which renders the component -// inline limitation was necessary to enable virtualized scrolling, which improves performance -export const MAX_LINES_CLASSIC_TABLE = 500; // Minimum height for the source content to guarantee minimum space when the flyout is scrollable. export const MIN_HEIGHT = 400; @@ -57,10 +54,6 @@ export const DocViewerSource = ({ const [jsonValue, setJsonValue] = useState(''); const { uiSettings } = getUnifiedDocViewerServices(); const useNewFieldsApi = !uiSettings.get(SEARCH_FIELDS_FROM_SOURCE); - const useDocExplorer = !isLegacyTableEnabled({ - uiSettings, - isEsqlMode: Array.isArray(textBasedHits), - }); const [requestState, hit] = useEsDocSearch({ id, index, @@ -75,9 +68,7 @@ export const DocViewerSource = ({ } }, [requestState, hit]); - // setting editor height - // - classic view: based on lines height and count to stretch and fit its content - // - explorer: to fill the available space of the document flyout + // setting editor height to fill the available space of the document flyout useEffect(() => { if (!editor) { return; @@ -88,11 +79,7 @@ export const DocViewerSource = ({ return; } - const height = getHeight( - editor, - useDocExplorer, - decreaseAvailableHeightBy ?? DEFAULT_MARGIN_BOTTOM - ); + const height = getHeight(editor, decreaseAvailableHeightBy ?? DEFAULT_MARGIN_BOTTOM); if (height === 0) { return; } @@ -102,7 +89,7 @@ export const DocViewerSource = ({ } else { setEditorHeight(height); } - }, [editor, jsonValue, useDocExplorer, setEditorHeight, decreaseAvailableHeightBy]); + }, [editor, jsonValue, setEditorHeight, decreaseAvailableHeightBy]); const loadingState = (
        diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx deleted file mode 100644 index 43f2d21eb8fd..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.test.tsx +++ /dev/null @@ -1,452 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { findTestSubject } from '@elastic/eui/lib/test'; -import { DocViewerLegacyTable } from './table'; -import type { DataView } from '@kbn/data-views-plugin/public'; -import type { DocViewRenderProps } from '@kbn/unified-doc-viewer/types'; -import { buildDataTableRecord } from '@kbn/discover-utils'; -import { setUnifiedDocViewerServices } from '../../../plugin'; -import type { UnifiedDocViewerServices } from '../../../types'; - -const services = { - uiSettings: { - get: (key: string) => { - if (key === 'discover:showMultiFields') { - return true; - } - }, - }, - fieldFormats: { - getDefaultInstance: jest.fn(() => ({ convert: (value: unknown) => value })), - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - }, -}; - -const dataView = { - fields: { - getAll: () => [ - { - name: '_index', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'message', - type: 'string', - scripted: false, - filterable: false, - }, - { - name: 'extension', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'bytes', - type: 'number', - scripted: false, - filterable: true, - }, - { - name: 'scripted', - type: 'number', - scripted: true, - filterable: false, - }, - ], - }, - metaFields: ['_index', '_score'], - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), -} as unknown as DataView; - -dataView.fields.getByName = (name: string) => { - return dataView.fields.getAll().find((field) => field.name === name); -}; - -const mountComponent = ( - props: DocViewRenderProps, - overrides?: Partial -) => { - setUnifiedDocViewerServices({ ...services, ...overrides } as UnifiedDocViewerServices); - return mountWithIntl(); -}; - -describe('DocViewTable at Discover', () => { - // At Discover's main view, all buttons are rendered - // check for existence of action buttons and warnings - - const hit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _id: 'id123', - _score: 1, - _source: { - message: - 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ - Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus \ - et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, \ - ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. \ - Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, \ - rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. \ - Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \ - Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut', - extension: 'html', - not_mapped: 'yes', - bytes: 100, - objectArray: [{ foo: true }], - relatedContent: { - test: 1, - }, - scripted: 123, - _underscore: 123, - }, - }, - dataView - ); - - const props = { - hit, - columns: ['extension'], - dataView, - filter: jest.fn(), - onAddColumn: jest.fn(), - onRemoveColumn: jest.fn(), - }; - const component = mountComponent(props); - [ - { - _property: '_index', - addInclusiveFilterButton: true, - noMappingWarning: false, - toggleColumnButton: true, - underscoreWarning: false, - }, - { - _property: 'message', - addInclusiveFilterButton: false, - noMappingWarning: false, - toggleColumnButton: true, - underscoreWarning: false, - }, - { - _property: '_underscore', - addInclusiveFilterButton: false, - noMappingWarning: false, - toggleColumnButton: true, - underScoreWarning: true, - }, - { - _property: 'scripted', - addInclusiveFilterButton: false, - noMappingWarning: false, - toggleColumnButton: true, - underScoreWarning: false, - }, - { - _property: 'not_mapped', - addInclusiveFilterButton: false, - noMappingWarning: true, - toggleColumnButton: true, - underScoreWarning: false, - }, - ].forEach((check) => { - const rowComponent = findTestSubject(component, `tableDocViewRow-${check._property}`); - - it(`renders row for ${check._property}`, () => { - expect(rowComponent.length).toBe(1); - }); - - (['addInclusiveFilterButton', 'toggleColumnButton', 'underscoreWarning'] as const).forEach( - (element) => { - const elementExist = check[element]; - - if (typeof elementExist === 'boolean') { - const btn = findTestSubject(rowComponent, element, '^='); - - it(`renders ${element} for '${check._property}' correctly`, () => { - const disabled = btn.length ? btn.props().disabled : true; - const clickAble = btn.length && !disabled ? true : false; - expect(clickAble).toBe(elementExist); - }); - } - } - ); - }); -}); - -describe('DocViewTable at Discover Context', () => { - // here no toggleColumnButtons are rendered - const hit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _id: 'id123', - _score: 1, - _source: { - message: - 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. \ - Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus \ - et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, \ - ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. \ - Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, \ - rhoncus ut, imperdiet a, venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. \ - Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. \ - Phasellus ullamcorper ipsum rutrum nunc. Nunc nonummy metus. Vestibulum volutpat pretium libero. Cras id dui. Aenean ut', - }, - }, - dataView - ); - const props = { - hit, - columns: ['extension'], - dataView, - filter: jest.fn(), - }; - - const component = mountComponent(props); - - it(`renders no toggleColumnButton`, () => { - const foundLength = findTestSubject(component, 'toggleColumnButtons').length; - expect(foundLength).toBe(0); - }); - - it(`renders addInclusiveFilterButton`, () => { - const row = findTestSubject(component, `tableDocViewRow-_index`); - const btn = findTestSubject(row, 'addInclusiveFilterButton'); - expect(btn.length).toBe(1); - btn.simulate('click'); - expect(props.filter).toBeCalled(); - }); -}); - -describe('DocViewTable at Discover Doc', () => { - const hit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _score: 1, - _id: 'id123', - _source: { - extension: 'html', - not_mapped: 'yes', - }, - }, - dataView - ); - // here no action buttons are rendered - const props = { - hit, - dataView, - hideActionsColumn: true, - }; - const component = mountComponent(props); - const foundLength = findTestSubject(component, 'addInclusiveFilterButton').length; - - it(`renders no action buttons`, () => { - expect(foundLength).toBe(0); - }); -}); - -describe('DocViewTable at Discover Doc with Fields API', () => { - const dataViewCommerce = { - fields: { - getAll: () => [ - { - name: '_index', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'category', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'category.keyword', - displayName: 'category.keyword', - type: 'string', - scripted: false, - filterable: true, - spec: { - subType: { - multi: { - parent: 'category', - }, - }, - }, - }, - { - name: 'customer_first_name', - type: 'string', - scripted: false, - filterable: true, - }, - { - name: 'customer_first_name.keyword', - displayName: 'customer_first_name.keyword', - type: 'string', - scripted: false, - filterable: false, - spec: { - subType: { - multi: { - parent: 'customer_first_name', - }, - }, - }, - }, - { - name: 'customer_first_name.nickname', - displayName: 'customer_first_name.nickname', - type: 'string', - scripted: false, - filterable: false, - spec: { - subType: { - multi: { - parent: 'customer_first_name', - }, - }, - }, - }, - { - name: 'city', - displayName: 'city', - type: 'keyword', - isMapped: true, - readFromDocValues: true, - searchable: true, - shortDotsEnable: false, - scripted: false, - filterable: false, - }, - { - name: 'city.raw', - displayName: 'city.raw', - type: 'string', - isMapped: true, - spec: { - subType: { - multi: { - parent: 'city', - }, - }, - }, - shortDotsEnable: false, - scripted: false, - filterable: false, - }, - ], - }, - metaFields: ['_index', '_type', '_score', '_id'], - getFormatterForField: jest.fn(() => ({ convert: (value: unknown) => value })), - } as unknown as DataView; - - dataViewCommerce.fields.getByName = (name: string) => { - return dataViewCommerce.fields.getAll().find((field) => field.name === name); - }; - - const fieldsHit = buildDataTableRecord( - { - _index: 'logstash-2014.09.09', - _id: 'id123', - _score: 1.0, - fields: { - category: "Women's Clothing", - 'category.keyword': "Women's Clothing", - customer_first_name: 'Betty', - 'customer_first_name.keyword': 'Betty', - 'customer_first_name.nickname': 'Betsy', - 'city.raw': 'Los Angeles', - }, - }, - dataView - ); - const props = { - hit: fieldsHit, - columns: ['Document'], - dataView: dataViewCommerce, - filter: jest.fn(), - onAddColumn: jest.fn(), - onRemoveColumn: jest.fn(), - }; - - it('renders multifield rows if showMultiFields flag is set', () => { - const component = mountComponent(props); - - const categoryKeywordRow = findTestSubject(component, 'tableDocViewRow-category.keyword'); - expect(categoryKeywordRow.length).toBe(1); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword').length).toBe( - 1 - ); - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname').length).toBe( - 1 - ); - - expect( - findTestSubject(component, 'tableDocViewRow-category.keyword-multifieldBadge').length - ).toBe(1); - - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword-multifieldBadge') - .length - ).toBe(1); - - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname-multifieldBadge') - .length - ).toBe(1); - - expect(findTestSubject(component, 'tableDocViewRow-city.raw').length).toBe(1); - }); - - it('does not render multifield rows if showMultiFields flag is not set', () => { - const overridedServices = { - uiSettings: { - get: (key: string) => { - if (key === 'discover:showMultiFields') { - return false; - } - }, - }, - } as unknown as UnifiedDocViewerServices; - const component = mountComponent(props, overridedServices); - - const categoryKeywordRow = findTestSubject(component, 'tableDocViewRow-category.keyword'); - expect(categoryKeywordRow.length).toBe(0); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword').length).toBe( - 0 - ); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname').length).toBe( - 0 - ); - - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.keyword-multifieldBadge') - .length - ).toBe(0); - - expect(findTestSubject(component, 'tableDocViewRow-customer_first_name').length).toBe(1); - expect( - findTestSubject(component, 'tableDocViewRow-customer_first_name.nickname-multifieldBadge') - .length - ).toBe(0); - - expect(findTestSubject(component, 'tableDocViewRow-city').length).toBe(0); - expect(findTestSubject(component, 'tableDocViewRow-city.raw').length).toBe(1); - }); -}); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx deleted file mode 100644 index e834bef5d664..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table.tsx +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import '../table.scss'; -import React, { useCallback, useMemo } from 'react'; -import { EuiInMemoryTable } from '@elastic/eui'; -import { getFieldIconType } from '@kbn/field-utils/src/utils/get_field_icon_type'; -import { - SHOW_MULTIFIELDS, - formatFieldValue, - getIgnoredReason, - getShouldShowFieldHandler, - isNestedFieldParent, -} from '@kbn/discover-utils'; -import type { DocViewRenderProps, FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { getUnifiedDocViewerServices } from '../../../plugin'; -import { ACTIONS_COLUMN, MAIN_COLUMNS } from './table_columns'; - -export const DocViewerLegacyTable = ({ - columns, - hit, - dataView, - hideActionsColumn, - filter, - onAddColumn, - onRemoveColumn, -}: DocViewRenderProps) => { - const { fieldFormats, uiSettings } = getUnifiedDocViewerServices(); - const showMultiFields = useMemo(() => uiSettings.get(SHOW_MULTIFIELDS), [uiSettings]); - - const mapping = useCallback((name: string) => dataView.fields.getByName(name), [dataView.fields]); - const tableColumns = useMemo(() => { - return !hideActionsColumn ? [ACTIONS_COLUMN, ...MAIN_COLUMNS] : MAIN_COLUMNS; - }, [hideActionsColumn]); - - const onToggleColumn = useMemo(() => { - if (!onRemoveColumn || !onAddColumn || !columns) { - return undefined; - } - return (field: string) => { - if (columns.includes(field)) { - onRemoveColumn(field); - } else { - onAddColumn(field); - } - }; - }, [onRemoveColumn, onAddColumn, columns]); - - const onSetRowProps = useCallback(({ field: { field } }: FieldRecordLegacy) => { - return { - key: field, - className: 'kbnDocViewer__tableRow', - 'data-test-subj': `tableDocViewRow-${field}`, - }; - }, []); - - const shouldShowFieldHandler = useMemo( - () => getShouldShowFieldHandler(Object.keys(hit.flattened), dataView, showMultiFields), - [hit.flattened, dataView, showMultiFields] - ); - - const items: FieldRecordLegacy[] = Object.keys(hit.flattened) - .filter(shouldShowFieldHandler) - .sort((fieldA, fieldB) => { - const mappingA = mapping(fieldA); - const mappingB = mapping(fieldB); - const nameA = !mappingA || !mappingA.displayName ? fieldA : mappingA.displayName; - const nameB = !mappingB || !mappingB.displayName ? fieldB : mappingB.displayName; - return nameA.localeCompare(nameB); - }) - .map((field) => { - const fieldMapping = mapping(field); - const displayName = fieldMapping?.displayName ?? field; - const fieldType = isNestedFieldParent(field, dataView) - ? 'nested' - : fieldMapping - ? getFieldIconType(fieldMapping) - : undefined; - const ignored = getIgnoredReason(fieldMapping ?? field, hit.raw._ignored); - return { - action: { - onToggleColumn, - onFilter: filter, - isActive: !!columns?.includes(field), - flattenedField: hit.flattened[field], - }, - field: { - field, - displayName, - fieldMapping, - fieldType, - scripted: Boolean(fieldMapping?.scripted), - }, - value: { - formattedValue: formatFieldValue( - hit.flattened[field], - hit.raw, - fieldFormats, - dataView, - fieldMapping - ), - ignored, - }, - }; - }); - - return ( - - ); -}; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx deleted file mode 100644 index c63c8c1ae70e..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_cell_actions.tsx +++ /dev/null @@ -1,67 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import type { DataViewField } from '@kbn/data-views-plugin/public'; -import type { DocViewFilterFn } from '@kbn/unified-doc-viewer/types'; -import { DocViewTableRowBtnFilterRemove } from './table_row_btn_filter_remove'; -import { DocViewTableRowBtnFilterExists } from './table_row_btn_filter_exists'; -import { DocViewTableRowBtnToggleColumn } from './table_row_btn_toggle_column'; -import { DocViewTableRowBtnFilterAdd } from './table_row_btn_filter_add'; - -interface TableActionsProps { - field: string; - isActive: boolean; - flattenedField: unknown; - fieldMapping?: DataViewField; - onFilter: DocViewFilterFn; - onToggleColumn: ((field: string) => void) | undefined; - ignoredValue: boolean; -} - -export const TableActions = ({ - isActive, - field, - fieldMapping, - flattenedField, - onToggleColumn, - onFilter, - ignoredValue, -}: TableActionsProps) => { - return ( -
        - {onFilter && ( - onFilter(fieldMapping, flattenedField, '+')} - /> - )} - {onFilter && ( - onFilter(fieldMapping, flattenedField, '-')} - /> - )} - {onToggleColumn && ( - onToggleColumn(field)} - /> - )} - {onFilter && ( - onFilter('_exists_', field, '+')} - scripted={fieldMapping && fieldMapping.scripted} - /> - )} -
        - ); -}; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_columns.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_columns.tsx deleted file mode 100644 index 3b510f613022..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_columns.tsx +++ /dev/null @@ -1,115 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { EuiBasicTableColumn, EuiText } from '@elastic/eui'; -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import type { FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { FieldName } from '@kbn/unified-doc-viewer'; -import { TableActions } from './table_cell_actions'; -import { TableFieldValue } from '../table_cell_value'; - -export const ACTIONS_COLUMN: EuiBasicTableColumn = { - field: 'action', - className: 'kbnDocViewer__tableActionsCell', - width: '108px', - mobileOptions: { header: false }, - name: ( - - - - - - ), - render: ( - { flattenedField, isActive, onFilter, onToggleColumn }: FieldRecordLegacy['action'], - { field: { field, fieldMapping }, value: { ignored } }: FieldRecordLegacy - ) => { - return ( - - ); - }, -}; -export const MAIN_COLUMNS: Array> = [ - { - field: 'field', - className: 'kbnDocViewer__tableFieldNameCell', - mobileOptions: { header: false }, - width: '30%', - name: ( - - - - - - ), - render: ({ - field, - fieldType, - displayName, - fieldMapping, - scripted, - }: FieldRecordLegacy['field']) => { - return field ? ( - - ) : ( -   - ); - }, - }, - { - field: 'value', - className: 'kbnDocViewer__tableValueCell', - mobileOptions: { header: false }, - name: ( - - - - - - ), - render: ( - { formattedValue, ignored }: FieldRecordLegacy['value'], - { field: { field }, action: { flattenedField } }: FieldRecordLegacy - ) => { - return ( - - ); - }, - }, -]; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_add.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_add.tsx deleted file mode 100644 index 12e3196cac1c..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_add.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export interface Props { - onClick: () => void; - disabled: boolean; -} - -export function DocViewTableRowBtnFilterAdd({ onClick, disabled = false }: Props) { - const tooltipContent = disabled ? ( - - ) : ( - - ); - - return ( - - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_exists.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_exists.tsx deleted file mode 100644 index 2685b4b7b8e6..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_exists.tsx +++ /dev/null @@ -1,63 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -export interface Props { - onClick: () => void; - disabled?: boolean; - scripted?: boolean; -} - -export function DocViewTableRowBtnFilterExists({ - onClick, - disabled = false, - scripted = false, -}: Props) { - const tooltipContent = disabled ? ( - scripted ? ( - - ) : ( - - ) - ) : ( - - ); - - return ( - - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_remove.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_remove.tsx deleted file mode 100644 index c9073fc9831c..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_filter_remove.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; - -export interface Props { - onClick: () => void; - disabled?: boolean; -} - -export function DocViewTableRowBtnFilterRemove({ onClick, disabled = false }: Props) { - const tooltipContent = disabled ? ( - - ) : ( - - ); - - return ( - - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_toggle_column.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_toggle_column.tsx deleted file mode 100644 index 9f999248cf26..000000000000 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/legacy/table_row_btn_toggle_column.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { i18n } from '@kbn/i18n'; -import { EuiToolTip, EuiButtonIcon } from '@elastic/eui'; - -export interface Props { - active: boolean; - disabled?: boolean; - onClick: () => void; - fieldname: string; -} - -export function DocViewTableRowBtnToggleColumn({ - onClick, - active, - disabled = false, - fieldname = '', -}: Props) { - if (disabled) { - return ( - - ); - } - return ( - - } - > - - - ); -} diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss index 64e700c73fca..348c8c9784ad 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.scss @@ -1,59 +1,3 @@ -.kbnDocViewer { - .euiTableRowCell { - vertical-align: top; - } -} - -.kbnDocViewer__tableRow { - font-size: $euiFontSizeXS; - font-family: $euiCodeFontFamily; - - // set min-width for each column except actions - .euiTableRowCell:nth-child(n+2) { - min-width: $euiSizeM * 9; - } - - .kbnDocViewer__buttons { - // Show all icons if one is focused, - &:focus-within { - .kbnDocViewer__actionButton { - opacity: 1; - } - } - } - - &:hover { - .kbnDocViewer__actionButton { - opacity: 1; - } - } - - .kbnDocViewer__actionButton { - @include euiBreakpoint('m', 'l', 'xl') { - opacity: 0; - } - - &:focus { - opacity: 1; - } - } -} - -.kbnDocViewer__tableActionsCell, -.kbnDocViewer__tableFieldNameCell { - .euiTableCellContent { - align-items: flex-start; - padding: $euiSizeXS; - } -} - -.kbnDocViewer__tableValueCell { - .euiTableCellContent { - flex-direction: column; - align-items: flex-start; - } -} - .kbnDocViewer__value { word-break: break-all; word-wrap: break-word; diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx index 16976d43e58f..632652100069 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table.tsx @@ -497,7 +497,7 @@ export const DocViewerTable = ({ {rows.length === 0 ? ( - +

        { - if (key === TRUNCATE_MAX_HEIGHT) { - return mockTruncateMaxHeightSetting ?? TRUNCATE_MAX_HEIGHT_DEFAULT_VALUE; - } - return; -}) as IUiSettingsClient['get']; - setUnifiedDocViewerServices(mockUnifiedDocViewerServices); let mockScrollHeight = 0; @@ -35,7 +21,6 @@ jest.spyOn(HTMLElement.prototype, 'scrollHeight', 'get').mockImplementation(() = describe('TableFieldValue', () => { afterEach(() => { mockScrollHeight = 0; - mockTruncateMaxHeightSetting = undefined; }); it('should render correctly', async () => { @@ -121,97 +106,4 @@ describe('TableFieldValue', () => { expect(valueElement.getAttribute('css')).toBeNull(); expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); }); - - it('should truncate a long value in legacy table correctly', async () => { - mockScrollHeight = 1000; - - const value = 'long value'.repeat(300); - render( - - ); - - expect(screen.getByText(value)).toBeInTheDocument(); - - let toggleButton = screen.getByTestId('toggleLongFieldValue-message'); - expect(toggleButton).toBeInTheDocument(); - expect(toggleButton.getAttribute('aria-expanded')).toBe('false'); - - let valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeDefined(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(true); - - toggleButton.click(); - - toggleButton = screen.getByTestId('toggleLongFieldValue-message'); - expect(toggleButton).toBeInTheDocument(); - expect(toggleButton.getAttribute('aria-expanded')).toBe('true'); - - valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeNull(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); - - toggleButton.click(); - - toggleButton = screen.getByTestId('toggleLongFieldValue-message'); - expect(toggleButton).toBeInTheDocument(); - expect(toggleButton.getAttribute('aria-expanded')).toBe('false'); - - valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeDefined(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(true); - }); - - it('should not truncate a long value in legacy table if limit is not reached', async () => { - mockScrollHeight = 112; - - const value = 'long value'.repeat(300); - render( - - ); - - expect(screen.getByText(value)).toBeInTheDocument(); - expect(screen.queryByTestId('toggleLongFieldValue-message')).toBeNull(); - - const valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeNull(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); - }); - - it('should not truncate a long value in legacy table if setting is 0', async () => { - mockScrollHeight = 1000; - mockTruncateMaxHeightSetting = 0; - - const value = 'long value'.repeat(300); - render( - - ); - - expect(screen.getByText(value)).toBeInTheDocument(); - expect(screen.queryByTestId('toggleLongFieldValue-message')).toBeNull(); - - const valueElement = screen.getByTestId('tableDocViewRow-message-value'); - expect(valueElement.getAttribute('css')).toBeNull(); - expect(valueElement.classList.contains('kbnDocViewer__value--truncated')).toBe(false); - }); }); diff --git a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx index 3afe935307ab..556f671e67cb 100644 --- a/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx +++ b/src/plugins/unified_doc_viewer/public/components/doc_viewer_table/table_cell_value.tsx @@ -21,9 +21,7 @@ import { import classnames from 'classnames'; import React, { Fragment, useCallback, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { IgnoredReason, TRUNCATE_MAX_HEIGHT } from '@kbn/discover-utils'; -import { FieldRecordLegacy } from '@kbn/unified-doc-viewer/types'; -import { getUnifiedDocViewerServices } from '../../plugin'; +import { IgnoredReason } from '@kbn/discover-utils'; const DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT = 110; @@ -96,14 +94,14 @@ const IgnoreWarning: React.FC = React.memo(({ rawValue, reas ); }); -type TableFieldValueProps = Pick & { - formattedValue: FieldRecordLegacy['value']['formattedValue']; +interface TableFieldValueProps { + field: string; + formattedValue: string; rawValue: unknown; ignoreReason?: IgnoredReason; isDetails?: boolean; // true when inside EuiDataGrid cell popover - isLegacy?: boolean; // true when inside legacy table isHighlighted?: boolean; // whether it's matching a search term -}; +} export const TableFieldValue = ({ formattedValue, @@ -111,14 +109,10 @@ export const TableFieldValue = ({ rawValue, ignoreReason, isDetails, - isLegacy, isHighlighted, }: TableFieldValueProps) => { const { euiTheme } = useEuiTheme(); - const { uiSettings } = getUnifiedDocViewerServices(); - const truncationHeight = isLegacy - ? uiSettings.get(TRUNCATE_MAX_HEIGHT) - : DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT; + const truncationHeight = DOC_VIEWER_DEFAULT_TRUNCATE_MAX_HEIGHT; const [containerRef, setContainerRef] = useState(null); useResizeObserver(containerRef); diff --git a/src/plugins/unified_doc_viewer/public/plugin.tsx b/src/plugins/unified_doc_viewer/public/plugin.tsx index 41db23a52591..4806d5fce091 100644 --- a/src/plugins/unified_doc_viewer/public/plugin.tsx +++ b/src/plugins/unified_doc_viewer/public/plugin.tsx @@ -9,7 +9,6 @@ import React from 'react'; import type { CoreSetup, Plugin } from '@kbn/core/public'; -import { isLegacyTableEnabled } from '@kbn/discover-utils'; import { i18n } from '@kbn/i18n'; import { DocViewsRegistry } from '@kbn/unified-doc-viewer'; import { EuiDelayRender, EuiSkeletonText } from '@elastic/eui'; @@ -31,9 +30,6 @@ const fallback = ( ); -const LazyDocViewerLegacyTable = dynamic(() => import('./components/doc_viewer_table/legacy'), { - fallback, -}); const LazyDocViewerTable = dynamic(() => import('./components/doc_viewer_table'), { fallback }); const LazySourceViewer = dynamic(() => import('./components/doc_viewer_source'), { fallback }); @@ -65,17 +61,7 @@ export class UnifiedDocViewerPublicPlugin }), order: 10, component: (props) => { - const { textBasedHits } = props; - const { uiSettings } = getUnifiedDocViewerServices(); - - const LazyDocView = isLegacyTableEnabled({ - uiSettings, - isEsqlMode: Array.isArray(textBasedHits), - }) - ? LazyDocViewerLegacyTable - : LazyDocViewerTable; - - return ; + return ; }, }); diff --git a/src/plugins/unified_histogram/public/chart/chart.tsx b/src/plugins/unified_histogram/public/chart/chart.tsx index 4fb1b9cbe647..164d1eb539e3 100644 --- a/src/plugins/unified_histogram/public/chart/chart.tsx +++ b/src/plugins/unified_histogram/public/chart/chart.tsx @@ -8,7 +8,6 @@ */ import React, { memo, ReactElement, useCallback, useEffect, useMemo, useState } from 'react'; -import type { Observable } from 'rxjs'; import { Subject } from 'rxjs'; import useObservable from 'react-use/lib/useObservable'; import { IconButtonGroup, type IconButtonGroupProps } from '@kbn/shared-ux-button-toolbar'; @@ -70,7 +69,7 @@ export interface ChartProps { disabledActions?: LensEmbeddableInput['disabledActions']; input$?: UnifiedHistogramInput$; lensAdapters?: UnifiedHistogramChartLoadEvent['adapters']; - lensEmbeddableOutput$?: Observable; + dataLoading$?: LensEmbeddableOutput['dataLoading']; isChartLoading?: boolean; onChartHiddenChange?: (chartHidden: boolean) => void; onTimeIntervalChange?: (timeInterval: string) => void; @@ -105,7 +104,7 @@ export function Chart({ disabledActions, input$: originalInput$, lensAdapters, - lensEmbeddableOutput$, + dataLoading$, isChartLoading, onChartHiddenChange, onTimeIntervalChange, @@ -383,9 +382,7 @@ export function Chart({ )} {canSaveVisualization && isSaveModalVisible && visContext.attributes && ( {}} onClose={() => setIsSaveModalVisible(false)} isSaveable={false} @@ -393,18 +390,16 @@ export function Chart({ )} {isFlyoutVisible && !!visContext && !!lensVisServiceCurrentSuggestionContext && ( )} diff --git a/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx b/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx index f2d080fcf0e6..edcd831d3f7a 100644 --- a/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx +++ b/src/plugins/unified_histogram/public/chart/chart_config_panel.tsx @@ -8,7 +8,6 @@ */ import React, { ComponentProps, useCallback, useEffect, useRef, useState } from 'react'; -import type { Observable } from 'rxjs'; import type { AggregateQuery, Query } from '@kbn/es-query'; import { isEqual, isObject } from 'lodash'; import type { LensEmbeddableOutput, Suggestion } from '@kbn/lens-plugin/public'; @@ -29,7 +28,7 @@ export function ChartConfigPanel({ services, visContext, lensAdapters, - lensEmbeddableOutput$, + dataLoading$, currentSuggestionContext, isFlyoutVisible, setIsFlyoutVisible, @@ -42,7 +41,7 @@ export function ChartConfigPanel({ isFlyoutVisible: boolean; setIsFlyoutVisible: (flag: boolean) => void; lensAdapters?: UnifiedHistogramChartLoadEvent['adapters']; - lensEmbeddableOutput$?: Observable; + dataLoading$?: LensEmbeddableOutput['dataLoading']; currentSuggestionContext: UnifiedHistogramSuggestionContext; isPlainRecord?: boolean; query?: Query | AggregateQuery; @@ -108,7 +107,7 @@ export function ChartConfigPanel({ updateSuggestion={updateSuggestion} updatePanelState={updatePanelState} lensAdapters={lensAdapters} - output$={lensEmbeddableOutput$} + dataLoading$={dataLoading$} displayFlyoutHeader closeFlyout={() => { setIsFlyoutVisible(false); @@ -141,7 +140,7 @@ export function ChartConfigPanel({ isFlyoutVisible, setIsFlyoutVisible, lensAdapters, - lensEmbeddableOutput$, + dataLoading$, currentSuggestionType, ]); diff --git a/src/plugins/unified_histogram/public/chart/histogram.test.tsx b/src/plugins/unified_histogram/public/chart/histogram.test.tsx index 72b5c0cc0b79..7bef5d4f8555 100644 --- a/src/plugins/unified_histogram/public/chart/histogram.test.tsx +++ b/src/plugins/unified_histogram/public/chart/histogram.test.tsx @@ -10,7 +10,7 @@ import { mountWithIntl } from '@kbn/test-jest-helpers'; import { Histogram } from './histogram'; import React from 'react'; -import { of, Subject } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; import { unifiedHistogramServicesMock } from '../__mocks__/services'; import { getLensVisMock } from '../__mocks__/lens_vis'; import { dataViewWithTimefieldMock } from '../__mocks__/data_view_with_timefield'; @@ -101,7 +101,7 @@ describe('Histogram', () => { searchSessionId: props.request.searchSessionId, getTimeRange: props.getTimeRange, attributes: (await getMockLensAttributes())!.attributes, - onLoad: lensProps.onLoad, + onLoad: lensProps.onLoad!, }); expect(lensProps).toMatchObject(expect.objectContaining(originalProps)); component.setProps({ request: { ...props.request, searchSessionId: '321' } }).update(); @@ -120,7 +120,7 @@ describe('Histogram', () => { it('should execute onLoad correctly', async () => { const { component, props } = await mountComponent(); const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; - const onLoad = component.find(embeddable).props().onLoad; + const onLoad = component.find(embeddable).props().onLoad!; const adapters = createDefaultInspectorAdapters(); adapters.tables.tables.unifiedHistogram = { meta: { statistics: { totalCount: 100 } } } as any; const rawResponse = { @@ -172,25 +172,25 @@ describe('Histogram', () => { jest .spyOn(adapters.requests, 'getRequests') .mockReturnValue([{ response: { json: { rawResponse } } } as any]); - const embeddableOutput$ = jest.fn().mockReturnValue(of('output$')); - onLoad(true, undefined, embeddableOutput$); + const dataLoading$ = new BehaviorSubject(false); + onLoad(true, undefined, dataLoading$); expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( UnifiedHistogramFetchStatus.loading, undefined ); - expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters: {}, embeddableOutput$ }); + expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters: {}, dataLoading$ }); expect(buildBucketInterval.buildBucketInterval).not.toHaveBeenCalled(); expect(useTimeRange.useTimeRange).toHaveBeenLastCalledWith( expect.objectContaining({ bucketInterval: undefined }) ); act(() => { - onLoad(false, adapters, embeddableOutput$); + onLoad?.(false, adapters, dataLoading$); }); expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( UnifiedHistogramFetchStatus.complete, 100 ); - expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters, embeddableOutput$ }); + expect(props.onChartLoad).toHaveBeenLastCalledWith({ adapters, dataLoading$ }); expect(buildBucketInterval.buildBucketInterval).toHaveBeenCalled(); expect(useTimeRange.useTimeRange).toHaveBeenLastCalledWith( expect.objectContaining({ bucketInterval: mockBucketInterval }) @@ -200,12 +200,12 @@ describe('Histogram', () => { it('should execute onLoad correctly when the request has a failure status', async () => { const { component, props } = await mountComponent(); const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; - const onLoad = component.find(embeddable).props().onLoad; + const onLoad = component.find(embeddable).props().onLoad!; const adapters = createDefaultInspectorAdapters(); jest .spyOn(adapters.requests, 'getRequests') .mockReturnValue([{ status: RequestStatus.ERROR } as any]); - onLoad(false, adapters); + onLoad?.(false, adapters); expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( UnifiedHistogramFetchStatus.error, undefined @@ -216,7 +216,7 @@ describe('Histogram', () => { it('should execute onLoad correctly when the response has shard failures', async () => { const { component, props } = await mountComponent(); const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; - const onLoad = component.find(embeddable).props().onLoad; + const onLoad = component.find(embeddable).props().onLoad!; const adapters = createDefaultInspectorAdapters(); adapters.tables.tables.unifiedHistogram = { meta: { statistics: { totalCount: 100 } } } as any; const rawResponse = { @@ -237,7 +237,7 @@ describe('Histogram', () => { .spyOn(adapters.requests, 'getRequests') .mockReturnValue([{ response: { json: { rawResponse } } } as any]); act(() => { - onLoad(false, adapters); + onLoad?.(false, adapters); }); expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( UnifiedHistogramFetchStatus.error, @@ -249,7 +249,7 @@ describe('Histogram', () => { it('should execute onLoad correctly for textbased language and no Lens suggestions', async () => { const { component, props } = await mountComponent(true, false); const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; - const onLoad = component.find(embeddable).props().onLoad; + const onLoad = component.find(embeddable).props().onLoad!; const adapters = createDefaultInspectorAdapters(); adapters.tables.tables.layerId = { meta: { type: 'es_ql' }, @@ -273,7 +273,7 @@ describe('Histogram', () => { ], } as any; act(() => { - onLoad(false, adapters); + onLoad?.(false, adapters); }); expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( UnifiedHistogramFetchStatus.complete, @@ -285,7 +285,7 @@ describe('Histogram', () => { it('should execute onLoad correctly for textbased language and Lens suggestions', async () => { const { component, props } = await mountComponent(true, true); const embeddable = unifiedHistogramServicesMock.lens.EmbeddableComponent; - const onLoad = component.find(embeddable).props().onLoad; + const onLoad = component.find(embeddable).props().onLoad!; const adapters = createDefaultInspectorAdapters(); adapters.tables.tables.layerId = { meta: { type: 'es_ql' }, @@ -309,7 +309,7 @@ describe('Histogram', () => { ], } as any; act(() => { - onLoad(false, adapters); + onLoad?.(false, adapters); }); expect(props.onTotalHitsChange).toHaveBeenLastCalledWith( UnifiedHistogramFetchStatus.complete, diff --git a/src/plugins/unified_histogram/public/chart/histogram.tsx b/src/plugins/unified_histogram/public/chart/histogram.tsx index 7e8c6ea382bd..8e3aa78da8d9 100644 --- a/src/plugins/unified_histogram/public/chart/histogram.tsx +++ b/src/plugins/unified_histogram/public/chart/histogram.tsx @@ -10,18 +10,15 @@ import { useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import React, { useState } from 'react'; -import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/public'; +import type { DataView } from '@kbn/data-views-plugin/public'; import type { DefaultInspectorAdapters, Datatable } from '@kbn/expressions-plugin/common'; import type { IKibanaSearchResponse } from '@kbn/search-types'; import type { estypes } from '@elastic/elasticsearch'; import type { TimeRange } from '@kbn/es-query'; -import { - EmbeddableComponentProps, - LensEmbeddableInput, - LensEmbeddableOutput, -} from '@kbn/lens-plugin/public'; +import type { EmbeddableComponentProps, LensEmbeddableInput } from '@kbn/lens-plugin/public'; import { RequestStatus } from '@kbn/inspector-plugin/public'; import type { Observable } from 'rxjs'; +import { PublishingSubject } from '@kbn/presentation-publishing'; import { UnifiedHistogramBucketInterval, UnifiedHistogramChartContext, @@ -59,32 +56,6 @@ export interface HistogramProps { withDefaultActions: EmbeddableComponentProps['withDefaultActions']; } -/** - * To prevent flakiness in the chart, we need to ensure that the data view config is valid. - * This requires that there are not multiple different data view ids in the given configuration. - * @param dataView - * @param visContext - * @param adHocDataViews - */ -const checkValidDataViewConfig = ( - dataView: DataView, - visContext: UnifiedHistogramVisContext, - adHocDataViews: { [key: string]: DataViewSpec } | undefined -) => { - if (!dataView.id) { - return false; - } - - if (!dataView.isPersisted() && !adHocDataViews?.[dataView.id]) { - return false; - } - - if (dataView.id !== visContext.requestData.dataViewId) { - return false; - } - return true; -}; - const computeTotalHits = ( hasLensSuggestions: boolean, adapterTables: @@ -147,7 +118,7 @@ export function Histogram({ ( isLoading: boolean, adapters: Partial | undefined, - lensEmbeddableOutput$?: Observable + dataLoading$?: PublishingSubject ) => { const lensRequest = adapters?.requests?.getRequests()[0]; const requestFailed = lensRequest?.status === RequestStatus.ERROR; @@ -186,7 +157,7 @@ export function Histogram({ setBucketInterval(newBucketInterval); } - onChartLoad?.({ adapters: adapters ?? {}, embeddableOutput$: lensEmbeddableOutput$ }); + onChartLoad?.({ adapters: adapters ?? {}, dataLoading$ }); } ); @@ -230,10 +201,6 @@ export function Histogram({ } `; - if (!checkValidDataViewConfig(dataView, visContext, lensProps.attributes.state.adHocDataViews)) { - return <>; - } - return ( <>

        void; onVisContextChanged?: ( nextVisContext: UnifiedHistogramVisContext | undefined, externalVisContextStatus: UnifiedHistogramExternalVisContextStatus @@ -86,19 +89,15 @@ export type UnifiedHistogramApi = { refetch: () => void; } & Pick< UnifiedHistogramStateService, - | 'state$' - | 'setChartHidden' - | 'setTopPanelHeight' - | 'setBreakdownField' - | 'setTimeInterval' - | 'setTotalHits' + 'state$' | 'setChartHidden' | 'setTopPanelHeight' | 'setTimeInterval' | 'setTotalHits' >; export const UnifiedHistogramContainer = forwardRef< UnifiedHistogramApi, UnifiedHistogramContainerProps ->(({ onVisContextChanged, ...containerProps }, ref) => { +>(({ onBreakdownFieldChange, onVisContextChanged, ...containerProps }, ref) => { const [layoutProps, setLayoutProps] = useState(); + const [localStorageKeyPrefix, setLocalStorageKeyPrefix] = useState(); const [stateService, setStateService] = useState(); const [lensSuggestionsApi, setLensSuggestionsApi] = useState(); const [input$] = useState(() => new Subject()); @@ -114,6 +113,7 @@ export const UnifiedHistogramContainer = forwardRef< const apiHelper = await services.lens.stateHelperApi(); setLayoutProps(pick(options, 'disableAutoFetching', 'disableTriggers', 'disabledActions')); + setLocalStorageKeyPrefix(options?.localStorageKeyPrefix); setStateService(createStateService({ services, ...options })); setLensSuggestionsApi(() => apiHelper.suggestions); }); @@ -133,21 +133,34 @@ export const UnifiedHistogramContainer = forwardRef< 'state$', 'setChartHidden', 'setTopPanelHeight', - 'setBreakdownField', 'setTimeInterval', 'setTotalHits' ), }); }, [input$, stateService]); - const { dataView, query, searchSessionId, requestAdapter, isChartLoading } = containerProps; + + const { services, dataView, query, columns, searchSessionId, requestAdapter, isChartLoading } = + containerProps; const topPanelHeight = useStateSelector(stateService?.state$, topPanelHeightSelector); + const initialBreakdownField = useMemo( + () => + localStorageKeyPrefix + ? getBreakdownField(services.storage, localStorageKeyPrefix) + : undefined, + [localStorageKeyPrefix, services.storage] + ); const stateProps = useStateProps({ + services, + localStorageKeyPrefix, stateService, dataView, query, searchSessionId, requestAdapter, - columns: containerProps.columns, + columns, + breakdownField: initialBreakdownField, + ...pick(containerProps, 'breakdownField'), + onBreakdownFieldChange, }); const handleVisContextChange: UnifiedHistogramLayoutProps['onVisContextChanged'] | undefined = diff --git a/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts b/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts index 5a3356ba9e03..f57392998d1f 100644 --- a/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts +++ b/src/plugins/unified_histogram/public/container/hooks/use_state_props.test.ts @@ -26,7 +26,6 @@ import { useStateProps } from './use_state_props'; describe('useStateProps', () => { const initialState: UnifiedHistogramState = { - breakdownField: 'bytes', chartHidden: false, lensRequestAdapter: new RequestAdapter(), lensAdapters: lensAdaptersMock, @@ -44,7 +43,6 @@ describe('useStateProps', () => { }); jest.spyOn(stateService, 'setChartHidden'); jest.spyOn(stateService, 'setTopPanelHeight'); - jest.spyOn(stateService, 'setBreakdownField'); jest.spyOn(stateService, 'setTimeInterval'); jest.spyOn(stateService, 'setLensRequestAdapter'); jest.spyOn(stateService, 'setTotalHits'); @@ -56,30 +54,28 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` Object { "breakdown": Object { - "field": Object { - "aggregatable": true, - "displayName": "bytes", - "filterable": true, - "name": "bytes", - "scripted": false, - "type": "number", - }, + "field": undefined, }, "chart": Object { "hidden": false, "timeInterval": "auto", }, + "dataLoading$": undefined, "hits": Object { "status": "uninitialized", "total": undefined, @@ -120,7 +116,6 @@ describe('useStateProps', () => { }, }, }, - "lensEmbeddableOutput$": undefined, "onBreakdownFieldChange": [Function], "onChartHiddenChange": [Function], "onChartLoad": [Function], @@ -147,12 +142,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` @@ -164,6 +163,7 @@ describe('useStateProps', () => { "hidden": false, "timeInterval": "auto", }, + "dataLoading$": undefined, "hits": Object { "status": "uninitialized", "total": undefined, @@ -204,7 +204,6 @@ describe('useStateProps', () => { }, }, }, - "lensEmbeddableOutput$": undefined, "onBreakdownFieldChange": [Function], "onChartHiddenChange": [Function], "onChartLoad": [Function], @@ -240,12 +239,16 @@ describe('useStateProps', () => { }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index | keep field1' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current.chart).toStrictEqual({ hidden: false, timeInterval: 'auto' }); @@ -271,17 +274,20 @@ describe('useStateProps', () => { initialState: { ...initialState, currentSuggestionContext: undefined, - breakdownField, }, }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: esqlColumns, + breakdownField, + onBreakdownFieldChange: undefined, }) ); @@ -314,25 +320,30 @@ describe('useStateProps', () => { }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { esql: 'FROM index' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: esqlColumns, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); const { onBreakdownFieldChange } = result.current; act(() => { onBreakdownFieldChange({ name: breakdownField } as DataViewField); }); - expect(stateService.setBreakdownField).toHaveBeenLastCalledWith(breakdownField); }); it('should return the correct props when a rollup data view is used', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: { ...dataViewWithTimefieldMock, @@ -342,12 +353,15 @@ describe('useStateProps', () => { requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` Object { "breakdown": undefined, "chart": undefined, + "dataLoading$": undefined, "hits": Object { "status": "uninitialized", "total": undefined, @@ -388,7 +402,6 @@ describe('useStateProps', () => { }, }, }, - "lensEmbeddableOutput$": undefined, "onBreakdownFieldChange": [Function], "onChartHiddenChange": [Function], "onChartLoad": [Function], @@ -415,18 +428,23 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); expect(result.current).toMatchInlineSnapshot(` Object { "breakdown": undefined, "chart": undefined, + "dataLoading$": undefined, "hits": Object { "status": "uninitialized", "total": undefined, @@ -467,7 +485,6 @@ describe('useStateProps', () => { }, }, }, - "lensEmbeddableOutput$": undefined, "onBreakdownFieldChange": [Function], "onChartHiddenChange": [Function], "onChartLoad": [Function], @@ -494,12 +511,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const { result } = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); @@ -553,8 +574,6 @@ describe('useStateProps', () => { act(() => { onBreakdownFieldChange({ name: 'field' } as DataViewField); }); - expect(stateService.setBreakdownField).toHaveBeenLastCalledWith('field'); - act(() => { onSuggestionContextChange({ suggestion: { title: 'Stacked Bar' }, @@ -569,12 +588,16 @@ describe('useStateProps', () => { const stateService = getStateService({ initialState }); const hook = renderHook(() => useStateProps({ + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }) ); (stateService.setLensRequestAdapter as jest.Mock).mockClear(); @@ -589,12 +612,16 @@ describe('useStateProps', () => { it('should clear lensRequestAdapter when chart is undefined', () => { const stateService = getStateService({ initialState }); const initialProps = { + services: unifiedHistogramServicesMock, + localStorageKeyPrefix: undefined, stateService, dataView: dataViewWithTimefieldMock, query: { language: 'kuery', query: '' }, requestAdapter: new RequestAdapter(), searchSessionId: '123', columns: undefined, + breakdownField: undefined, + onBreakdownFieldChange: undefined, }; const hook = renderHook((props: Parameters[0]) => useStateProps(props), { initialProps, diff --git a/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts b/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts index fcc19fcd78a0..46244d69d1f8 100644 --- a/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts +++ b/src/plugins/unified_histogram/public/container/hooks/use_state_props.ts @@ -17,45 +17,50 @@ import { useCallback, useEffect, useMemo } from 'react'; import { UnifiedHistogramChartLoadEvent, UnifiedHistogramFetchStatus, + UnifiedHistogramServices, UnifiedHistogramSuggestionContext, } from '../../types'; import type { UnifiedHistogramStateService } from '../services/state_service'; import { - breakdownFieldSelector, chartHiddenSelector, timeIntervalSelector, totalHitsResultSelector, totalHitsStatusSelector, lensAdaptersSelector, - lensEmbeddableOutputSelector$, + lensDataLoadingSelector$, } from '../utils/state_selectors'; import { useStateSelector } from '../utils/use_state_selector'; +import { setBreakdownField } from '../utils/local_storage_utils'; export const useStateProps = ({ + services, + localStorageKeyPrefix, stateService, dataView, query, searchSessionId, requestAdapter, columns, + breakdownField, + onBreakdownFieldChange: originalOnBreakdownFieldChange, }: { + services: UnifiedHistogramServices; + localStorageKeyPrefix: string | undefined; stateService: UnifiedHistogramStateService | undefined; dataView: DataView; query: Query | AggregateQuery | undefined; searchSessionId: string | undefined; requestAdapter: RequestAdapter | undefined; columns: DatatableColumn[] | undefined; + breakdownField: string | undefined; + onBreakdownFieldChange: ((breakdownField: string | undefined) => void) | undefined; }) => { - const breakdownField = useStateSelector(stateService?.state$, breakdownFieldSelector); const chartHidden = useStateSelector(stateService?.state$, chartHiddenSelector); const timeInterval = useStateSelector(stateService?.state$, timeIntervalSelector); const totalHitsResult = useStateSelector(stateService?.state$, totalHitsResultSelector); const totalHitsStatus = useStateSelector(stateService?.state$, totalHitsStatusSelector); const lensAdapters = useStateSelector(stateService?.state$, lensAdaptersSelector); - const lensEmbeddableOutput$ = useStateSelector( - stateService?.state$, - lensEmbeddableOutputSelector$ - ); + const lensDataLoading$ = useStateSelector(stateService?.state$, lensDataLoadingSelector$); /** * Contexts */ @@ -162,16 +167,16 @@ export const useStateProps = ({ // We need to store the Lens request adapter in order to inspect its requests stateService?.setLensRequestAdapter(event.adapters.requests); stateService?.setLensAdapters(event.adapters); - stateService?.setLensEmbeddableOutput$(event.embeddableOutput$); + stateService?.setLensDataLoading$(event.dataLoading$); }, [stateService] ); const onBreakdownFieldChange = useCallback( (newBreakdownField: DataViewField | undefined) => { - stateService?.setBreakdownField(newBreakdownField?.name); + originalOnBreakdownFieldChange?.(newBreakdownField?.name); }, - [stateService] + [originalOnBreakdownFieldChange] ); const onSuggestionContextChange = useCallback( @@ -185,6 +190,13 @@ export const useStateProps = ({ * Effects */ + // Sync the breakdown field with local storage + useEffect(() => { + if (localStorageKeyPrefix) { + setBreakdownField(services.storage, localStorageKeyPrefix, breakdownField); + } + }, [breakdownField, localStorageKeyPrefix, services.storage]); + // Clear the Lens request adapter when the chart is hidden useEffect(() => { if (chartHidden || !chart) { @@ -199,7 +211,7 @@ export const useStateProps = ({ request, isPlainRecord, lensAdapters, - lensEmbeddableOutput$, + dataLoading$: lensDataLoading$, onTopPanelHeightChange, onTimeIntervalChange, onTotalHitsChange, diff --git a/src/plugins/unified_histogram/public/container/services/state_service.test.ts b/src/plugins/unified_histogram/public/container/services/state_service.test.ts index dcce90037ec9..5c3024eef7dd 100644 --- a/src/plugins/unified_histogram/public/container/services/state_service.test.ts +++ b/src/plugins/unified_histogram/public/container/services/state_service.test.ts @@ -14,10 +14,8 @@ import { lensAdaptersMock } from '../../__mocks__/lens_adapters'; import { getChartHidden, getTopPanelHeight, - getBreakdownField, setChartHidden, setTopPanelHeight, - setBreakdownField, } from '../utils/local_storage_utils'; import { createStateService, UnifiedHistogramState } from './state_service'; @@ -27,10 +25,8 @@ jest.mock('../utils/local_storage_utils', () => { ...originalModule, getChartHidden: jest.fn(originalModule.getChartHidden), getTopPanelHeight: jest.fn(originalModule.getTopPanelHeight), - getBreakdownField: jest.fn(originalModule.getBreakdownField), setChartHidden: jest.fn(originalModule.setChartHidden), setTopPanelHeight: jest.fn(originalModule.setTopPanelHeight), - setBreakdownField: jest.fn(originalModule.setBreakdownField), }; }); @@ -38,14 +34,11 @@ describe('UnifiedHistogramStateService', () => { beforeEach(() => { (getChartHidden as jest.Mock).mockClear(); (getTopPanelHeight as jest.Mock).mockClear(); - (getBreakdownField as jest.Mock).mockClear(); (setChartHidden as jest.Mock).mockClear(); (setTopPanelHeight as jest.Mock).mockClear(); - (setBreakdownField as jest.Mock).mockClear(); }); const initialState: UnifiedHistogramState = { - breakdownField: 'bytes', chartHidden: false, lensRequestAdapter: new RequestAdapter(), lensAdapters: lensAdaptersMock, @@ -61,7 +54,6 @@ describe('UnifiedHistogramStateService', () => { let state: UnifiedHistogramState | undefined; stateService.state$.subscribe((s) => (state = s)); expect(state).toEqual({ - breakdownField: undefined, chartHidden: false, lensRequestAdapter: undefined, timeInterval: 'auto', @@ -97,10 +89,6 @@ describe('UnifiedHistogramStateService', () => { unifiedHistogramServicesMock.storage, localStorageKeyPrefix ); - expect(getBreakdownField as jest.Mock).toHaveBeenCalledWith( - unifiedHistogramServicesMock.storage, - localStorageKeyPrefix - ); }); it('should not get values from storage if localStorageKeyPrefix is not provided', () => { @@ -110,7 +98,6 @@ describe('UnifiedHistogramStateService', () => { }); expect(getChartHidden as jest.Mock).not.toHaveBeenCalled(); expect(getTopPanelHeight as jest.Mock).not.toHaveBeenCalled(); - expect(getBreakdownField as jest.Mock).not.toHaveBeenCalled(); }); it('should update state', () => { @@ -128,9 +115,6 @@ describe('UnifiedHistogramStateService', () => { stateService.setTopPanelHeight(200); newState = { ...newState, topPanelHeight: 200 }; expect(state).toEqual(newState); - stateService.setBreakdownField('test'); - newState = { ...newState, breakdownField: 'test' }; - expect(state).toEqual(newState); stateService.setTimeInterval('test'); newState = { ...newState, timeInterval: 'test' }; expect(state).toEqual(newState); @@ -139,8 +123,8 @@ describe('UnifiedHistogramStateService', () => { stateService.setLensAdapters(undefined); newState = { ...newState, lensAdapters: undefined }; expect(state).toEqual(newState); - stateService.setLensEmbeddableOutput$(undefined); - newState = { ...newState, lensEmbeddableOutput$: undefined }; + stateService.setLensDataLoading$(undefined); + newState = { ...newState, dataLoading$: undefined }; expect(state).toEqual(newState); stateService.setTotalHits({ totalHitsStatus: UnifiedHistogramFetchStatus.complete, @@ -166,12 +150,10 @@ describe('UnifiedHistogramStateService', () => { expect(state).toEqual(initialState); stateService.setChartHidden(true); stateService.setTopPanelHeight(200); - stateService.setBreakdownField('test'); expect(state).toEqual({ ...initialState, chartHidden: true, topPanelHeight: 200, - breakdownField: 'test', }); expect(setChartHidden as jest.Mock).toHaveBeenCalledWith( unifiedHistogramServicesMock.storage, @@ -183,11 +165,6 @@ describe('UnifiedHistogramStateService', () => { localStorageKeyPrefix, 200 ); - expect(setBreakdownField as jest.Mock).toHaveBeenCalledWith( - unifiedHistogramServicesMock.storage, - localStorageKeyPrefix, - 'test' - ); }); it('should not save state to storage if localStorageKeyPrefix is not provided', () => { @@ -200,15 +177,12 @@ describe('UnifiedHistogramStateService', () => { expect(state).toEqual(initialState); stateService.setChartHidden(true); stateService.setTopPanelHeight(200); - stateService.setBreakdownField('test'); expect(state).toEqual({ ...initialState, chartHidden: true, topPanelHeight: 200, - breakdownField: 'test', }); expect(setChartHidden as jest.Mock).not.toHaveBeenCalled(); expect(setTopPanelHeight as jest.Mock).not.toHaveBeenCalled(); - expect(setBreakdownField as jest.Mock).not.toHaveBeenCalled(); }); }); diff --git a/src/plugins/unified_histogram/public/container/services/state_service.ts b/src/plugins/unified_histogram/public/container/services/state_service.ts index 551773cfe189..cdca02396e3a 100644 --- a/src/plugins/unified_histogram/public/container/services/state_service.ts +++ b/src/plugins/unified_histogram/public/container/services/state_service.ts @@ -8,15 +8,13 @@ */ import type { RequestAdapter } from '@kbn/inspector-plugin/common'; -import type { LensEmbeddableOutput } from '@kbn/lens-plugin/public'; import { BehaviorSubject, Observable } from 'rxjs'; +import { PublishingSubject } from '@kbn/presentation-publishing'; import { UnifiedHistogramFetchStatus } from '../..'; import type { UnifiedHistogramServices, UnifiedHistogramChartLoadEvent } from '../../types'; import { - getBreakdownField, getChartHidden, getTopPanelHeight, - setBreakdownField, setChartHidden, setTopPanelHeight, } from '../utils/local_storage_utils'; @@ -26,10 +24,6 @@ import type { UnifiedHistogramSuggestionContext } from '../../types'; * The current state of the container */ export interface UnifiedHistogramState { - /** - * The current field used for the breakdown - */ - breakdownField: string | undefined; /** * The current Lens suggestion */ @@ -49,7 +43,7 @@ export interface UnifiedHistogramState { /** * Lens embeddable output observable */ - lensEmbeddableOutput$?: Observable; + dataLoading$?: PublishingSubject; /** * The current time interval of the chart */ @@ -108,10 +102,6 @@ export interface UnifiedHistogramStateService { * Sets the current top panel height */ setTopPanelHeight: (topPanelHeight: number | undefined) => void; - /** - * Sets the current breakdown field - */ - setBreakdownField: (breakdownField: string | undefined) => void; /** * Sets the current time interval */ @@ -124,9 +114,7 @@ export interface UnifiedHistogramStateService { * Sets the current Lens adapters */ setLensAdapters: (lensAdapters: UnifiedHistogramChartLoadEvent['adapters'] | undefined) => void; - setLensEmbeddableOutput$: ( - lensEmbeddableOutput$: Observable | undefined - ) => void; + setLensDataLoading$: (dataLoading$: PublishingSubject | undefined) => void; /** * Sets the current total hits status and result */ @@ -143,16 +131,13 @@ export const createStateService = ( let initialChartHidden = false; let initialTopPanelHeight: number | undefined; - let initialBreakdownField: string | undefined; if (localStorageKeyPrefix) { initialChartHidden = getChartHidden(services.storage, localStorageKeyPrefix) ?? false; initialTopPanelHeight = getTopPanelHeight(services.storage, localStorageKeyPrefix); - initialBreakdownField = getBreakdownField(services.storage, localStorageKeyPrefix); } const state$ = new BehaviorSubject({ - breakdownField: initialBreakdownField, chartHidden: initialChartHidden, currentSuggestionContext: undefined, lensRequestAdapter: undefined, @@ -189,14 +174,6 @@ export const createStateService = ( updateState({ topPanelHeight }); }, - setBreakdownField: (breakdownField: string | undefined) => { - if (localStorageKeyPrefix) { - setBreakdownField(services.storage, localStorageKeyPrefix, breakdownField); - } - - updateState({ breakdownField }); - }, - setCurrentSuggestionContext: ( suggestionContext: UnifiedHistogramSuggestionContext | undefined ) => { @@ -214,10 +191,8 @@ export const createStateService = ( setLensAdapters: (lensAdapters: UnifiedHistogramChartLoadEvent['adapters'] | undefined) => { updateState({ lensAdapters }); }, - setLensEmbeddableOutput$: ( - lensEmbeddableOutput$: Observable | undefined - ) => { - updateState({ lensEmbeddableOutput$ }); + setLensDataLoading$: (dataLoading$: PublishingSubject | undefined) => { + updateState({ dataLoading$ }); }, setTotalHits: (totalHits: { diff --git a/src/plugins/unified_histogram/public/container/utils/state_selectors.ts b/src/plugins/unified_histogram/public/container/utils/state_selectors.ts index 6eacbaaef950..c20ec4193c53 100644 --- a/src/plugins/unified_histogram/public/container/utils/state_selectors.ts +++ b/src/plugins/unified_histogram/public/container/utils/state_selectors.ts @@ -9,12 +9,10 @@ import type { UnifiedHistogramState } from '../services/state_service'; -export const breakdownFieldSelector = (state: UnifiedHistogramState) => state.breakdownField; export const chartHiddenSelector = (state: UnifiedHistogramState) => state.chartHidden; export const timeIntervalSelector = (state: UnifiedHistogramState) => state.timeInterval; export const topPanelHeightSelector = (state: UnifiedHistogramState) => state.topPanelHeight; export const totalHitsResultSelector = (state: UnifiedHistogramState) => state.totalHitsResult; export const totalHitsStatusSelector = (state: UnifiedHistogramState) => state.totalHitsStatus; export const lensAdaptersSelector = (state: UnifiedHistogramState) => state.lensAdapters; -export const lensEmbeddableOutputSelector$ = (state: UnifiedHistogramState) => - state.lensEmbeddableOutput$; +export const lensDataLoadingSelector$ = (state: UnifiedHistogramState) => state.dataLoading$; diff --git a/src/plugins/unified_histogram/public/layout/layout.tsx b/src/plugins/unified_histogram/public/layout/layout.tsx index 3e34cf4ee69b..b9d9f6fbc446 100644 --- a/src/plugins/unified_histogram/public/layout/layout.tsx +++ b/src/plugins/unified_histogram/public/layout/layout.tsx @@ -9,7 +9,6 @@ import { EuiSpacer, useEuiTheme, useIsWithinBreakpoints } from '@elastic/eui'; import React, { PropsWithChildren, ReactElement, useEffect, useMemo, useState } from 'react'; -import { Observable } from 'rxjs'; import useObservable from 'react-use/lib/useObservable'; import { createHtmlPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; import { css } from '@emotion/css'; @@ -99,7 +98,7 @@ export interface UnifiedHistogramLayoutProps extends PropsWithChildren */ hits?: UnifiedHistogramHitsContext; lensAdapters?: UnifiedHistogramChartLoadEvent['adapters']; - lensEmbeddableOutput$?: Observable; + dataLoading$?: LensEmbeddableOutput['dataLoading']; /** * Context object for the chart -- leave undefined to hide the chart */ @@ -214,7 +213,7 @@ export const UnifiedHistogramLayout = ({ request, hits, lensAdapters, - lensEmbeddableOutput$, + dataLoading$, chart: originalChart, breakdown, container, @@ -372,7 +371,7 @@ export const UnifiedHistogramLayout = ({ onFilter={onFilter} onBrushEnd={onBrushEnd} lensAdapters={lensAdapters} - lensEmbeddableOutput$={lensEmbeddableOutput$} + dataLoading$={dataLoading$} withDefaultActions={withDefaultActions} columns={columns} /> diff --git a/src/plugins/unified_histogram/public/mocks.ts b/src/plugins/unified_histogram/public/mocks.ts index 4772739e2836..11ebd5023925 100644 --- a/src/plugins/unified_histogram/public/mocks.ts +++ b/src/plugins/unified_histogram/public/mocks.ts @@ -15,7 +15,6 @@ export const createMockUnifiedHistogramApi = () => { state$: new Observable(), setChartHidden: jest.fn(), setTopPanelHeight: jest.fn(), - setBreakdownField: jest.fn(), setTimeInterval: jest.fn(), setTotalHits: jest.fn(), refetch: jest.fn(), diff --git a/src/plugins/unified_histogram/public/services/lens_vis_service.attributes.test.ts b/src/plugins/unified_histogram/public/services/lens_vis_service.attributes.test.ts index babea0335e1c..f338ef955c01 100644 --- a/src/plugins/unified_histogram/public/services/lens_vis_service.attributes.test.ts +++ b/src/plugins/unified_histogram/public/services/lens_vis_service.attributes.test.ts @@ -108,6 +108,7 @@ describe('LensVisService attributes', () => { "sourceField": "timestamp", }, }, + "indexPatternId": "index-pattern-with-timefield-id", }, }, }, @@ -284,6 +285,7 @@ describe('LensVisService attributes', () => { "sourceField": "timestamp", }, }, + "indexPatternId": "index-pattern-with-timefield-id", }, }, }, @@ -434,6 +436,7 @@ describe('LensVisService attributes', () => { "sourceField": "timestamp", }, }, + "indexPatternId": "index-pattern-with-timefield-id", }, }, }, diff --git a/src/plugins/unified_histogram/public/services/lens_vis_service.ts b/src/plugins/unified_histogram/public/services/lens_vis_service.ts index 1f119ee5b1c9..52968693ed65 100644 --- a/src/plugins/unified_histogram/public/services/lens_vis_service.ts +++ b/src/plugins/unified_histogram/public/services/lens_vis_service.ts @@ -329,8 +329,13 @@ export class LensVisService { queryParams: QueryParams; timeInterval: string | undefined; breakdownField: DataViewField | undefined; - }): Suggestion => { + }): Suggestion | undefined => { const { dataView } = queryParams; + + if (!dataView.isTimeBased() || !dataView.timeFieldName) { + return undefined; + } + const showBreakdown = breakdownField && fieldSupportsBreakdown(breakdownField); let columnOrder = ['date_column', 'count_column']; @@ -343,7 +348,7 @@ export class LensVisService { date_column: { dataType: 'date', isBucketed: true, - label: dataView.timeFieldName ?? '', + label: dataView.timeFieldName, operationType: 'date_histogram', scale: 'interval', sourceField: dataView.timeFieldName, @@ -403,7 +408,7 @@ export class LensVisService { const datasourceState = { layers: { - [UNIFIED_HISTOGRAM_LAYER_ID]: { columnOrder, columns }, + [UNIFIED_HISTOGRAM_LAYER_ID]: { columnOrder, columns, indexPatternId: dataView.id }, }, }; diff --git a/src/plugins/unified_histogram/public/types.ts b/src/plugins/unified_histogram/public/types.ts index b777fe89a348..a64000da11df 100644 --- a/src/plugins/unified_histogram/public/types.ts +++ b/src/plugins/unified_histogram/public/types.ts @@ -10,19 +10,15 @@ import type { IUiSettingsClient, Capabilities } from '@kbn/core/public'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { - LensEmbeddableOutput, - LensPublicStart, - TypedLensByValueInput, - Suggestion, -} from '@kbn/lens-plugin/public'; +import type { LensPublicStart, TypedLensByValueInput, Suggestion } from '@kbn/lens-plugin/public'; import type { DataViewField } from '@kbn/data-views-plugin/public'; import type { RequestAdapter } from '@kbn/inspector-plugin/public'; import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; -import type { Observable, Subject } from 'rxjs'; +import type { Subject } from 'rxjs'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { Storage } from '@kbn/kibana-utils-plugin/public'; import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import { PublishingSubject } from '@kbn/presentation-publishing'; /** * The fetch status of a Unified Histogram request @@ -72,9 +68,9 @@ export interface UnifiedHistogramChartLoadEvent { */ adapters: UnifiedHistogramAdapters; /** - * Observable of the lens embeddable output + * Observable for the data change subscription */ - embeddableOutput$?: Observable; + dataLoading$?: PublishingSubject; } /** diff --git a/src/plugins/unified_histogram/public/utils/external_vis_context.ts b/src/plugins/unified_histogram/public/utils/external_vis_context.ts index ef5788b4b25b..29e393d14508 100644 --- a/src/plugins/unified_histogram/public/utils/external_vis_context.ts +++ b/src/plugins/unified_histogram/public/utils/external_vis_context.ts @@ -43,7 +43,7 @@ export const exportVisContext = ( ? { suggestionType: visContext.suggestionType, requestData: visContext.requestData, - attributes: removeTablesFromLensAttributes(visContext.attributes), + attributes: removeTablesFromLensAttributes(visContext.attributes).attributes, } : undefined; diff --git a/src/plugins/unified_histogram/public/utils/lens_vis_from_table.ts b/src/plugins/unified_histogram/public/utils/lens_vis_from_table.ts index 95693851db52..bc618343a0a7 100644 --- a/src/plugins/unified_histogram/public/utils/lens_vis_from_table.ts +++ b/src/plugins/unified_histogram/public/utils/lens_vis_from_table.ts @@ -10,6 +10,7 @@ import type { Datatable } from '@kbn/expressions-plugin/common'; import type { LensAttributes } from '@kbn/lens-embeddable-utils'; import type { TextBasedPersistedState } from '@kbn/lens-plugin/public/datasources/text_based/types'; +import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; export const enrichLensAttributesWithTablesData = ({ attributes, @@ -53,6 +54,8 @@ export const enrichLensAttributesWithTablesData = ({ return updatedAttributes; }; -export const removeTablesFromLensAttributes = (attributes: LensAttributes): LensAttributes => { - return enrichLensAttributesWithTablesData({ attributes, table: undefined }); +export const removeTablesFromLensAttributes = ( + attributes: LensAttributes +): TypedLensByValueInput => { + return { attributes: enrichLensAttributesWithTablesData({ attributes, table: undefined }) }; }; diff --git a/src/plugins/unified_histogram/tsconfig.json b/src/plugins/unified_histogram/tsconfig.json index d14adf53889b..68c096665eb7 100644 --- a/src/plugins/unified_histogram/tsconfig.json +++ b/src/plugins/unified_histogram/tsconfig.json @@ -33,6 +33,7 @@ "@kbn/discover-utils", "@kbn/visualization-utils", "@kbn/search-types", + "@kbn/presentation-publishing", "@kbn/data-view-utils", ], "exclude": [ diff --git a/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx b/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx index cc602efa6142..425624c3e194 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_editor/filter_editor.tsx @@ -280,7 +280,7 @@ class FilterEditorComponent extends Component { diff --git a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx index 19ba66809246..9c8e7b074149 100644 --- a/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx +++ b/src/plugins/unified_search/public/filter_bar/filter_item/filter_item.tsx @@ -388,7 +388,7 @@ function FilterItemComponent(props: FilterItemProps) { ) : ( +
        ); diff --git a/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx b/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx index 319d3b0f4984..16ef016ff400 100644 --- a/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx +++ b/src/plugins/unified_search/public/query_string_input/filter_editor_wrapper.tsx @@ -105,7 +105,7 @@ export const FilterEditorWrapper = React.memo(function FilterEditorWrapper({ } return ( -
        +
        {newFilter && ( -

        {strings.getNoDataPopoverContent()}

        +

        {strings.getNoDataPopoverContent()}

        } minWidth={300} diff --git a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx index 4d4db4438d74..037997bbd5c8 100644 --- a/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_bar_top_row.tsx @@ -628,7 +628,7 @@ export const QueryBarTopRow = React.memo( function renderDataViewsPicker() { if (props.dataViewPickerComponentProps && !Boolean(isQueryLangSelected)) { return ( - + {!isQueryLangSelected ? renderQueryInput() : null} diff --git a/src/plugins/unified_search/public/query_string_input/query_string_input.tsx b/src/plugins/unified_search/public/query_string_input/query_string_input.tsx index 2e3b0fab0a16..2e76341ae607 100644 --- a/src/plugins/unified_search/public/query_string_input/query_string_input.tsx +++ b/src/plugins/unified_search/public/query_string_input/query_string_input.tsx @@ -808,7 +808,7 @@ export default class QueryStringInputUI extends PureComponent
        { it('should render the saved queries on the selectable component', async () => { render(wrapSavedQueriesListComponentInContext(props)); - expect(await screen.findAllByRole('option')).toHaveLength(1); + await waitFor(() => expect(screen.queryAllByRole('option')).toHaveLength(1)); expect(screen.getByRole('option', { name: 'Test' })).toBeInTheDocument(); }); diff --git a/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx b/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx index ff0b48a1de7a..b83a3330cce2 100644 --- a/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx +++ b/src/plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx @@ -116,7 +116,7 @@ export function LinkedSearch({ savedSearch, eventEmitter }: LinkedSearchProps) { defaultMessage="Linked to saved search" /> -
        +

        { }); it('should subscribe on uiState changes and update local state', async () => { - const { result, unmount, waitForNextUpdate } = renderHook(() => useUiState(uiState)); + const { result, unmount } = renderHook(() => useUiState(uiState)); expect(uiState.on).toHaveBeenCalledWith('change', expect.any(Function)); // @ts-expect-error @@ -61,18 +61,18 @@ describe('useUiState', () => { updateOnChange(); }); - await waitForNextUpdate(); - // should update local state with new values - expect(result.current).toEqual({ - columnsWidth: [], - sort: { - columnIndex: 1, - direction: 'asc', - }, - setColumnsWidth: expect.any(Function), - setSort: expect.any(Function), - }); + await waitFor(() => + expect(result.current).toEqual({ + columnsWidth: [], + sort: { + columnIndex: 1, + direction: 'asc', + }, + setColumnsWidth: expect.any(Function), + setSort: expect.any(Function), + }) + ); act(() => { updateOnChange(); diff --git a/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_row.tsx b/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_row.tsx index 1a533c5fdd7e..fd41e4996ff0 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_row.tsx +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/agg_row.tsx @@ -48,7 +48,7 @@ export function AggRow(props: AggRowProps) { responsive={false} > - + {props.children} diff --git a/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js index f30dfce37e5c..7a93aa271b5d 100644 --- a/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js +++ b/src/plugins/vis_types/timeseries/public/application/components/aggs/percentile_ui.js @@ -122,7 +122,7 @@ export class Percentiles extends Component { {/* If the series is grouped by, then these colors are not respected, no need to display the color picker */} {!isGroupedBy && !['table', 'metric', 'markdown'].includes(panel.type) && ( - + -

        +
        {i18n.translate('visTypeTimeseries.indexPatternSelect.switchModePopover.title', { defaultMessage: 'Data view mode', diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap index 7ded8e2254aa..18ce44a9fb7e 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/decorators/__snapshots__/area_decorator.test.js.snap @@ -18,7 +18,7 @@ exports[`src/legacy/core_plugins/metrics/public/visualizations/views/timeseries/ "radius": 1, "stroke": "rgb(0, 156, 224)", "strokeWidth": 5, - "visible": false, + "visible": "never", }, } } diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap index 054ca0f0d819..28bfd0c69830 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/__snapshots__/series_styles.test.js.snap @@ -17,7 +17,7 @@ Object { "radius": 1, "stroke": "rgb(224, 0, 221)", "strokeWidth": 1, - "visible": true, + "visible": "always", }, }, "curve": 7, @@ -41,7 +41,7 @@ Object { "radius": 0.5, "stroke": "#000", "strokeWidth": 5, - "visible": false, + "visible": "never", }, }, "curve": 9, diff --git a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js index 0da1e8e474b5..6bfbbb7bfb28 100644 --- a/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js +++ b/src/plugins/vis_types/timeseries/public/application/visualizations/views/timeseries/utils/series_styles.js @@ -27,7 +27,7 @@ export const getAreaStyles = ({ points, lines, color }) => ({ radius: points.radius || 0.5, stroke: color || DEFAULT_COLOR, strokeWidth: points.lineWidth || 5, - visible: points.lineWidth > 0 && Boolean(points.show), + visible: points.lineWidth > 0 && Boolean(points.show) ? 'always' : 'never', }, }, curve: lines.steps ? CurveType.CURVE_STEP_AFTER : CurveType.LINEAR, diff --git a/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts b/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts index 51150cd65873..450238142b23 100644 --- a/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts +++ b/src/plugins/vis_types/vega/public/vega_view/vega_tooltip.styles.ts @@ -53,7 +53,7 @@ export const vegaVisTooltipStyles = (euiThemeContext: UseEuiTheme) => { 'max-width', mathWithUnits(euiTheme.size.base, (x) => x * 10) )} - color: ${euiTheme.colors.mediumShade}; + color: ${euiTheme.colors.lightShade}; ${logicalTextAlignCSS('right')} ${logicalCSS('padding-right', euiTheme.size.xs)} } diff --git a/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx b/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx index d4124ca216d0..e0be21c3272e 100644 --- a/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx +++ b/src/plugins/visualizations/public/components/visualization_missed_saved_object_error.tsx @@ -49,7 +49,7 @@ export const VisualizationMissedSavedObjectError = ({ path: '/kibana/indexPatterns/create', })} data-test-subj="configuration-failure-reconfigure-indexpatterns" - style={{ width: '100%' }} + css={{ width: '100%' }} > {i18n.translate('visualizations.missedDataView.dataViewReconfigure', { defaultMessage: `Recreate it in the data view management page`, diff --git a/src/plugins/visualizations/public/embeddable/types.ts b/src/plugins/visualizations/public/embeddable/types.ts index f4215d923e1d..80e7e2d9179e 100644 --- a/src/plugins/visualizations/public/embeddable/types.ts +++ b/src/plugins/visualizations/public/embeddable/types.ts @@ -17,6 +17,7 @@ import { HasSupportedTriggers, PublishesDataLoading, PublishesDataViews, + PublishesRendered, PublishesTimeRange, SerializedTimeRange, SerializedTitles, @@ -92,6 +93,7 @@ export const isVisualizeRuntimeState = (state: unknown): state is VisualizeRunti export type VisualizeApi = Partial & PublishesDataViews & PublishesDataLoading & + PublishesRendered & HasVisualizeConfig & HasInspectorAdapters & HasSupportedTriggers & diff --git a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx index 7b48521265d6..71338e96ea14 100644 --- a/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx +++ b/src/plugins/visualizations/public/embeddable/visualize_embeddable.tsx @@ -179,6 +179,7 @@ export const getVisualizeEmbeddableFactory: (deps: { defaultPanelTitle, dataLoading: dataLoading$, dataViews: new BehaviorSubject(initialDataViews), + rendered$: hasRendered$, supportedTriggers: () => [ ACTION_CONVERT_TO_LENS, APPLY_FILTER_TRIGGER, @@ -397,7 +398,6 @@ export const getVisualizeEmbeddableFactory: (deps: { if (hasRendered$.getValue() === true) return; hasRendered$.next(true); - hasRendered$.complete(); }, onEvent: async (event) => { // Visualize doesn't respond to sizing events, so ignore. @@ -472,7 +472,7 @@ export const getVisualizeEmbeddableFactory: (deps: { return (
        {/* Replicate the loading state for the expression renderer to avoid FOUC */} - + {isLoading && } {!isLoading && error && ( { describe('edit saved visualization route', () => { test('should load instance and initiate an editor if chrome is set up', async () => { - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined, savedVisId) ); @@ -135,7 +135,7 @@ describe('useSavedVisInstance', () => { expect(mockGetVisualizationInstance).toHaveBeenCalledWith(mockServices, savedVisId); expect(mockGetVisualizationInstance.mock.calls.length).toBe(1); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(mockServices.chrome.setBreadcrumbs).toHaveBeenCalledWith('Test Vis'); expect(mockServices.chrome.docTitle.change).toHaveBeenCalledWith('Test Vis'); expect(getEditBreadcrumbs).toHaveBeenCalledWith( @@ -156,7 +156,7 @@ describe('useSavedVisInstance', () => { }, id: 'panel1', }; - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useSavedVisInstance( mockServices, eventEmitter, @@ -171,7 +171,7 @@ describe('useSavedVisInstance', () => { expect(mockGetVisualizationInstance).toHaveBeenCalledWith(mockServices, savedVisId); expect(mockGetVisualizationInstance.mock.calls.length).toBe(1); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(mockServices.chrome.setBreadcrumbs).toHaveBeenCalledWith('Test Vis'); expect(mockServices.chrome.docTitle.change).toHaveBeenCalledWith('Test Vis'); expect(getEditBreadcrumbs).toHaveBeenCalledWith( @@ -189,13 +189,13 @@ describe('useSavedVisInstance', () => { }); test('should destroy the editor and the savedVis on unmount if chrome exists', async () => { - const { result, unmount, waitForNextUpdate } = renderHook(() => + const { result, unmount } = renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined, savedVisId) ); result.current.visEditorRef.current = document.createElement('div'); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); unmount(); expect(mockDefaultEditorControllerDestroy.mock.calls.length).toBe(1); @@ -215,7 +215,7 @@ describe('useSavedVisInstance', () => { }); test('should create new visualization based on search params', async () => { - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useSavedVisInstance(mockServices, eventEmitter, true, undefined, undefined) ); @@ -226,7 +226,7 @@ describe('useSavedVisInstance', () => { type: 'area', }); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(getCreateBreadcrumbs).toHaveBeenCalled(); expect(mockEmbeddableHandlerRender).not.toHaveBeenCalled(); @@ -263,7 +263,7 @@ describe('useSavedVisInstance', () => { describe('embeded mode', () => { test('should create new visualization based on search params', async () => { - const { result, unmount, waitForNextUpdate } = renderHook(() => + const { result, unmount } = renderHook(() => useSavedVisInstance(mockServices, eventEmitter, false, undefined, savedVisId) ); @@ -273,7 +273,7 @@ describe('useSavedVisInstance', () => { expect(mockGetVisualizationInstance).toHaveBeenCalledWith(mockServices, savedVisId); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(mockEmbeddableHandlerRender).toHaveBeenCalled(); expect(result.current.visEditorController).toBeUndefined(); diff --git a/src/plugins/visualizations/public/visualize_app/utils/use/use_visualize_app_state.test.ts b/src/plugins/visualizations/public/visualize_app/utils/use/use_visualize_app_state.test.ts index f92bd7304a7e..7add55761e2a 100644 --- a/src/plugins/visualizations/public/visualize_app/utils/use/use_visualize_app_state.test.ts +++ b/src/plugins/visualizations/public/visualize_app/utils/use/use_visualize_app_state.test.ts @@ -7,7 +7,7 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { EventEmitter } from 'events'; import { Observable } from 'rxjs'; @@ -159,11 +159,11 @@ describe('useVisualizeAppState', () => { it('should successfully update vis state and set up app state container', async () => { stateContainerGetStateMock.mockImplementation(() => state); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useVisualizeAppState(mockServices, eventEmitter, savedVisInstance) ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { aggs, ...visState } = stateContainer.getState().vis; const expectedNewVisState = { @@ -183,11 +183,11 @@ describe('useVisualizeAppState', () => { ...visualizeAppStateStub, query: { query: 'test', language: 'kuery' }, })); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useVisualizeAppState(mockServices, eventEmitter, savedVisInstance) ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { aggs, ...visState } = stateContainer.getState().vis; const expectedNewVisState = { diff --git a/test/functional/apps/console/_autocomplete.ts b/test/functional/apps/console/_autocomplete.ts index 451e54613559..0e29b29e96eb 100644 --- a/test/functional/apps/console/_autocomplete.ts +++ b/test/functional/apps/console/_autocomplete.ts @@ -60,6 +60,28 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(true); }); + it('should not show duplicate suggestions', async () => { + await PageObjects.console.enterText(`POST _ingest/pipeline/_simulate +{ + "pipeline": { + "processors": [ + { + "script": {`); + await PageObjects.console.pressEnter(); + await PageObjects.console.sleepForDebouncePeriod(); + await PageObjects.console.enterText(`"`); + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(true); + + // Iterate on the first 10 suggestions (the ones that are only visible without scrolling) + const suggestions = []; + for (let i = 0; i < 10; i++) { + suggestions.push(await PageObjects.console.getAutocompleteSuggestion(i)); + } + + // and expect the array to not have duplicates + expect(suggestions).to.eql(_.uniq(suggestions)); + }); + describe('Autocomplete behavior', () => { beforeEach(async () => { await PageObjects.console.clearEditorText(); @@ -377,5 +399,41 @@ GET _search expect(await PageObjects.console.getAutocompleteSuggestion(1)).to.be.eql(undefined); }); }); + + describe('Autocomplete shouldnt trigger within', () => { + beforeEach(async () => { + await PageObjects.console.skipTourIfExists(); + await PageObjects.console.clearEditorText(); + }); + + it('a hash comment', async () => { + await PageObjects.console.enterText(`# GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + + it('a simple double slash comment', async () => { + await PageObjects.console.enterText(`// GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + + it('a single line block comment', async () => { + await PageObjects.console.enterText(`/* GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + + it('a multiline block comment', async () => { + await PageObjects.console.enterText(`/* + GET /`); + await PageObjects.console.sleepForDebouncePeriod(); + + expect(PageObjects.console.isAutocompleteVisible()).to.be.eql(false); + }); + }); }); } diff --git a/test/functional/apps/console/_context_menu.ts b/test/functional/apps/console/_context_menu.ts index 4ee3c2cca40a..0e126467c04c 100644 --- a/test/functional/apps/console/_context_menu.ts +++ b/test/functional/apps/console/_context_menu.ts @@ -70,6 +70,55 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { } }); + it('doesnt allow to copy kbn requests as anything other than curl', async () => { + const canReadClipboard = await browser.checkBrowserPermission('clipboard-read'); + + await PageObjects.console.clearEditorText(); + await PageObjects.console.enterText('GET _search\n'); + + // Add a kbn request + // pressEnter + await PageObjects.console.enterText('GET kbn:/api/spaces/space'); + // Make sure to select the es and kbn request + await PageObjects.console.selectAllRequests(); + + await PageObjects.console.clickContextMenu(); + await PageObjects.console.clickCopyAsButton(); + + let resultToast = await toasts.getElementByIndex(1); + let toastText = await resultToast.getVisibleText(); + + expect(toastText).to.be('Requests copied to clipboard as curl'); + + // Check if the clipboard has the curl request + if (canReadClipboard) { + const clipboardText = await browser.getClipboardValue(); + expect(clipboardText).to.contain('curl -X GET'); + } + + // Wait until async operation is done + await PageObjects.common.sleep(1000); + + // Focus editor once again + await PageObjects.console.focusInputEditor(); + + // Try to copy as javascript + await PageObjects.console.clickContextMenu(); + await PageObjects.console.changeLanguageAndCopy('javascript'); + + resultToast = await toasts.getElementByIndex(2); + toastText = await resultToast.getVisibleText(); + + expect(toastText).to.be('Kibana requests can only be copied as curl'); + + // Since we tried to copy as javascript, the clipboard should still have + // the curl request + if (canReadClipboard) { + const clipboardText = await browser.getClipboardValue(); + expect(clipboardText).to.contain('curl -X GET'); + } + }); + it.skip('allows to change default language', async () => { await PageObjects.console.clickContextMenu(); diff --git a/test/functional/apps/context/classic/_discover_navigation.ts b/test/functional/apps/context/classic/_discover_navigation.ts deleted file mode 100644 index 476a4bfac9e1..000000000000 --- a/test/functional/apps/context/classic/_discover_navigation.ts +++ /dev/null @@ -1,168 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const TEST_COLUMN_NAMES = ['@message']; -const TEST_FILTER_COLUMN_NAMES = [ - ['extension', 'jpg', 'extension.raw'], - ['geo.src', 'IN', 'geo.src'], -]; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const retry = getService('retry'); - const docTable = getService('docTable'); - const filterBar = getService('filterBar'); - const { common, discover, timePicker, dashboard, context, header, unifiedFieldList } = - getPageObjects([ - 'common', - 'discover', - 'timePicker', - 'dashboard', - 'context', - 'header', - 'unifiedFieldList', - ]); - const testSubjects = getService('testSubjects'); - const dashboardAddPanel = getService('dashboardAddPanel'); - const browser = getService('browser'); - const kibanaServer = getService('kibanaServer'); - - describe('context link in discover classic', () => { - before(async () => { - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await kibanaServer.uiSettings.update({ - 'doc_table:legacy': true, - defaultIndex: 'logstash-*', - }); - await common.navigateToApp('discover'); - await header.waitUntilLoadingHasFinished(); - for (const columnName of TEST_COLUMN_NAMES) { - await unifiedFieldList.clickFieldListItemAdd(columnName); - } - - for (const [columnName, value] of TEST_FILTER_COLUMN_NAMES) { - await unifiedFieldList.clickFieldListItem(columnName); - await unifiedFieldList.clickFieldListPlusFilter(columnName, value); - } - }); - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should open the context view with the same columns', async () => { - const columnNames = await docTable.getHeaderFields(); - expect(columnNames).to.eql(['@timestamp', ...TEST_COLUMN_NAMES]); - }); - - it('should open the context view with the selected document as anchor and allows selecting next anchor', async () => { - /** - * Helper function to get the first timestamp of the document table - * @param isAnchorRow - determins if just the anchor row of context should be selected - */ - const getTimestamp = async (isAnchorRow: boolean = false) => { - const contextFields = await docTable.getFields({ isAnchorRow }); - return contextFields[0][0]; - }; - // get the timestamp of the first row - - const firstDiscoverTimestamp = await getTimestamp(); - - // check the anchor timestamp in the context view - await retry.waitFor('selected document timestamp matches anchor timestamp ', async () => { - // navigate to the context view - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[0].click(); - await context.waitUntilContextLoadingHasFinished(); - const anchorTimestamp = await getTimestamp(true); - return anchorTimestamp === firstDiscoverTimestamp; - }); - - await retry.waitFor('next anchor timestamp matches previous anchor timestamp', async () => { - // get the timestamp of the first row - const firstContextTimestamp = await getTimestamp(false); - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[0].click(); - await context.waitUntilContextLoadingHasFinished(); - const anchorTimestamp = await getTimestamp(true); - return anchorTimestamp === firstContextTimestamp; - }); - }); - - it('should open the context view with the filters disabled', async () => { - let disabledFilterCounter = 0; - for (const [_, value, columnId] of TEST_FILTER_COLUMN_NAMES) { - if (await filterBar.hasFilter(columnId, value, false)) { - disabledFilterCounter++; - } - } - expect(disabledFilterCounter).to.be(TEST_FILTER_COLUMN_NAMES.length); - }); - - // bugfix: https://github.com/elastic/kibana/issues/92099 - it('should navigate to the first document and then back to discover', async () => { - await context.waitUntilContextLoadingHasFinished(); - - // navigate to the doc view - await docTable.clickRowToggle({ rowIndex: 0 }); - - // click the open action - await retry.try(async () => { - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - if (!rowActions.length) { - throw new Error('row actions empty, trying again'); - } - await rowActions[1].click(); - }); - - const hasDocHit = await testSubjects.exists('doc-hit'); - expect(hasDocHit).to.be(true); - - await testSubjects.click('~breadcrumb & ~first'); - await discover.waitForDiscoverAppOnScreen(); - await discover.waitForDocTableLoadingComplete(); - }); - - it('navigates to doc view from embeddable', async () => { - await common.navigateToApp('discover'); - await discover.saveSearch('my classic search'); - await header.waitUntilLoadingHasFinished(); - - await dashboard.navigateToApp(); - await dashboard.gotoDashboardLandingPage(); - await dashboard.clickNewDashboard(); - - await dashboardAddPanel.addSavedSearch('my classic search'); - await header.waitUntilLoadingHasFinished(); - - await docTable.clickRowToggle({ rowIndex: 0 }); - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - await rowActions[1].click(); - await common.sleep(250); - - // close popup - const alert = await browser.getAlert(); - await alert?.accept(); - if (await testSubjects.exists('confirmModalConfirmButton')) { - await testSubjects.click('confirmModalConfirmButton'); - } - - await retry.waitFor('navigate to doc view', async () => { - const currentUrl = await browser.getCurrentUrl(); - return currentUrl.includes('#/doc'); - }); - await retry.waitFor('doc view being rendered', async () => { - return await discover.isShowingDocViewer(); - }); - }); - }); -} diff --git a/test/functional/apps/context/classic/_filters.ts b/test/functional/apps/context/classic/_filters.ts deleted file mode 100644 index fd2ce16982f3..000000000000 --- a/test/functional/apps/context/classic/_filters.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../../../ftr_provider_context'; - -const TEST_INDEX_PATTERN = 'logstash-*'; -const TEST_ANCHOR_ID = 'AU_x3_BrGFA8no6QjjaI'; -const TEST_ANCHOR_FILTER_FIELD = 'geo.src'; -const TEST_ANCHOR_FILTER_VALUE = 'IN'; -const TEST_COLUMN_NAMES = ['extension', 'geo.src']; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const docTable = getService('docTable'); - const filterBar = getService('filterBar'); - const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); - - const PageObjects = getPageObjects(['common', 'context']); - - describe('context filters', function contextSize() { - before(async function () { - await kibanaServer.uiSettings.update({ 'doc_table:legacy': true }); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - beforeEach(async function () { - await PageObjects.context.navigateTo(TEST_INDEX_PATTERN, TEST_ANCHOR_ID, { - columns: TEST_COLUMN_NAMES, - }); - }); - - it('inclusive filter should be addable via expanded doc table rows', async function () { - await retry.waitFor(`filter ${TEST_ANCHOR_FILTER_FIELD} in filterbar`, async () => { - await docTable.toggleRowExpanded({ isAnchorRow: true }); - const anchorDetailsRow = await docTable.getAnchorDetailsRow(); - await docTable.addInclusiveFilter(anchorDetailsRow, TEST_ANCHOR_FILTER_FIELD); - await PageObjects.context.waitUntilContextLoadingHasFinished(); - - return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, TEST_ANCHOR_FILTER_VALUE, true); - }); - await retry.waitFor(`filter matching docs in docTable`, async () => { - const fields = await docTable.getFields(); - return fields - .map((row) => row[2]) - .every((fieldContent) => fieldContent === TEST_ANCHOR_FILTER_VALUE); - }); - }); - - it('filter for presence should be addable via expanded doc table rows', async function () { - await docTable.toggleRowExpanded({ isAnchorRow: true }); - - await retry.waitFor('an exists filter in the filterbar', async () => { - const anchorDetailsRow = await docTable.getAnchorDetailsRow(); - await docTable.addExistsFilter(anchorDetailsRow, TEST_ANCHOR_FILTER_FIELD); - await PageObjects.context.waitUntilContextLoadingHasFinished(); - return await filterBar.hasFilter(TEST_ANCHOR_FILTER_FIELD, 'exists', true); - }); - }); - }); -} diff --git a/test/functional/apps/context/index.ts b/test/functional/apps/context/index.ts index 2cfc8cf855a2..5cccbf163a8f 100644 --- a/test/functional/apps/context/index.ts +++ b/test/functional/apps/context/index.ts @@ -33,9 +33,7 @@ export default function ({ getService, getPageObjects, loadTestFile }: FtrProvid loadTestFile(require.resolve('./_context_accessibility')); loadTestFile(require.resolve('./_context_navigation')); loadTestFile(require.resolve('./_discover_navigation')); - loadTestFile(require.resolve('./classic/_discover_navigation')); loadTestFile(require.resolve('./_filters')); - loadTestFile(require.resolve('./classic/_filters')); loadTestFile(require.resolve('./_size')); loadTestFile(require.resolve('./_date_nanos')); loadTestFile(require.resolve('./_date_nanos_custom_timestamp')); diff --git a/test/functional/apps/dashboard/group1/embeddable_data_grid.ts b/test/functional/apps/dashboard/group1/embeddable_data_grid.ts index 781f9cda2d68..014d1dd15ed4 100644 --- a/test/functional/apps/dashboard/group1/embeddable_data_grid.ts +++ b/test/functional/apps/dashboard/group1/embeddable_data_grid.ts @@ -16,17 +16,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const esArchiver = getService('esArchiver'); const kibanaServer = getService('kibanaServer'); const find = getService('find'); - const { common, dashboard, header, timePicker } = getPageObjects([ - 'common', - 'dashboard', - 'header', - 'timePicker', - ]); + const { dashboard, header, timePicker } = getPageObjects(['dashboard', 'header', 'timePicker']); const retry = getService('retry'); const dataGrid = getService('dataGrid'); - // FLAKY: https://github.com/elastic/kibana/issues/181955 - describe.skip('dashboard embeddable data grid', () => { + describe('dashboard embeddable data grid', () => { before(async () => { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/dashboard/current/data'); @@ -36,7 +30,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await kibanaServer.uiSettings.replace({ defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c', - 'doc_table:legacy': false, }); await dashboard.navigateToApp(); await filterBar.ensureFieldEditorModalIsClosed(); @@ -62,16 +55,24 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('are added when a cell filter is clicked', async function () { - await find.clickByCssSelector(`[role="gridcell"]:nth-child(4)`); - // needs a short delay between becoming visible & being clickable - await common.sleep(250); - await find.clickByCssSelector(`[data-test-subj="filterOutButton"]`); + const gridCell = '[role="gridcell"]:nth-child(4)'; + const filterOutButton = '[data-test-subj="filterOutButton"]'; + const filterForButton = '[data-test-subj="filterForButton"]'; + await retry.try(async () => { + await find.clickByCssSelector(gridCell); + await find.clickByCssSelector(filterOutButton); + await header.waitUntilLoadingHasFinished(); + const filterCount = await filterBar.getFilterCount(); + expect(filterCount).to.equal(1); + }); await header.waitUntilLoadingHasFinished(); - await find.clickByCssSelector(`[role="gridcell"]:nth-child(4)`); - await common.sleep(250); - await find.clickByCssSelector(`[data-test-subj="filterForButton"]`); - const filterCount = await filterBar.getFilterCount(); - expect(filterCount).to.equal(2); + await retry.try(async () => { + await find.clickByCssSelector(gridCell); + await find.clickByCssSelector(filterForButton); + await header.waitUntilLoadingHasFinished(); + const filterCount = await filterBar.getFilterCount(); + expect(filterCount).to.equal(2); + }); }); }); } diff --git a/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts b/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts index e1935a083996..c80ee8e844cf 100644 --- a/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts +++ b/test/functional/apps/dashboard/group2/dashboard_filter_bar.ts @@ -23,12 +23,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const browser = getService('browser'); const queryBar = getService('queryBar'); const security = getService('security'); - const { dashboard, discover, header, timePicker } = getPageObjects([ - 'dashboard', - 'discover', - 'header', - 'timePicker', - ]); + const { dashboard, header, timePicker } = getPageObjects(['dashboard', 'header', 'timePicker']); describe('dashboard filter bar', () => { before(async () => { @@ -201,12 +196,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('are added when a cell magnifying glass is clicked', async function () { await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search'); await dashboard.waitForRenderComplete(); - const isLegacyDefault = await discover.useLegacyTable(); - if (isLegacyDefault) { - await testSubjects.click('docTableCellFilter'); - } else { - await dataGrid.clickCellFilterForButtonExcludingControlColumns(1, 1); - } + await dataGrid.clickCellFilterForButtonExcludingControlColumns(1, 1); const filterCount = await filterBar.getFilterCount(); expect(filterCount).to.equal(1); }); diff --git a/test/functional/apps/dashboard/group3/dashboard_time_picker.ts b/test/functional/apps/dashboard/group3/dashboard_time_picker.ts index 2e5d4217909f..a1fb468a9dd2 100644 --- a/test/functional/apps/dashboard/group3/dashboard_time_picker.ts +++ b/test/functional/apps/dashboard/group3/dashboard_time_picker.ts @@ -13,16 +13,10 @@ import { PIE_CHART_VIS_NAME } from '../../../page_objects/dashboard_page'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const dashboardExpect = getService('dashboardExpect'); const pieChart = getService('pieChart'); const elasticChart = getService('elasticChart'); const dashboardVisualizations = getService('dashboardVisualizations'); - const { dashboard, header, timePicker, discover } = getPageObjects([ - 'dashboard', - 'header', - 'timePicker', - 'discover', - ]); + const { dashboard, header, timePicker } = getPageObjects(['dashboard', 'header', 'timePicker']); const browser = getService('browser'); const log = getService('log'); const kibanaServer = getService('kibanaServer'); @@ -59,28 +53,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { fields: ['bytes', 'agent'], }); - const isLegacyDefault = await discover.useLegacyTable(); - if (isLegacyDefault) { - await dashboardExpect.docTableFieldCount(150); + const docCount = await dataGrid.getDocCount(); + expect(docCount).to.above(10); - // Set to time range with no data - await timePicker.setAbsoluteRange( - 'Jan 1, 2000 @ 00:00:00.000', - 'Jan 1, 2000 @ 01:00:00.000' - ); - await dashboardExpect.docTableFieldCount(0); - } else { - const docCount = await dataGrid.getDocCount(); - expect(docCount).to.above(10); - - // Set to time range with no data - await timePicker.setAbsoluteRange( - 'Jan 1, 2000 @ 00:00:00.000', - 'Jan 1, 2000 @ 01:00:00.000' - ); - const noResults = await dataGrid.hasNoResults(); - expect(noResults).to.be.ok(); - } + // Set to time range with no data + await timePicker.setAbsoluteRange('Jan 1, 2000 @ 00:00:00.000', 'Jan 1, 2000 @ 01:00:00.000'); + const noResults = await dataGrid.hasNoResults(); + expect(noResults).to.be.ok(); }); it('Timepicker start, end, interval values are set by url', async () => { diff --git a/test/functional/apps/dashboard/group6/dashboard_esql_chart.ts b/test/functional/apps/dashboard/group6/dashboard_esql_chart.ts index 35b7db4fabfc..faaacc48fe97 100644 --- a/test/functional/apps/dashboard/group6/dashboard_esql_chart.ts +++ b/test/functional/apps/dashboard/group6/dashboard_esql_chart.ts @@ -18,6 +18,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const monacoEditor = getService('monacoEditor'); const dashboardAddPanel = getService('dashboardAddPanel'); + const dashboardPanelActions = getService('dashboardPanelActions'); + const log = getService('log'); describe('dashboard add ES|QL chart', function () { before(async () => { @@ -30,6 +32,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); + after(async () => { + await dashboard.navigateToApp(); + await testSubjects.click('discard-unsaved-New-Dashboard'); + }); + it('should add an ES|QL datatable chart when the ES|QL panel action is clicked', async () => { await dashboard.navigateToApp(); await dashboard.clickNewDashboard(); @@ -57,6 +64,47 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); + it('should reset to the previous state on edit inline', async () => { + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.clickAddNewPanelFromUIActionLink('ES|QL'); + await dashboardAddPanel.expectEditorMenuClosed(); + await dashboard.waitForRenderComplete(); + + // Save the panel and close the flyout + log.debug('Applies the changes'); + await testSubjects.click('applyFlyoutButton'); + + // now edit the panel and click on Cancel + await dashboardPanelActions.clickInlineEdit(); + + const metricsConfigured = await testSubjects.findAll( + 'lnsDatatable_metrics > lnsLayerPanel-dimensionLink' + ); + // remove the first metric from the configuration + // Lens is x-pack so not available here, make things manually + await testSubjects.moveMouseTo(`lnsDatatable_metrics > indexPattern-dimension-remove`); + await testSubjects.click(`lnsDatatable_metrics > indexPattern-dimension-remove`); + const beforeCancelMetricsConfigured = await testSubjects.findAll( + 'lnsDatatable_metrics > lnsLayerPanel-dimensionLink' + ); + expect(beforeCancelMetricsConfigured.length).to.eql(metricsConfigured.length - 1); + + // now click cancel + await testSubjects.click('cancelFlyoutButton'); + await dashboard.waitForRenderComplete(); + + // re open the inline editor and check that the configured metrics are still the original ones + await dashboardPanelActions.clickInlineEdit(); + const afterCancelMetricsConfigured = await testSubjects.findAll( + 'lnsDatatable_metrics > lnsLayerPanel-dimensionLink' + ); + expect(afterCancelMetricsConfigured.length).to.eql(metricsConfigured.length); + // delete the panel + await testSubjects.click('cancelFlyoutButton'); + const panels = await dashboard.getDashboardPanels(); + await dashboardPanelActions.removePanel(panels[0]); + }); + it('should be able to edit the query and render another chart', async () => { await dashboardAddPanel.clickEditorMenuButton(); await dashboardAddPanel.clickAddNewPanelFromUIActionLink('ES|QL'); @@ -70,5 +118,41 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('applyFlyoutButton'); expect(await testSubjects.exists('mtrVis')).to.be(true); }); + + it('should add a second panel and remove when hitting cancel', async () => { + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.clickAddNewPanelFromUIActionLink('ES|QL'); + await dashboardAddPanel.expectEditorMenuClosed(); + await dashboard.waitForRenderComplete(); + // Cancel + await testSubjects.click('cancelFlyoutButton'); + // Test that there's only 1 panel left + await dashboard.waitForRenderComplete(); + await retry.try(async () => { + const panelCount = await dashboard.getPanelCount(); + expect(panelCount).to.eql(1); + }); + }); + + it('should not remove the first panel of two when editing and cancelling', async () => { + // add a second panel + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.clickAddNewPanelFromUIActionLink('ES|QL'); + await dashboardAddPanel.expectEditorMenuClosed(); + await dashboard.waitForRenderComplete(); + // save it + await testSubjects.click('applyFlyoutButton'); + await dashboard.waitForRenderComplete(); + + // now edit the first one + const [firstPanel] = await dashboard.getDashboardPanels(); + await dashboardPanelActions.clickInlineEdit(firstPanel); + await testSubjects.click('cancelFlyoutButton'); + await dashboard.waitForRenderComplete(); + await retry.try(async () => { + const panelCount = await dashboard.getPanelCount(); + expect(panelCount).to.eql(2); + }); + }); }); } diff --git a/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts b/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts index 333ac7f01539..4298ccdfb588 100644 --- a/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts +++ b/test/functional/apps/dashboard/group6/dashboard_esql_no_data.ts @@ -31,7 +31,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.dashboard.expectOnDashboard('New Dashboard'); expect(await testSubjects.exists('lnsVisualizationContainer')).to.be(true); - await panelActions.clickInlineEdit(); + await panelActions.clickEdit(); const editorValue = await monacoEditor.getCodeEditorValue(); expect(editorValue).to.eql(`FROM logs* | LIMIT 10`); }); diff --git a/test/functional/apps/dashboard/group6/view_edit.ts b/test/functional/apps/dashboard/group6/view_edit.ts index 487adc753e65..9304b51d302d 100644 --- a/test/functional/apps/dashboard/group6/view_edit.ts +++ b/test/functional/apps/dashboard/group6/view_edit.ts @@ -25,7 +25,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const security = getService('security'); - describe('dashboard view edit mode', function viewEditModeTests() { + // Failing: See https://github.com/elastic/kibana/issues/200748 + describe.skip('dashboard view edit mode', function viewEditModeTests() { before(async () => { await kibanaServer.savedObjects.cleanStandardList(); await kibanaServer.importExport.load( diff --git a/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts b/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts deleted file mode 100644 index c56ecc020f2b..000000000000 --- a/test/functional/apps/discover/classic/_classic_table_doc_navigation.ts +++ /dev/null @@ -1,75 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const docTable = getService('docTable'); - const filterBar = getService('filterBar'); - const testSubjects = getService('testSubjects'); - const { common, discover, timePicker } = getPageObjects(['common', 'discover', 'timePicker']); - const esArchiver = getService('esArchiver'); - const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); - - describe('classic table doc link', function contextSize() { - before(async () => { - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await kibanaServer.uiSettings.update({ - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - 'discover:searchFieldsFromSource': true, - }); - }); - after(async () => { - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); - await kibanaServer.uiSettings.replace({}); - }); - - beforeEach(async function () { - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await common.navigateToApp('discover'); - await discover.waitForDocTableLoadingComplete(); - }); - - it('should open the doc view of the selected document', async function () { - // navigate to the doc view - await docTable.clickRowToggle({ rowIndex: 0 }); - - // click the open action - await retry.try(async () => { - const rowActions = await docTable.getRowActions({ rowIndex: 0 }); - if (!rowActions.length) { - throw new Error('row actions empty, trying again'); - } - await rowActions[1].click(); - }); - - await retry.waitFor('hit loaded', async () => { - const hasDocHit = await testSubjects.exists('doc-hit'); - return !!hasDocHit; - }); - }); - - it('should create an exists filter from the doc view of the selected document', async function () { - await discover.waitUntilSearchingHasFinished(); - - await docTable.toggleRowExpanded(); - const detailsRow = await docTable.getDetailsRow(); - await docTable.addExistsFilter(detailsRow, '@timestamp'); - - const hasExistsFilter = await filterBar.hasFilter('@timestamp', 'exists', true, false, false); - expect(hasExistsFilter).to.be(true); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_discover_fields_api.ts b/test/functional/apps/discover/classic/_discover_fields_api.ts deleted file mode 100644 index e0fe867a25c8..000000000000 --- a/test/functional/apps/discover/classic/_discover_fields_api.ts +++ /dev/null @@ -1,98 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const log = getService('log'); - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const { common, discover, timePicker, settings, unifiedFieldList } = getPageObjects([ - 'common', - 'discover', - 'timePicker', - 'settings', - 'unifiedFieldList', - ]); - const defaultSettings = { - defaultIndex: 'logstash-*', - 'discover:searchFieldsFromSource': false, - 'doc_table:legacy': true, - }; - describe('discover uses fields API test', function describeIndexTests() { - before(async function () { - log.debug('load kibana index with default index pattern'); - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should correctly display documents', async function () { - log.debug('check if Document title exists in the grid'); - expect(await discover.getDocHeader()).to.have.string('Document'); - const rowData = await discover.getDocTableIndex(1); - log.debug('check the newest doc timestamp in UTC (check diff timezone in last test)'); - expect(rowData.startsWith('Sep 22, 2015 @ 23:50:13.253')).to.be.ok(); - const expectedHitCount = '14,004'; - await retry.try(async function () { - expect(await discover.getHitCount()).to.be(expectedHitCount); - }); - }); - - it('adding a column removes a default column', async function () { - await unifiedFieldList.clickFieldListItemAdd('_score'); - expect(await discover.getDocHeader()).to.have.string('_score'); - expect(await discover.getDocHeader()).not.to.have.string('Document'); - }); - - it('removing a column adds a default column', async function () { - await unifiedFieldList.clickFieldListItemRemove('_score'); - expect(await discover.getDocHeader()).not.to.have.string('_score'); - expect(await discover.getDocHeader()).to.have.string('Document'); - }); - - it('displays _source viewer in doc viewer', async function () { - await discover.clickDocTableRowToggle(0); - await discover.isShowingDocViewer(); - await discover.clickDocViewerTab('doc_view_source'); - await discover.expectSourceViewerToExist(); - }); - - it('switches to _source column when fields API is no longer used', async function () { - await settings.navigateTo(); - await settings.clickKibanaSettings(); - await settings.toggleAdvancedSettingCheckbox('discover:searchFieldsFromSource'); - - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - - expect(await discover.getDocHeader()).to.have.string('_source'); - }); - - it('switches to Document column when fields API is used', async function () { - await settings.navigateTo(); - await settings.clickKibanaSettings(); - await settings.toggleAdvancedSettingCheckbox('discover:searchFieldsFromSource'); - - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - - expect(await discover.getDocHeader()).to.have.string('Document'); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_doc_table.ts b/test/functional/apps/discover/classic/_doc_table.ts deleted file mode 100644 index 5c765a6b2ef2..000000000000 --- a/test/functional/apps/discover/classic/_doc_table.ts +++ /dev/null @@ -1,309 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const browser = getService('browser'); - const log = getService('log'); - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const docTable = getService('docTable'); - const queryBar = getService('queryBar'); - const find = getService('find'); - const { common, discover, header, timePicker, unifiedFieldList } = getPageObjects([ - 'common', - 'discover', - 'header', - 'timePicker', - 'unifiedFieldList', - ]); - const defaultSettings = { - defaultIndex: 'logstash-*', - hideAnnouncements: true, - 'doc_table:legacy': true, - }; - const testSubjects = getService('testSubjects'); - - describe('discover doc table', function describeIndexTests() { - const rowsHardLimit = 500; - - before(async function () { - log.debug('load kibana index with default index pattern'); - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - - // and load a set of makelogs data - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - log.debug('discover doc table'); - await common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover.json'); - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.uiSettings.replace({}); - }); - - it('should show records by default', async function () { - // with the default range the number of hits is ~14000 - const rows = await discover.getDocTableRows(); - expect(rows.length).to.be.greaterThan(0); - }); - - it('should refresh the table content when changing time window', async function () { - const initialRows = await discover.getDocTableRows(); - - const fromTime = 'Sep 20, 2015 @ 23:00:00.000'; - const toTime = 'Sep 20, 2015 @ 23:14:00.000'; - - await timePicker.setAbsoluteRange(fromTime, toTime); - await discover.waitUntilSearchingHasFinished(); - - const finalRows = await discover.getDocTableRows(); - expect(finalRows.length).to.be.below(initialRows.length); - await timePicker.setDefaultAbsoluteRange(); - }); - - describe('classic table in window 900x700', function () { - before(async () => { - await browser.setWindowSize(900, 700); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - it('should load more rows when scrolling down the document table', async function () { - const initialRows = await testSubjects.findAll('docTableRow'); - await testSubjects.scrollIntoView('discoverBackToTop'); - // now count the rows - await retry.waitFor('next batch of documents to be displayed', async () => { - const actual = await testSubjects.findAll('docTableRow'); - log.debug(`initial doc nr: ${initialRows.length}, actual doc nr: ${actual.length}`); - return actual.length > initialRows.length; - }); - }); - }); - - describe('classic table in window 600x700', function () { - before(async () => { - await browser.setWindowSize(600, 700); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - it('should load more rows when scrolling down the document table', async function () { - const initialRows = await testSubjects.findAll('docTableRow'); - await testSubjects.scrollIntoView('discoverBackToTop'); - // now count the rows - await retry.waitFor('next batch of documents to be displayed', async () => { - const actual = await testSubjects.findAll('docTableRow'); - log.debug(`initial doc nr: ${initialRows.length}, actual doc nr: ${actual.length}`); - return actual.length > initialRows.length; - }); - }); - }); - - describe('legacy', function () { - before(async () => { - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - it(`should load up to ${rowsHardLimit} rows when scrolling at the end of the table`, async function () { - const initialRows = await testSubjects.findAll('docTableRow'); - // click the Skip to the end of the table - await discover.skipToEndOfDocTable(); - // now count the rows - const finalRows = await testSubjects.findAll('docTableRow'); - expect(finalRows.length).to.be.above(initialRows.length); - expect(finalRows.length).to.be(rowsHardLimit); - await discover.backToTop(); - }); - - it('should go the end and back to top of the classic table when using the accessible buttons', async function () { - // click the Skip to the end of the table - await discover.skipToEndOfDocTable(); - // now check the footer text content - const footer = await discover.getDocTableFooter(); - expect(await footer.getVisibleText()).to.have.string(rowsHardLimit); - await discover.backToTop(); - // check that the skip to end of the table button now has focus - const skipButton = await testSubjects.find('discoverSkipTableButton'); - const activeElement = await find.activeElement(); - const activeElementText = await activeElement.getVisibleText(); - const skipButtonText = await skipButton.getVisibleText(); - expect(skipButtonText === activeElementText).to.be(true); - }); - - describe('expand a document row', function () { - const rowToInspect = 1; - beforeEach(async function () { - // close the toggle if open - const details = await docTable.getDetailsRows(); - if (details.length) { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - } - }); - - it('should expand the detail row when the toggle arrow is clicked', async function () { - await retry.try(async function () { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - const detailsEl = await docTable.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject( - 'docViewerRowDetailsTitle' - ); - expect(defaultMessageEl).to.be.ok(); - }); - }); - - it('should show the detail panel actions', async function () { - await retry.try(async function () { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - // const detailsEl = await discover.getDocTableRowDetails(rowToInspect); - const [surroundingActionEl, singleActionEl] = await docTable.getRowActions({ - isAnchorRow: false, - rowIndex: rowToInspect - 1, - }); - expect(surroundingActionEl).to.be.ok(); - expect(singleActionEl).to.be.ok(); - // TODO: test something more meaninful here? - }); - }); - - it('should not close the detail panel actions when data is re-requested', async function () { - await retry.try(async function () { - const nrOfFetches = await discover.getNrOfFetches(); - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - const detailsEl = await docTable.getDetailsRows(); - const defaultMessageEl = await detailsEl[0].findByTestSubject( - 'docViewerRowDetailsTitle' - ); - expect(defaultMessageEl).to.be.ok(); - await queryBar.submitQuery(); - const nrOfFetchesResubmit = await discover.getNrOfFetches(); - expect(nrOfFetchesResubmit).to.be.above(nrOfFetches); - const defaultMessageElResubmit = await detailsEl[0].findByTestSubject( - 'docViewerRowDetailsTitle' - ); - - expect(defaultMessageElResubmit).to.be.ok(); - }); - }); - - it('should show allow toggling columns from the expanded document', async function () { - await discover.clickNewSearchButton(); - await retry.try(async function () { - await docTable.clickRowToggle({ isAnchorRow: false, rowIndex: rowToInspect - 1 }); - - // add columns - const fields = ['_id', '_index', 'agent']; - for (const field of fields) { - await testSubjects.click(`toggleColumnButton-${field}`); - await testSubjects.click(`tableDocViewRow-${field}`); // to suppress the appeared tooltip - } - - const headerWithFields = await docTable.getHeaderFields(); - expect(headerWithFields.join(' ')).to.contain(fields.join(' ')); - - // remove columns - for (const field of fields) { - await testSubjects.click(`toggleColumnButton-${field}`); - await testSubjects.click(`tableDocViewRow-${field}`); - } - - const headerWithoutFields = await docTable.getHeaderFields(); - expect(headerWithoutFields.join(' ')).not.to.contain(fields.join(' ')); - }); - }); - }); - - describe('add and remove columns', function () { - const extraColumns = ['phpmemory', 'ip']; - const expectedFieldLength: Record = { - phpmemory: 1, - ip: 4, - }; - afterEach(async function () { - for (const column of extraColumns) { - await unifiedFieldList.clickFieldListItemRemove(column); - await header.waitUntilLoadingHasFinished(); - } - }); - - it('should add more columns to the table', async function () { - for (const column of extraColumns) { - await unifiedFieldList.clearFieldSearchInput(); - await unifiedFieldList.findFieldByName(column); - await unifiedFieldList.waitUntilFieldlistHasCountOfFields(expectedFieldLength[column]); - await retry.waitFor('field to appear', async function () { - return await testSubjects.exists(`field-${column}`); - }); - await unifiedFieldList.clickFieldListItemAdd(column); - await header.waitUntilLoadingHasFinished(); - // test the header now - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - const docHeaderText = await docHeader.getVisibleText(); - expect(docHeaderText).to.have.string(column); - } - }); - - it('should remove columns from the table', async function () { - for (const column of extraColumns) { - await unifiedFieldList.clearFieldSearchInput(); - await unifiedFieldList.findFieldByName(column); - await unifiedFieldList.waitUntilFieldlistHasCountOfFields(expectedFieldLength[column]); - await unifiedFieldList.clickFieldListItemAdd(column); - await header.waitUntilLoadingHasFinished(); - } - // remove the second column - await unifiedFieldList.clickFieldListItemRemove(extraColumns[1]); - await header.waitUntilLoadingHasFinished(); - // test that the second column is no longer there - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - expect(await docHeader.getVisibleText()).to.not.have.string(extraColumns[1]); - }); - }); - - it('should make the document table scrollable', async function () { - await unifiedFieldList.clearFieldSearchInput(); - const dscTableWrapper = await find.byCssSelector('.kbnDocTableWrapper'); - const fieldNames = await unifiedFieldList.getAllFieldNames(); - const clientHeight = await dscTableWrapper.getAttribute('clientHeight'); - let fieldCounter = 0; - const checkScrollable = async () => { - const scrollWidth = await dscTableWrapper.getAttribute('scrollWidth'); - const clientWidth = await dscTableWrapper.getAttribute('clientWidth'); - log.debug(`scrollWidth: ${scrollWidth}, clientWidth: ${clientWidth}`); - return Number(scrollWidth) > Number(clientWidth); - }; - const addColumn = async () => { - await unifiedFieldList.clickFieldListItemAdd(fieldNames[fieldCounter++]); - }; - - await addColumn(); - const isScrollable = await checkScrollable(); - expect(isScrollable).to.be(false); - - await retry.waitForWithTimeout('container to be scrollable', 60 * 1000, async () => { - await addColumn(); - return await checkScrollable(); - }); - // so now we need to check if the horizontal scrollbar is displayed - const newClientHeight = await dscTableWrapper.getAttribute('clientHeight'); - expect(Number(clientHeight)).to.be.above(Number(newClientHeight)); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_doc_table_newline.ts b/test/functional/apps/discover/classic/_doc_table_newline.ts deleted file mode 100644 index 3c2b426a2dbe..000000000000 --- a/test/functional/apps/discover/classic/_doc_table_newline.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const { common, unifiedFieldList } = getPageObjects(['common', 'unifiedFieldList']); - const find = getService('find'); - const log = getService('log'); - const retry = getService('retry'); - const security = getService('security'); - - describe('discover doc table newline handling', function describeIndexTests() { - before(async function () { - await security.testUser.setRoles(['kibana_admin', 'kibana_message_with_newline']); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/message_with_newline'); - await kibanaServer.importExport.load( - 'test/functional/fixtures/kbn_archiver/message_with_newline.json' - ); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'newline-test', - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - }); - - after(async () => { - await security.testUser.restoreDefaults(); - await esArchiver.unload('test/functional/fixtures/es_archiver/message_with_newline'); - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.uiSettings.replace({}); - }); - - it('should break text on newlines', async function () { - await unifiedFieldList.clickFieldListItemToggle('message'); - const dscTableRows = await find.allByCssSelector('.kbnDocTable__row'); - - await retry.waitFor('height of multi-line content > single-line content', async () => { - const heightWithoutNewline = await dscTableRows[0].getAttribute('clientHeight'); - const heightWithNewline = await dscTableRows[1].getAttribute('clientHeight'); - log.debug(`Without newlines: ${heightWithoutNewline}, With newlines: ${heightWithNewline}`); - - await common.sleep(10000); - return Number(heightWithNewline) > Number(heightWithoutNewline); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_esql_grid.ts b/test/functional/apps/discover/classic/_esql_grid.ts deleted file mode 100644 index 94dcabdba4ef..000000000000 --- a/test/functional/apps/discover/classic/_esql_grid.ts +++ /dev/null @@ -1,95 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); - const security = getService('security'); - const dataGrid = getService('dataGrid'); - const dashboardAddPanel = getService('dashboardAddPanel'); - const dashboardPanelActions = getService('dashboardPanelActions'); - const { common, discover, dashboard, header, timePicker } = getPageObjects([ - 'common', - 'discover', - 'dashboard', - 'header', - 'timePicker', - ]); - - const defaultSettings = { - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - }; - - describe('discover esql grid with legacy setting', function () { - before(async () => { - await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace(defaultSettings); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.savedObjects.cleanStandardList(); - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({}); - }); - - it('should render esql view correctly', async function () { - const savedSearchESQL = 'testESQLWithLegacySetting'; - await header.waitUntilLoadingHasFinished(); - await discover.waitUntilSearchingHasFinished(); - - await testSubjects.existOrFail('docTableHeader'); - await testSubjects.missingOrFail('euiDataGridBody'); - - await discover.selectTextBaseLang(); - - await header.waitUntilLoadingHasFinished(); - await discover.waitUntilSearchingHasFinished(); - - await testSubjects.missingOrFail('docTableHeader'); - await testSubjects.existOrFail('euiDataGridBody'); - - await dataGrid.clickRowToggle({ rowIndex: 0 }); - - await testSubjects.existOrFail('docViewerFlyout'); - - await discover.saveSearch(savedSearchESQL); - - await common.navigateToApp('dashboard'); - await dashboard.clickNewDashboard(); - await timePicker.setDefaultAbsoluteRange(); - await dashboardAddPanel.clickOpenAddPanel(); - await dashboardAddPanel.addSavedSearch(savedSearchESQL); - await header.waitUntilLoadingHasFinished(); - - await testSubjects.missingOrFail('docTableHeader'); - await testSubjects.existOrFail('euiDataGridBody'); - - await dataGrid.clickRowToggle({ rowIndex: 0 }); - - await testSubjects.existOrFail('docViewerFlyout'); - - await dashboardPanelActions.removePanelByTitle(savedSearchESQL); - - await dashboardAddPanel.addSavedSearch('A Saved Search'); - - await header.waitUntilLoadingHasFinished(); - await testSubjects.existOrFail('docTableHeader'); - await testSubjects.missingOrFail('euiDataGridBody'); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_field_data.ts b/test/functional/apps/discover/classic/_field_data.ts deleted file mode 100644 index 2ebd49bb24ae..000000000000 --- a/test/functional/apps/discover/classic/_field_data.ts +++ /dev/null @@ -1,63 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const retry = getService('retry'); - const esArchiver = getService('esArchiver'); - const kibanaServer = getService('kibanaServer'); - const { common, timePicker } = getPageObjects(['common', 'timePicker']); - const find = getService('find'); - const testSubjects = getService('testSubjects'); - - describe('discover tab', function describeIndexTests() { - this.tags('includeFirefox'); - before(async function () { - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'discover:searchFieldsFromSource': true, - 'doc_table:legacy': true, - }); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - it('doc view should show @timestamp and _source columns', async function () { - const expectedHeader = '@timestamp\n_source'; - const docHeader = await find.byCssSelector('thead > tr:nth-child(1)'); - const docHeaderText = await docHeader.getVisibleText(); - expect(docHeaderText).to.be(expectedHeader); - }); - - it('doc view should sort ascending', async function () { - const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - - // we don't technically need this sleep here because the tryForTime will retry and the - // results will match on the 2nd or 3rd attempt, but that debug output is huge in this - // case and it can be avoided with just a few seconds sleep. - await common.sleep(2000); - await retry.try(async function tryingForTime() { - const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); - const rowData = await row.getVisibleText(); - expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_field_data_with_fields_api.ts b/test/functional/apps/discover/classic/_field_data_with_fields_api.ts deleted file mode 100644 index 4932ba3e2434..000000000000 --- a/test/functional/apps/discover/classic/_field_data_with_fields_api.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const retry = getService('retry'); - const kibanaServer = getService('kibanaServer'); - const { common, timePicker } = getPageObjects(['common', 'timePicker']); - const find = getService('find'); - const esArchiver = getService('esArchiver'); - const testSubjects = getService('testSubjects'); - - describe('discover tab with new fields API', function describeIndexTests() { - before(async function () { - await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'discover:searchFieldsFromSource': false, - 'doc_table:legacy': true, - }); - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await common.navigateToApp('discover'); - }); - - after(async function () { - await kibanaServer.uiSettings.replace({}); - }); - - it('doc view should sort ascending', async function () { - const expectedTimeStamp = 'Sep 20, 2015 @ 00:00:00.000'; - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - - // we don't technically need this sleep here because the tryForTime will retry and the - // results will match on the 2nd or 3rd attempt, but that debug output is huge in this - // case and it can be avoided with just a few seconds sleep. - await common.sleep(2000); - await retry.try(async function tryingForTime() { - const row = await find.byCssSelector(`tr.kbnDocTable__row:nth-child(1)`); - const rowData = await row.getVisibleText(); - - expect(rowData.startsWith(expectedTimeStamp)).to.be.ok(); - }); - }); - }); -} diff --git a/test/functional/apps/discover/classic/_hide_announcements.ts b/test/functional/apps/discover/classic/_hide_announcements.ts deleted file mode 100644 index df7fcbb62813..000000000000 --- a/test/functional/apps/discover/classic/_hide_announcements.ts +++ /dev/null @@ -1,49 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const { common, discover, timePicker } = getPageObjects(['common', 'discover', 'timePicker']); - const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); - const browser = getService('browser'); - - describe('test hide announcements', function () { - before(async function () { - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should display try document explorer button', async function () { - await discover.selectIndexPattern('logstash-*'); - const tourButtonExists = await testSubjects.exists('tryDocumentExplorerButton'); - expect(tourButtonExists).to.be(true); - }); - - it('should not display try document explorer button', async function () { - await kibanaServer.uiSettings.update({ hideAnnouncements: true }); - await browser.refresh(); - const tourButtonExists = await testSubjects.exists('tryDocumentExplorerButton'); - expect(tourButtonExists).to.be(false); - }); - }); -} diff --git a/test/functional/apps/discover/classic/index.ts b/test/functional/apps/discover/classic/index.ts deleted file mode 100644 index fce8963d1908..000000000000 --- a/test/functional/apps/discover/classic/index.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, loadTestFile }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const browser = getService('browser'); - - describe('discover/classic', function () { - before(async function () { - await browser.setWindowSize(1300, 800); - }); - - after(async function unloadMakelogs() { - await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); - }); - - loadTestFile(require.resolve('./_discover_fields_api')); - loadTestFile(require.resolve('./_doc_table')); - loadTestFile(require.resolve('./_doc_table_newline')); - loadTestFile(require.resolve('./_field_data')); - loadTestFile(require.resolve('./_field_data_with_fields_api')); - loadTestFile(require.resolve('./_classic_table_doc_navigation')); - loadTestFile(require.resolve('./_hide_announcements')); - loadTestFile(require.resolve('./_esql_grid')); - }); -} diff --git a/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts b/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts index 7e7a12840f76..5fd8e97c8f05 100644 --- a/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts +++ b/test/functional/apps/discover/context_awareness/extensions/_get_default_app_state.ts @@ -40,8 +40,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); } + function expectBreakdown(breakdown: string) { + return retry.try(async () => { + const breakdownFieldValue = await discover.getBreakdownFieldValue(); + expect(breakdownFieldValue).to.be(breakdown); + }); + } + describe('ES|QL mode', () => { - it('should render default columns and row height', async () => { + it('should render default state', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -57,9 +64,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should render default columns and row height when switching index patterns', async () => { + it('should render state when switching index patterns', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -83,9 +91,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should reset default columns and row height when clicking "New"', async () => { + it('should reset default state when clicking "New"', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -111,6 +120,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); it('should merge and dedup configured default columns with default profile columns', async () => { @@ -131,7 +141,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('data view mode', () => { - it('should render default columns and row height', async () => { + it('should render default state', async () => { await common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -144,9 +154,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should render default columns and row height when switching data views', async () => { + it('should render default state when switching data views', async () => { await common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -166,9 +177,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should reset default columns and row height when clicking "New"', async () => { + it('should reset default state when clicking "New"', async () => { await common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -190,6 +202,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); it('should merge and dedup configured default columns with default profile columns', async () => { diff --git a/test/functional/apps/discover/esql/_esql_view.ts b/test/functional/apps/discover/esql/_esql_view.ts index d27df2244b18..65d8b7ce698b 100644 --- a/test/functional/apps/discover/esql/_esql_view.ts +++ b/test/functional/apps/discover/esql/_esql_view.ts @@ -383,6 +383,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); await testSubjects.click('querySubmitButton'); await header.waitUntilLoadingHasFinished(); + // for some reason the chart query is taking a very long time to return (3x the delay) + // so wait for the chart to be loaded + await discover.waitForChartLoadingComplete(1); await browser.execute(() => { window.ELASTIC_ESQL_DELAY_SECONDS = undefined; }); diff --git a/test/functional/apps/discover/group1/_date_nanos_mixed.ts b/test/functional/apps/discover/group1/_date_nanos_mixed.ts index 7162d01bb96c..a30c4a316351 100644 --- a/test/functional/apps/discover/group1/_date_nanos_mixed.ts +++ b/test/functional/apps/discover/group1/_date_nanos_mixed.ts @@ -45,14 +45,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('shows a list of records of indices with date & date_nanos fields in the right order', async function () { - const isLegacy = await discover.useLegacyTable(); const rowData1 = await discover.getDocTableIndex(1); expect(rowData1).to.contain('Jan 1, 2019 @ 12:10:30.124000000'); - const rowData2 = await discover.getDocTableIndex(isLegacy ? 3 : 2); + const rowData2 = await discover.getDocTableIndex(2); expect(rowData2).to.contain('Jan 1, 2019 @ 12:10:30.123498765'); - const rowData3 = await discover.getDocTableIndex(isLegacy ? 5 : 3); + const rowData3 = await discover.getDocTableIndex(3); expect(rowData3).to.contain('Jan 1, 2019 @ 12:10:30.123456789'); - const rowData4 = await discover.getDocTableIndex(isLegacy ? 7 : 4); + const rowData4 = await discover.getDocTableIndex(4); expect(rowData4).to.contain('Jan 1, 2019 @ 12:10:30.123000000'); }); }); diff --git a/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts b/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts index b50cd7e16cf0..e801b40a8003 100644 --- a/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts +++ b/test/functional/apps/discover/group2_data_grid3/_data_grid_density.ts @@ -52,9 +52,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataGrid.changeDensityValue('Normal'); // toggle the popover - // Right now changing the density closes the popover (see packages/kbn-unified-data-table/src/components/data_table.tsx:1144) - // When that workaround is removed we will need to uncomment this next line - // await dataGrid.clickGridSettings(); + await dataGrid.clickGridSettings(); await dataGrid.clickGridSettings(); expect(await dataGrid.getCurrentDensityValue()).to.be('Normal'); }); @@ -62,7 +60,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should persist the density selection after reloading the page', async () => { await dataGrid.clickGridSettings(); await dataGrid.changeDensityValue('Expanded'); - await dataGrid.clickGridSettings(); expect(await dataGrid.getCurrentDensityValue()).to.be('Expanded'); await browser.refresh(); diff --git a/test/functional/apps/discover/group3/_request_counts.ts b/test/functional/apps/discover/group3/_request_counts.ts index 8a029928af0c..32f1be5a62e7 100644 --- a/test/functional/apps/discover/group3/_request_counts.ts +++ b/test/functional/apps/discover/group3/_request_counts.ts @@ -97,7 +97,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expectedRequests?: number; expectedRefreshRequest?: number; }) => { - it(`should send ${expectedRequests} search requests (documents + chart) on page load`, async () => { + it(`should send no more than ${expectedRequests} search requests (documents + chart) on page load`, async () => { await browser.refresh(); await browser.execute(async () => { performance.setResourceTimingBufferSize(Number.MAX_SAFE_INTEGER); @@ -107,20 +107,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(searchCount).to.be(expectedRequests); }); - it(`should send ${expectedRequests} requests (documents + chart) when refreshing`, async () => { + it(`should send no more than ${expectedRequests} requests (documents + chart) when refreshing`, async () => { await expectSearches(type, expectedRequests, async () => { await queryBar.clickQuerySubmitButton(); }); }); - it(`should send ${expectedRequests} requests (documents + chart) when changing the query`, async () => { + it(`should send no more than ${expectedRequests} requests (documents + chart) when changing the query`, async () => { await expectSearches(type, expectedRequests, async () => { await setQuery(query1); await queryBar.clickQuerySubmitButton(); }); }); - it(`should send ${expectedRequests} requests (documents + chart) when changing the time range`, async () => { + it(`should send no more than ${expectedRequests} requests (documents + chart) when changing the time range`, async () => { await expectSearches(type, expectedRequests, async () => { await timePicker.setAbsoluteRange( 'Sep 21, 2015 @ 06:31:44.000', @@ -174,7 +174,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { setQuery: (query) => queryBar.setQuery(query), }); - it(`should send 2 requests (documents + chart) when toggling the chart visibility`, async () => { + it(`should send no more than 2 requests (documents + chart) when toggling the chart visibility`, async () => { await expectSearches(type, 2, async () => { await discover.toggleChartVisibility(); }); @@ -183,7 +183,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should send 2 requests (documents + chart) when adding a filter', async () => { + it('should send no more than 2 requests (documents + chart) when adding a filter', async () => { await expectSearches(type, 2, async () => { await filterBar.addFilter({ field: 'extension', @@ -193,31 +193,31 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should send 2 requests (documents + chart) when sorting', async () => { + it('should send no more than 2 requests (documents + chart) when sorting', async () => { await expectSearches(type, 2, async () => { await discover.clickFieldSort('@timestamp', 'Sort Old-New'); }); }); - it('should send 2 requests (documents + chart) when changing to a breakdown field without an other bucket', async () => { + it('should send no more than 2 requests (documents + chart) when changing to a breakdown field without an other bucket', async () => { await expectSearches(type, 2, async () => { await discover.chooseBreakdownField('type'); }); }); - it('should send 3 requests (documents + chart + other bucket) when changing to a breakdown field with an other bucket', async () => { + it('should send no more than 3 requests (documents + chart + other bucket) when changing to a breakdown field with an other bucket', async () => { await expectSearches(type, 3, async () => { await discover.chooseBreakdownField('extension.raw'); }); }); - it('should send 2 requests (documents + chart) when changing the chart interval', async () => { + it('should send no more than 2 requests (documents + chart) when changing the chart interval', async () => { await expectSearches(type, 2, async () => { await discover.setChartInterval('Day'); }); }); - it('should send 2 requests (documents + chart) when changing the data view', async () => { + it('should send no more than 2 requests (documents + chart) when changing the data view', async () => { await expectSearches(type, 2, async () => { await discover.selectIndexPattern('long-window-logstash-*'); }); diff --git a/test/functional/apps/discover/group4/_data_view_edit.ts b/test/functional/apps/discover/group4/_data_view_edit.ts index c0c521601019..9abefdb31115 100644 --- a/test/functional/apps/discover/group4/_data_view_edit.ts +++ b/test/functional/apps/discover/group4/_data_view_edit.ts @@ -18,11 +18,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const dataViews = getService('dataViews'); - const { common, discover, timePicker, unifiedFieldList } = getPageObjects([ + const { common, discover, timePicker, unifiedFieldList, header } = getPageObjects([ 'common', 'discover', 'timePicker', 'unifiedFieldList', + 'header', ]); describe('data view flyout', function () { @@ -40,23 +41,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.savedObjects.cleanStandardList(); await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await es.transport.request({ - path: '/my-index-000001', + path: '/data-view-index-000001', method: 'DELETE', }); await es.transport.request({ - path: '/my-index-000002', + path: '/data-view-index-000002', method: 'DELETE', }); await es.transport.request({ - path: '/my-index-000003', + path: '/data-view-index-000003', method: 'DELETE', }); }); it('create ad hoc data view', async function () { - const initialPattern = 'my-index-'; + const initialPattern = 'data-view-index-'; await es.transport.request({ - path: '/my-index-000001/_doc', + path: '/data-view-index-000001/_doc', method: 'POST', body: { '@timestamp': new Date().toISOString(), @@ -65,7 +66,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); await es.transport.request({ - path: '/my-index-000002/_doc', + path: '/data-view-index-000002/_doc', method: 'POST', body: { '@timestamp': new Date().toISOString(), @@ -87,12 +88,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('create saved data view', async function () { - const updatedPattern = 'my-index-000001'; + const updatedPattern = 'data-view-index-000001'; await dataViews.createFromSearchBar({ name: updatedPattern, adHoc: false, hasTimeField: true, }); + await header.waitUntilLoadingHasFinished(); await discover.waitUntilSearchingHasFinished(); await retry.try(async () => { @@ -104,9 +106,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('update data view with a different time field', async function () { - const updatedPattern = 'my-index-000003'; + const updatedPattern = 'data-view-index-000003'; await es.transport.request({ - path: '/my-index-000003/_doc', + path: '/data-view-index-000003/_doc', method: 'POST', body: { timestamp: new Date('1970-01-01').toISOString(), @@ -116,7 +118,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); for (let i = 0; i < 3; i++) { await es.transport.request({ - path: '/my-index-000003/_doc', + path: '/data-view-index-000003/_doc', method: 'POST', body: { timestamp: new Date().toISOString(), diff --git a/test/functional/apps/discover/group6/_sidebar.ts b/test/functional/apps/discover/group6/_sidebar.ts index a88623bb58d1..01adcb7a0a90 100644 --- a/test/functional/apps/discover/group6/_sidebar.ts +++ b/test/functional/apps/discover/group6/_sidebar.ts @@ -28,10 +28,27 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const filterBar = getService('filterBar'); const fieldEditor = getService('fieldEditor'); const dataViews = getService('dataViews'); + const queryBar = getService('queryBar'); const retry = getService('retry'); const dataGrid = getService('dataGrid'); + const log = getService('log'); const INITIAL_FIELD_LIST_SUMMARY = '48 available fields. 5 empty fields. 4 meta fields.'; + const expectFieldListDescription = async (expectedNumber: string) => { + return await retry.try(async () => { + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + const ariaDescription = await unifiedFieldList.getSidebarAriaDescription(); + if (ariaDescription !== expectedNumber) { + log.warning( + `Expected Sidebar Aria Description: ${expectedNumber}, got: ${ariaDescription}` + ); + await queryBar.submitQuery(); + } + expect(ariaDescription).to.be(expectedNumber); + }); + }; + describe('discover sidebar', function describeIndexTests() { before(async function () { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); @@ -65,35 +82,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.waitUntilSidebarHasLoaded(); await unifiedFieldList.openSidebarFieldFilter(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await testSubjects.click('typeFilter-keyword'); - - await retry.waitFor('first updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '6 available fields. 1 empty field. 3 meta fields.' - ); - }); + // first update + await expectFieldListDescription('6 available fields. 1 empty field. 3 meta fields.'); await testSubjects.click('typeFilter-number'); - await retry.waitFor('second updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '10 available fields. 3 empty fields. 4 meta fields.' - ); - }); + // second update + await expectFieldListDescription('10 available fields. 3 empty fields. 4 meta fields.'); await testSubjects.click('fieldListFiltersFieldTypeFilterClearAll'); - await retry.waitFor('reset', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === INITIAL_FIELD_LIST_SUMMARY - ); - }); + // reset + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should show filters by type in ES|QL view', async function () { @@ -114,18 +117,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { options = await find.allByCssSelector('[data-test-subj*="typeFilter"]'); expect(options).to.have.length(6); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '76 available fields. 6 empty fields.' - ); - + await expectFieldListDescription('76 available fields. 6 empty fields.'); await testSubjects.click('typeFilter-number'); - - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 2 empty fields.' - ); - }); + await expectFieldListDescription('4 available fields. 2 empty fields.'); }); it('should show empty fields in ES|QL view', async function () { @@ -138,52 +132,29 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await header.waitUntilLoadingHasFinished(); await unifiedFieldList.waitUntilSidebarHasLoaded(); await unifiedFieldList.openSidebarFieldFilter(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '2 selected fields. 1 available field. 1 empty field.' - ); + await expectFieldListDescription('2 selected fields. 1 available field. 1 empty field.'); }); }); describe('search', function () { beforeEach(async () => { - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); afterEach(async () => { const fieldSearch = await testSubjects.find('clearSearchButton'); await fieldSearch.click(); - await retry.waitFor('reset', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === INITIAL_FIELD_LIST_SUMMARY - ); - }); + // reset + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should be able to search by string', async function () { await unifiedFieldList.findFieldByName('i'); - await retry.waitFor('first updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '28 available fields. 2 empty fields. 3 meta fields.' - ); - }); - + await expectFieldListDescription('28 available fields. 2 empty fields. 3 meta fields.'); await unifiedFieldList.findFieldByName('p'); - - await retry.waitFor('second updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'clientip, ip, relatedContent.og:description, relatedContent.twitter:description' @@ -192,13 +163,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search by wildcard', async function () { await unifiedFieldList.findFieldByName('relatedContent*image'); - - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '2 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('2 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'relatedContent.og:image, relatedContent.twitter:image' @@ -208,12 +173,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search with spaces as wildcard', async function () { await unifiedFieldList.findFieldByName('relatedContent image'); - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'relatedContent.og:image, relatedContent.og:image:height, relatedContent.og:image:width, relatedContent.twitter:image' @@ -222,13 +182,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search with fuzzy search (1 typo)', async function () { await unifiedFieldList.findFieldByName('rel4tedContent.art'); - - await retry.waitFor('updates', async () => { - return ( - (await unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ')).to.be( 'relatedContent.article:modified_time, relatedContent.article:published_time, relatedContent.article:section, relatedContent.article:tag' @@ -243,9 +197,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); // expect no changes in the list - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); }); @@ -345,10 +297,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect((await unifiedFieldList.getSidebarSectionFieldNames('meta')).join(', ')).to.be( '_id, _ignored, _index, _score' ); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should show field list groups excluding subfields when searched from source', async function () { @@ -387,7 +336,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'relatedContent' ); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '48 available fields. 1 unmapped field. 5 empty fields. 4 meta fields.' ); }); @@ -406,7 +355,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(availableFields.includes('extension')).to.be(true); expect(availableFields.includes('@message')).to.be(true); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '2 selected fields. 2 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); @@ -426,52 +375,35 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { '@message, _id, extension' ); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); // verify popular fields were persisted await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); }); it('should show selected and available fields in ES|QL mode', async function () { - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await discover.selectTextBaseLang(); await monacoEditor.setCodeEditorValue('from logstash-* | limit 10000'); await testSubjects.click('querySubmitButton'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '76 available fields. 6 empty fields.' - ); + await expectFieldListDescription('76 available fields. 6 empty fields.'); await unifiedFieldList.clickFieldListItemRemove('extension'); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '76 available fields. 6 empty fields.' - ); + await expectFieldListDescription('76 available fields. 6 empty fields.'); const testQuery = `from logstash-* | limit 10 | stats countB = count(bytes) by geo.dest | sort countB`; await monacoEditor.setCodeEditorValue(testQuery); await testSubjects.click('querySubmitButton'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '2 selected fields. 2 available fields.' - ); + await expectFieldListDescription('2 selected fields. 2 available fields.'); expect((await unifiedFieldList.getSidebarSectionFieldNames('selected')).join(', ')).to.be( 'countB, geo.dest' ); @@ -480,12 +412,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedSearch.switchDataView('discover-dataView-switch-link', 'logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '48 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('48 available fields. 5 empty fields. 4 meta fields.'); }); it('should work correctly for a data view for a missing index', async function () { @@ -494,20 +421,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('with-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 0 meta fields.' - ); + await expectFieldListDescription('0 available fields. 0 meta fields.'); await testSubjects.missingOrFail( `${unifiedFieldList.getSidebarSectionSelector('available')}-fetchWarning` ); @@ -517,12 +435,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataViews.switchToAndValidate('logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); @@ -537,41 +450,22 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('without-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '6 available fields. 4 meta fields.' - ); + await expectFieldListDescription('6 available fields. 4 meta fields.'); await dataViews.switchToAndValidate('with-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 7 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('0 available fields. 7 empty fields. 4 meta fields.'); await testSubjects.existOrFail( `${unifiedFieldList.getSidebarSectionSelector('available')}NoFieldsCallout-noFieldsMatch` ); await dataViews.switchToAndValidate('logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' @@ -583,11 +477,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should work when filters change', async () => { - await header.waitUntilLoadingHasFinished(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await unifiedFieldList.clickFieldListItem('extension'); expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( @@ -595,12 +485,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await filterBar.addFilter({ field: 'extension', operation: 'is', value: 'jpg' }); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); // check that the filter was passed down to the sidebar await unifiedFieldList.clickFieldListItem('extension'); @@ -614,29 +500,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('indices-stats*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '6873 available fields. 4 meta fields.' - ); + await expectFieldListDescription('6873 available fields. 4 meta fields.'); await dataViews.switchToAndValidate('logstash-*'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/many_fields_data_view' @@ -650,12 +522,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { adHoc: true, hasTimeField: true, }); - await discover.waitUntilSearchingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await discover.addRuntimeField( '_bytes-runtimefield', @@ -666,12 +534,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return !(await testSubjects.exists('fieldEditor')); }); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); let allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield')).to.be(true); @@ -685,23 +548,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return !(await testSubjects.exists('fieldEditor')); }); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield2')).to.be(true); expect(allFields.includes('_bytes-runtimefield')).to.be(false); await discover.removeField('_bytes-runtimefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield2')).to.be(false); @@ -709,11 +562,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should render even when retrieving documents failed with an error', async () => { - await header.waitUntilLoadingHasFinished(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await discover.addRuntimeField('_invalid-runtimefield', `emit(‘’);`); @@ -725,9 +574,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await unifiedFieldList.waitUntilSidebarHasLoaded(); // check that the sidebar is rendered - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); let allFields = await unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_invalid-runtimefield')).to.be(true); @@ -754,20 +601,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('with-timefield'); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 7 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('0 available fields. 7 empty fields. 4 meta fields.'); await testSubjects.existOrFail( `${unifiedFieldList.getSidebarSectionSelector('available')}NoFieldsCallout-noFieldsMatch` ); @@ -777,12 +615,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'Sep 23, 2019 @ 00:00:00.000' ); - await header.waitUntilLoadingHasFinished(); - await unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await unifiedFieldList.getSidebarAriaDescription()).to.be( - '7 available fields. 4 meta fields.' - ); + await expectFieldListDescription('7 available fields. 4 meta fields.'); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' diff --git a/test/functional/apps/discover/group6/_time_field_column.ts b/test/functional/apps/discover/group6/_time_field_column.ts index 5965b7765e18..9e5ce3f94a45 100644 --- a/test/functional/apps/discover/group6/_time_field_column.ts +++ b/test/functional/apps/discover/group6/_time_field_column.ts @@ -34,7 +34,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dataViews = getService('dataViews'); const testSubjects = getService('testSubjects'); const security = getService('security'); - const docTable = getService('docTable'); const defaultSettings = { defaultIndex: 'logstash-*', hideAnnouncements: true, @@ -228,7 +227,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await timePicker.setDefaultAbsoluteRangeViaUiSettings(); await kibanaServer.uiSettings.update({ ...defaultSettings, - 'doc_table:legacy': false, 'doc_table:hideTimeColumn': hideTimeFieldColumnSetting, }); await common.navigateToApp('discover'); @@ -319,103 +317,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); }); - - // These tests are skipped as they take a lot of time to run. Temporary unskip them to validate current functionality if necessary. - describe.skip('legacy table', () => { - beforeEach(async () => { - await kibanaServer.uiSettings.update({ - ...defaultSettings, - 'doc_table:hideTimeColumn': hideTimeFieldColumnSetting, - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - it('should render initial columns correctly', async () => { - // no columns - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['Summary'] : ['@timestamp', 'Summary'] - ); - - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}-`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['Summary']); - - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}ESQL`); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['Summary'] : ['@timestamp', 'Summary'] - ); - - await discover.loadSavedSearch(`${SEARCH_NO_COLUMNS}${savedSearchSuffix}ESQLdrop`); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql(['Summary']); - - // only @timestamp is selected - await discover.loadSavedSearch(`${SEARCH_WITH_ONLY_TIMESTAMP}${savedSearchSuffix}`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['@timestamp'] : ['@timestamp', '@timestamp'] - ); - - await discover.loadSavedSearch(`${SEARCH_WITH_ONLY_TIMESTAMP}${savedSearchSuffix}-`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['@timestamp']); - - await discover.loadSavedSearch(`${SEARCH_WITH_ONLY_TIMESTAMP}${savedSearchSuffix}ESQL`); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting ? ['@timestamp'] : ['@timestamp', 'Summary'] - ); - }); - - it('should render selected columns correctly', async () => { - // with selected columns - await discover.loadSavedSearch(`${SEARCH_WITH_SELECTED_COLUMNS}${savedSearchSuffix}`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting - ? ['bytes', 'extension'] - : ['@timestamp', 'bytes', 'extension'] - ); - - await discover.loadSavedSearch(`${SEARCH_WITH_SELECTED_COLUMNS}${savedSearchSuffix}-`); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['bytes', 'extension']); - - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS}${savedSearchSuffix}ESQL` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql(['bytes', 'extension']); - - // with selected columns and @timestamp - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS_AND_TIMESTAMP}${savedSearchSuffix}` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql( - hideTimeFieldColumnSetting - ? ['bytes', 'extension', '@timestamp'] - : ['@timestamp', 'bytes', 'extension', '@timestamp'] - ); - - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS_AND_TIMESTAMP}${savedSearchSuffix}-` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await docTable.getHeaderFields()).to.eql(['bytes', 'extension', '@timestamp']); - - await discover.loadSavedSearch( - `${SEARCH_WITH_SELECTED_COLUMNS_AND_TIMESTAMP}${savedSearchSuffix}ESQL` - ); - await discover.waitUntilSearchingHasFinished(); - expect(await dataGrid.getHeaderFields()).to.eql(['bytes', 'extension', '@timestamp']); - }); - }); }); }); }); diff --git a/test/functional/apps/discover/group6/_view_mode_toggle.ts b/test/functional/apps/discover/group6/_view_mode_toggle.ts index 2591716c87d0..4ff5339b8084 100644 --- a/test/functional/apps/discover/group6/_view_mode_toggle.ts +++ b/test/functional/apps/discover/group6/_view_mode_toggle.ts @@ -33,102 +33,75 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + await timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update(defaultSettings); + await common.navigateToApp('discover'); + await discover.waitUntilSearchingHasFinished(); }); after(async () => { await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); await esArchiver.unload('test/functional/fixtures/es_archiver/logstash_functional'); await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.uiSettings.replace({}); }); - [true, false].forEach((useLegacyTable) => { - describe(`isLegacy: ${useLegacyTable}`, function () { - before(async function () { - await timePicker.setDefaultAbsoluteRangeViaUiSettings(); - await kibanaServer.uiSettings.update({ - ...defaultSettings, - 'doc_table:legacy': useLegacyTable, - }); - await common.navigateToApp('discover'); - await discover.waitUntilSearchingHasFinished(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should show Documents tab', async () => { - await testSubjects.existOrFail('dscViewModeToggle'); - - if (!useLegacyTable) { - await testSubjects.existOrFail('unifiedDataTableToolbar'); - } - - const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); - expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); - }); - - it('should show legacy Document Explorer info callout', async () => { - if (useLegacyTable) { - await testSubjects.existOrFail('dscDocumentExplorerLegacyCallout'); - } else { - await testSubjects.missingOrFail('dscDocumentExplorerLegacyCallout'); - } - }); - - it('should show an error callout', async () => { - await queryBar.setQuery('@message::'); // invalid - await queryBar.submitQuery(); - await header.waitUntilLoadingHasFinished(); - - await discover.showsErrorCallout(); - - await queryBar.clearQuery(); - await queryBar.submitQuery(); - await header.waitUntilLoadingHasFinished(); - - await testSubjects.missingOrFail('discoverErrorCalloutTitle'); - }); - - describe('Patterns tab (basic license)', function () { - this.tags('skipFIPS'); - - it('should not show', async function () { - await testSubjects.missingOrFail('dscViewModePatternAnalysisButton'); - }); - }); - - it('should not show Field Statistics tab', async () => { - await testSubjects.existOrFail('dscViewModeToggle'); - }); - - it('should not show view mode toggle for ES|QL searches', async () => { - await testSubjects.click('dscViewModeDocumentButton'); - - await retry.try(async () => { - const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); - expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); - }); - - await testSubjects.existOrFail('dscViewModeToggle'); - - await discover.selectTextBaseLang(); - - await testSubjects.missingOrFail('dscViewModeToggle'); - await testSubjects.existOrFail('discoverQueryTotalHits'); - - if (!useLegacyTable) { - await testSubjects.existOrFail('unifiedDataTableToolbar'); - } - }); - - it('should show ES|QL columns callout', async () => { - await testSubjects.missingOrFail('dscSelectedColumnsCallout'); - await unifiedFieldList.clickFieldListItemAdd('extension'); - await header.waitUntilLoadingHasFinished(); - await testSubjects.existOrFail('dscSelectedColumnsCallout'); - }); + it('should show Documents tab', async () => { + await testSubjects.existOrFail('dscViewModeToggle'); + await testSubjects.existOrFail('unifiedDataTableToolbar'); + + const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); + expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); + }); + + it('should show an error callout', async () => { + await queryBar.setQuery('@message::'); // invalid + await queryBar.submitQuery(); + await header.waitUntilLoadingHasFinished(); + + await discover.showsErrorCallout(); + + await queryBar.clearQuery(); + await queryBar.submitQuery(); + await header.waitUntilLoadingHasFinished(); + + await testSubjects.missingOrFail('discoverErrorCalloutTitle'); + }); + + describe('Patterns tab (basic license)', function () { + this.tags('skipFIPS'); + + it('should not show', async function () { + await testSubjects.missingOrFail('dscViewModePatternAnalysisButton'); + }); + }); + + it('should not show Field Statistics tab', async () => { + await testSubjects.existOrFail('dscViewModeToggle'); + }); + + it('should not show view mode toggle for ES|QL searches', async () => { + await testSubjects.click('dscViewModeDocumentButton'); + + await retry.try(async () => { + const documentsTab = await testSubjects.find('dscViewModeDocumentButton'); + expect(await documentsTab.getAttribute('aria-selected')).to.be('true'); }); + + await testSubjects.existOrFail('dscViewModeToggle'); + + await discover.selectTextBaseLang(); + + await testSubjects.missingOrFail('dscViewModeToggle'); + await testSubjects.existOrFail('discoverQueryTotalHits'); + await testSubjects.existOrFail('unifiedDataTableToolbar'); + }); + + it('should show ES|QL columns callout', async () => { + await testSubjects.missingOrFail('dscSelectedColumnsCallout'); + await unifiedFieldList.clickFieldListItemAdd('extension'); + await header.waitUntilLoadingHasFinished(); + await testSubjects.existOrFail('dscSelectedColumnsCallout'); }); }); } diff --git a/test/functional/apps/discover/group7/_runtime_fields_editor.ts b/test/functional/apps/discover/group7/_runtime_fields_editor.ts index ab8711c362b7..e93e73650b46 100644 --- a/test/functional/apps/discover/group7/_runtime_fields_editor.ts +++ b/test/functional/apps/discover/group7/_runtime_fields_editor.ts @@ -234,17 +234,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // navigate to doc view const fieldName = '_runtimefield-doc-view'; await createRuntimeField(fieldName); - const table = await discover.getDocTable(); - const useLegacyTable = await discover.useLegacyTable(); - await table.clickRowToggle(); + await dataGrid.clickRowToggle(); // click the open action await retry.try(async () => { - const rowActions = await table.getRowActions({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); if (!rowActions.length) { throw new Error('row actions empty, trying again'); } - const idxToClick = useLegacyTable ? 1 : 0; + const idxToClick = 0; await rowActions[idxToClick].click(); }); diff --git a/test/functional/apps/discover/group8/_hide_announcements.ts b/test/functional/apps/discover/group8/_hide_announcements.ts deleted file mode 100644 index 9dc11f9eefca..000000000000 --- a/test/functional/apps/discover/group8/_hide_announcements.ts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the "Elastic License - * 2.0", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const esArchiver = getService('esArchiver'); - const { common, discover, timePicker } = getPageObjects(['common', 'discover', 'timePicker']); - const kibanaServer = getService('kibanaServer'); - const testSubjects = getService('testSubjects'); - const browser = getService('browser'); - const security = getService('security'); - - describe('test hide announcements', function () { - before(async function () { - await security.testUser.setRoles(['kibana_admin', 'test_logstash_reader']); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover.json'); - await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); - await kibanaServer.uiSettings.replace({ - defaultIndex: 'logstash-*', - 'doc_table:legacy': true, - }); - await common.navigateToApp('discover'); - await timePicker.setDefaultAbsoluteRange(); - }); - - after(async () => { - await kibanaServer.uiSettings.replace({}); - }); - - it('should display callout', async function () { - await discover.selectIndexPattern('logstash-*'); - const calloutExists = await testSubjects.exists('dscDocumentExplorerLegacyCallout'); - expect(calloutExists).to.be(true); - }); - - it('should not display callout', async function () { - await kibanaServer.uiSettings.update({ hideAnnouncements: true }); - await browser.refresh(); - const calloutExists = await testSubjects.exists('dscDocumentExplorerLegacyCallout'); - expect(calloutExists).to.be(false); - }); - }); -} diff --git a/test/functional/apps/discover/group8/index.ts b/test/functional/apps/discover/group8/index.ts index 14b544e2c201..46d5040fee29 100644 --- a/test/functional/apps/discover/group8/index.ts +++ b/test/functional/apps/discover/group8/index.ts @@ -23,7 +23,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { }); loadTestFile(require.resolve('./_default_route')); - loadTestFile(require.resolve('./_hide_announcements')); loadTestFile(require.resolve('./_flyouts')); }); } diff --git a/test/functional/apps/management/data_views/_field_formatter.ts b/test/functional/apps/management/data_views/_field_formatter.ts index 1f7cd6c23a83..bd88d96f9700 100644 --- a/test/functional/apps/management/data_views/_field_formatter.ts +++ b/test/functional/apps/management/data_views/_field_formatter.ts @@ -403,8 +403,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { beforeSave: async () => { await testSubjects.click('colorEditorAddColor'); await testSubjects.setValue('~colorEditorKeyPattern', 'red'); - await testSubjects.setValue('~colorEditorColorPicker', '#ffffff'); - await testSubjects.setValue('~colorEditorBackgroundPicker', '#ff0000'); + await testSubjects.click('~colorEditorColorPicker'); + await testSubjects.setValue('~euiColorPickerInput_bottom', '#ffffff'); + await testSubjects.click('~colorEditorBackgroundPicker'); + await testSubjects.setValue('~euiColorPickerInput_bottom', '#ff0000'); }, expect: async (renderedValueContainer) => { const span = await renderedValueContainer.findByTagName('span'); diff --git a/test/functional/apps/management/data_views/_scripted_fields.ts b/test/functional/apps/management/data_views/_scripted_fields.ts index f86ae72aa504..df51514425a2 100644 --- a/test/functional/apps/management/data_views/_scripted_fields.ts +++ b/test/functional/apps/management/data_views/_scripted_fields.ts @@ -387,14 +387,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('docTableHeaderFieldSort_@timestamp'); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\ntrue'); }); await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\nfalse'); }); }); @@ -469,14 +469,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.click('docTableHeaderFieldSort_@timestamp'); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); }); await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); await PageObjects.header.waitUntilLoadingHasFinished(); await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); + const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); }); }); diff --git a/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts b/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts deleted file mode 100644 index 4f3d30222e49..000000000000 --- a/test/functional/apps/management/data_views/_scripted_fields_classic_table.ts +++ /dev/null @@ -1,463 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -// Tests for 4 scripted fields; -// 1. Painless (number type) -// 2. Painless (string type) -// 3. Painless (boolean type) -// 4. Painless (date type) -// -// Each of these scripted fields has 4 tests (12 tests total); -// 1. Create scripted field -// 2. See the expected value of the scripted field in Discover doc view -// 3. Filter in Discover by the scripted field -// 4. Visualize with aggregation on the scripted field by clicking unifiedFieldList.clickFieldListItemVisualize - -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../../ftr_provider_context'; - -export default function ({ getService, getPageObjects }: FtrProviderContext) { - const kibanaServer = getService('kibanaServer'); - const log = getService('log'); - const browser = getService('browser'); - const retry = getService('retry'); - const testSubjects = getService('testSubjects'); - const filterBar = getService('filterBar'); - const docTable = getService('docTable'); - const PageObjects = getPageObjects([ - 'common', - 'header', - 'settings', - 'visualize', - 'discover', - 'timePicker', - 'unifiedFieldList', - ]); - - describe('scripted fields', function () { - this.tags(['skipFirefox']); - - before(async function () { - await browser.setWindowSize(1200, 800); - await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); - await kibanaServer.uiSettings.replace({}); - await kibanaServer.uiSettings.update({ - 'doc_table:legacy': true, - }); - }); - - after(async function afterAll() { - await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); - await kibanaServer.uiSettings.replace({}); - }); - - it('should not allow saving of invalid scripts', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - await PageObjects.settings.clickScriptedFieldsTab(); - await PageObjects.settings.clickAddScriptedField(); - await PageObjects.settings.setScriptedFieldName('doomedScriptedField'); - await PageObjects.settings.setScriptedFieldScript(`i n v a l i d s c r i p t`); - await PageObjects.settings.clickSaveScriptedField(); - await retry.try(async () => { - const invalidScriptErrorExists = await testSubjects.exists('invalidScriptError'); - expect(invalidScriptErrorExists).to.be(true); - }); - }); - - describe('testing regression for issue #33251', function describeIndexTests() { - const scriptedPainlessFieldName = 'ram_Pain_reg'; - - it('should create and edit scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - const script = `1`; - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName, - 'painless', - 'number', - null, - '1', - script - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - - for (let i = 0; i < 3; i++) { - await PageObjects.settings.editScriptedField(scriptedPainlessFieldName); - const fieldSaveButton = await testSubjects.exists('fieldSaveButton'); - expect(fieldSaveButton).to.be(true); - await PageObjects.settings.clickSaveScriptedField(); - } - }); - }); - - describe('creating and using Painless numeric scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName = 'ram_Pain1'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - const script = `if (doc['machine.ram'].size() == 0) return -1; - else return doc['machine.ram'].value / (1024 * 1024 * 1024); - `; - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName, - 'painless', - 'number', - null, - '100', - script - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; - const toTime = 'Sep 18, 2015 @ 18:31:44.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18'); - }); - }); - - // add a test to sort numeric scripted field - it('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 10:53:14.181\n-1'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\n20'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName); - await log.debug('filter by the first value (14) in the expanded scripted field list'); - await PageObjects.unifiedFieldList.clickFieldListPlusFilter( - scriptedPainlessFieldName, - '14' - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('31'); - }); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await filterBar.removeAllFilters(); - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( - '@timestamp', - 'Median of ram_Pain1' - ); - }); - }); - - describe('creating and using Painless string scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName2 = 'painString'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName2, - 'painless', - 'string', - null, - '1', - "if (doc['response.raw'].value == '200') { return 'good'} else { return 'bad'}" - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; - const toTime = 'Sep 18, 2015 @ 18:31:44.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood'); - }); - }); - - // add a test to sort string scripted field - it('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 09:48:40.594\nbad'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 17, 2015 @ 06:32:29.479\ngood'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); - await log.debug('filter by "bad" in the expanded scripted field list'); - await PageObjects.unifiedFieldList.clickFieldListPlusFilter( - scriptedPainlessFieldName2, - 'bad' - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('27'); - }); - await filterBar.removeAllFilters(); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( - 'Top 5 values of painString' - ); - }); - }); - - describe('creating and using Painless boolean scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName2 = 'painBool'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName2, - 'painless', - 'boolean', - null, - '1', - "doc['response.raw'].value == '200'" - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 06:31:44.000'; - const toTime = 'Sep 18, 2015 @ 18:31:44.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.unifiedFieldList.clickFieldListItem(scriptedPainlessFieldName2); - await log.debug('filter by "true" in the expanded scripted field list'); - await PageObjects.unifiedFieldList.clickFieldListPlusFilter( - scriptedPainlessFieldName2, - 'true' - ); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('359'); - }); - await filterBar.removeAllFilters(); - }); - - // add a test to sort boolean - // existing bug: https://github.com/elastic/kibana/issues/75519 hence the issue is skipped. - it.skip('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\ntrue'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\nfalse'); - }); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain( - 'Top 5 values of painBool' - ); - }); - }); - - describe('creating and using Painless date scripted fields', function describeIndexTests() { - const scriptedPainlessFieldName2 = 'painDate'; - - it('should create scripted field', async function () { - await PageObjects.settings.navigateTo(); - await PageObjects.settings.clickKibanaIndexPatterns(); - await PageObjects.settings.clickIndexPatternLogstash(); - const startingCount = parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10); - await PageObjects.settings.clickScriptedFieldsTab(); - await log.debug('add scripted field'); - await PageObjects.settings.addScriptedField( - scriptedPainlessFieldName2, - 'painless', - 'date', - { format: 'date', datePattern: 'YYYY-MM-DD HH:00' }, - '1', - "doc['utc_time'].value.toEpochMilli() + (1000) * 60 * 60" - ); - await retry.try(async function () { - expect(parseInt(await PageObjects.settings.getScriptedFieldsTabCount(), 10)).to.be( - startingCount + 1 - ); - }); - }); - - it('should see scripted field value in Discover', async function () { - const fromTime = 'Sep 17, 2015 @ 19:22:00.000'; - const toTime = 'Sep 18, 2015 @ 07:00:00.000'; - await PageObjects.common.navigateToApp('discover'); - await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - - await retry.try(async function () { - await PageObjects.unifiedFieldList.clickFieldListItemAdd(scriptedPainlessFieldName2); - }); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00'); - }); - }); - - // add a test to sort date scripted field - // https://github.com/elastic/kibana/issues/75711 - it.skip('should sort scripted field value in Discover', async function () { - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - // after the first click on the scripted field, it becomes secondary sort after time. - // click on the timestamp twice to make it be the secondary sort key. - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await testSubjects.click('docTableHeaderFieldSort_@timestamp'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); - }); - - await testSubjects.click(`docTableHeaderFieldSort_${scriptedPainlessFieldName2}`); - await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.try(async function () { - const rowData = await PageObjects.discover.getDocTableIndexLegacy(1); - expect(rowData).to.be('updateExpectedResultHere\n2015-09-18 07:00'); - }); - }); - - it('should filter by scripted field value in Discover', async function () { - await PageObjects.header.waitUntilLoadingHasFinished(); - await docTable.toggleRowExpanded(); - const firstRow = await docTable.getDetailsRow(); - await docTable.addInclusiveFilter(firstRow, scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - - await retry.try(async function () { - expect(await PageObjects.discover.getHitCount()).to.be('1'); - }); - await filterBar.removeAllFilters(); - }); - - it('should visualize scripted field in vertical bar chart', async function () { - await PageObjects.unifiedFieldList.clickFieldListItemVisualize(scriptedPainlessFieldName2); - await PageObjects.header.waitUntilLoadingHasFinished(); - // verify Lens opens a visualization - expect(await testSubjects.getVisibleTextAll('lns-dimensionTrigger')).to.contain('painDate'); - }); - }); - }); -} diff --git a/test/functional/apps/management/index.ts b/test/functional/apps/management/index.ts index 2300543f06d5..962aa41bd8ba 100644 --- a/test/functional/apps/management/index.ts +++ b/test/functional/apps/management/index.ts @@ -31,7 +31,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./_mgmt_import_saved_objects')); loadTestFile(require.resolve('./data_views/_index_patterns_empty')); loadTestFile(require.resolve('./data_views/_scripted_fields')); - loadTestFile(require.resolve('./data_views/_scripted_fields_classic_table')); loadTestFile(require.resolve('./data_views/_runtime_fields')); loadTestFile(require.resolve('./data_views/_runtime_fields_composite')); loadTestFile(require.resolve('./data_views/_field_formatter')); diff --git a/test/functional/apps/visualize/group3/_annotation_listing.ts b/test/functional/apps/visualize/group3/_annotation_listing.ts index a6a174343009..1ec8fb8cdea9 100644 --- a/test/functional/apps/visualize/group3/_annotation_listing.ts +++ b/test/functional/apps/visualize/group3/_annotation_listing.ts @@ -177,7 +177,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { dataView: 'logs*', }); expect(await annotationEditor.showingMissingDataViewPrompt()).to.be(false); - expect(await find.byCssSelector('canvas')).to.be.ok(); + // @TODO: re-enable this once the error bubbling issue is fixed at Lens custom component level + // expect(await find.byCssSelector('canvas')).to.be.ok(); }); await annotationEditor.saveGroup(); diff --git a/test/functional/firefox/discover.config.ts b/test/functional/firefox/discover.config.ts index 7012a3bccad1..9c4c689f0e8c 100644 --- a/test/functional/firefox/discover.config.ts +++ b/test/functional/firefox/discover.config.ts @@ -18,7 +18,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...baseConfig.getAll(), testFiles: [ - require.resolve('../apps/discover/classic'), require.resolve('../apps/discover/esql'), require.resolve('../apps/discover/group1'), require.resolve('../apps/discover/group2_data_grid1'), diff --git a/test/functional/page_objects/console_page.ts b/test/functional/page_objects/console_page.ts index a80f3426e256..30a4b27c3f03 100644 --- a/test/functional/page_objects/console_page.ts +++ b/test/functional/page_objects/console_page.ts @@ -52,6 +52,13 @@ export class ConsolePageObject extends FtrService { await textArea.clearValueWithKeyboard(); } + public async focusInputEditor() { + const outputEditor = await this.testSubjects.find('consoleMonacoEditor'); + // Simply clicking on the editor doesn't focus it, so we need to click + // on the margin view overlays + await (await outputEditor.findByClassName('margin-view-overlays')).click(); + } + public async focusOutputEditor() { const outputEditor = await this.testSubjects.find('consoleMonacoOutput'); // Simply clicking on the output editor doesn't focus it, so we need to click diff --git a/test/functional/page_objects/dashboard_page.ts b/test/functional/page_objects/dashboard_page.ts index 2a263e9aa8ca..c9ba5b0c5fa8 100644 --- a/test/functional/page_objects/dashboard_page.ts +++ b/test/functional/page_objects/dashboard_page.ts @@ -49,7 +49,6 @@ export class DashboardPageObject extends FtrService { private readonly common = this.ctx.getPageObject('common'); private readonly header = this.ctx.getPageObject('header'); private readonly visualize = this.ctx.getPageObject('visualize'); - private readonly discover = this.ctx.getPageObject('discover'); private readonly appsMenu = this.ctx.getService('appsMenu'); private readonly toasts = this.ctx.getService('toasts'); @@ -271,22 +270,12 @@ export class DashboardPageObject extends FtrService { */ public async expectToolbarPaginationDisplayed() { - const isLegacyDefault = await this.discover.useLegacyTable(); - if (isLegacyDefault) { - const subjects = [ - 'pagination-button-previous', - 'pagination-button-next', - 'toolBarTotalDocsText', - ]; - await Promise.all(subjects.map(async (subj) => await this.testSubjects.existOrFail(subj))); - } else { - const subjects = ['pagination-button-previous', 'pagination-button-next']; + const subjects = ['pagination-button-previous', 'pagination-button-next']; - await Promise.all(subjects.map(async (subj) => await this.testSubjects.existOrFail(subj))); - const paginationListExists = await this.find.existsByCssSelector('.euiPagination__list'); - if (!paginationListExists) { - throw new Error(`expected discover data grid pagination list to exist`); - } + await Promise.all(subjects.map(async (subj) => await this.testSubjects.existOrFail(subj))); + const paginationListExists = await this.find.existsByCssSelector('.euiPagination__list'); + if (!paginationListExists) { + throw new Error(`expected discover data grid pagination list to exist`); } } diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 8feccfd955c7..1f5945ff379f 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -22,10 +22,8 @@ export class DiscoverPageObject extends FtrService { private readonly browser = this.ctx.getService('browser'); private readonly globalNav = this.ctx.getService('globalNav'); private readonly elasticChart = this.ctx.getService('elasticChart'); - private readonly docTable = this.ctx.getService('docTable'); private readonly config = this.ctx.getService('config'); private readonly dataGrid = this.ctx.getService('dataGrid'); - private readonly kibanaServer = this.ctx.getService('kibanaServer'); private readonly fieldEditor = this.ctx.getService('fieldEditor'); private readonly queryBar = this.ctx.getService('queryBar'); private readonly savedObjectsFinder = this.ctx.getService('savedObjectsFinder'); @@ -42,15 +40,6 @@ export class DiscoverPageObject extends FtrService { return await this.testSubjects.getAttribute('unifiedHistogramChart', 'data-time-range'); } - public async getDocTable() { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - return this.docTable; - } else { - return this.dataGrid; - } - } - public async saveSearch( searchName: string, saveAsNew?: boolean, @@ -117,12 +106,7 @@ export class DiscoverPageObject extends FtrService { } public async getColumnHeaders() { - const isLegacy = await this.useLegacyTable(); - if (isLegacy) { - return await this.docTable.getHeaderFields('embeddedSavedSearchDocTable'); - } - const table = await this.getDocTable(); - return await table.getHeaderFields(); + return await this.dataGrid.getHeaderFields(); } public async openLoadSavedSearchPanel() { @@ -224,6 +208,12 @@ export class DiscoverPageObject extends FtrService { ); } + public async getBreakdownFieldValue() { + const breakdownButton = await this.testSubjects.find('unifiedHistogramBreakdownSelectorButton'); + + return breakdownButton.getVisibleText(); + } + public async chooseBreakdownField(field: string, value?: string) { await this.retry.try(async () => { await this.testSubjects.click('unifiedHistogramBreakdownSelectorButton'); @@ -355,28 +345,16 @@ export class DiscoverPageObject extends FtrService { } public async getDocHeader() { - const table = await this.getDocTable(); - const docHeader = await table.getHeaders(); + const docHeader = await this.dataGrid.getHeaders(); return docHeader.join(); } public async getDocTableRows() { await this.header.waitUntilLoadingHasFinished(); - const table = await this.getDocTable(); - return await table.getBodyRows(); - } - - public async useLegacyTable() { - return (await this.kibanaServer.uiSettings.get('doc_table:legacy')) === true; + return await this.dataGrid.getBodyRows(); } public async getDocTableIndex(index: number, visibleText = false) { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - const row = await this.find.byCssSelector(`tr.kbnDocTable__row:nth-child(${index})`); - return await row.getVisibleText(); - } - const row = await this.dataGrid.getRow({ rowIndex: index - 1 }); const result = await Promise.all( row.map(async (cell) => { @@ -392,21 +370,10 @@ export class DiscoverPageObject extends FtrService { return result.slice(await this.dataGrid.getControlColumnsCount()).join(' '); } - public async getDocTableIndexLegacy(index: number) { - const row = await this.find.byCssSelector(`tr.kbnDocTable__row:nth-child(${index})`); - return await row.getVisibleText(); - } - public async getDocTableField(index: number, cellIdx: number = -1) { - const isLegacyDefault = await this.useLegacyTable(); - const usedDefaultCellIdx = isLegacyDefault ? 0 : await this.dataGrid.getControlColumnsCount(); + const usedDefaultCellIdx = await this.dataGrid.getControlColumnsCount(); const usedCellIdx = cellIdx === -1 ? usedDefaultCellIdx : cellIdx; - if (isLegacyDefault) { - const fields = await this.find.allByCssSelector( - `tr.kbnDocTable__row:nth-child(${index}) [data-test-subj='docTableField']` - ); - return await fields[usedCellIdx].getVisibleText(); - } + await this.testSubjects.click('dataGridFullScreenButton'); const row = await this.dataGrid.getRow({ rowIndex: index - 1 }); const result = await Promise.all(row.map(async (cell) => (await cell.getVisibleText()).trim())); @@ -414,33 +381,6 @@ export class DiscoverPageObject extends FtrService { return result[usedCellIdx]; } - public async clickDocTableRowToggle(rowIndex: number = 0) { - const docTable = await this.getDocTable(); - await docTable.clickRowToggle({ rowIndex }); - } - - public async skipToEndOfDocTable() { - // add the focus to the button to make it appear - const skipButton = await this.testSubjects.find('discoverSkipTableButton'); - // force focus on it, to make it interactable - await skipButton.focus(); - // now click it! - return skipButton.click(); - } - - /** - * When scrolling down the legacy table there's a link to scroll up - * So this is done by this function - */ - public async backToTop() { - const skipButton = await this.testSubjects.find('discoverBackToTop'); - return skipButton.click(); - } - - public async getDocTableFooter() { - return await this.testSubjects.find('discoverDocTableFooter'); - } - public isShowingDocViewer() { return this.dataGrid.isShowingDocViewer(); } @@ -472,7 +412,7 @@ export class DiscoverPageObject extends FtrService { } public async getMarks() { - const table = await this.docTable.getTable(); + const table = await this.dataGrid.getTable(); const marks = await table.findAllByTagName('mark'); return await Promise.all(marks.map((mark) => mark.getVisibleText())); } @@ -567,10 +507,6 @@ export class DiscoverPageObject extends FtrService { } public async clickFieldSort(field: string, text = 'Sort New-Old') { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - return await this.testSubjects.click(`docTableHeaderFieldSort_${field}`); - } return await this.dataGrid.clickDocSortAsc(field, text); } @@ -602,13 +538,7 @@ export class DiscoverPageObject extends FtrService { } public async removeHeaderColumn(name: string) { - const isLegacyDefault = await this.useLegacyTable(); - if (isLegacyDefault) { - await this.testSubjects.moveMouseTo(`docTableHeader-${name}`); - await this.testSubjects.click(`docTableRemoveHeader-${name}`); - } else { - await this.dataGrid.clickRemoveColumn(name); - } + await this.dataGrid.clickRemoveColumn(name); } public async waitForChartLoadingComplete(renderCount: number) { diff --git a/test/functional/services/dashboard/expectations.ts b/test/functional/services/dashboard/expectations.ts index 414a44b24df9..ec43f1ec8012 100644 --- a/test/functional/services/dashboard/expectations.ts +++ b/test/functional/services/dashboard/expectations.ts @@ -81,14 +81,6 @@ export class DashboardExpectService extends FtrService { }); } - async docTableFieldCount(expectedCount: number) { - this.log.debug(`DashboardExpect.docTableFieldCount(${expectedCount})`); - await this.retry.try(async () => { - const docTableCells = await this.testSubjects.findAll('docTableField', this.findTimeout); - expect(docTableCells.length).to.be(expectedCount); - }); - } - async fieldSuggestions(expectedFields: string[]) { this.log.debug(`DashboardExpect.fieldSuggestions(${expectedFields})`); const fields = await this.filterBar.getFilterEditorFields(); diff --git a/test/functional/services/dashboard/panel_actions.ts b/test/functional/services/dashboard/panel_actions.ts index 75474fef4165..31890d4c4c47 100644 --- a/test/functional/services/dashboard/panel_actions.ts +++ b/test/functional/services/dashboard/panel_actions.ts @@ -12,7 +12,6 @@ import { FtrService } from '../../ftr_provider_context'; const REMOVE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-deletePanel'; const EDIT_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-editPanel'; -const INLINE_EDIT_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-ACTION_CONFIGURE_IN_LENS'; const EDIT_IN_LENS_EDITOR_DATA_TEST_SUBJ = 'navigateToLensEditorLink'; const CLONE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-clonePanel'; const TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-togglePanel'; @@ -128,7 +127,9 @@ export class DashboardPanelActionsService extends FtrService { async navigateToEditorFromFlyout(wrapper?: WebElementWrapper) { this.log.debug('navigateToEditorFromFlyout'); - await this.clickPanelAction(INLINE_EDIT_PANEL_DATA_TEST_SUBJ, wrapper); + // make sure the context menu is open before proceeding + await this.openContextMenu(); + await this.clickPanelAction(EDIT_PANEL_DATA_TEST_SUBJ); await this.header.waitUntilLoadingHasFinished(); await this.testSubjects.clickWhenNotDisabledWithoutRetry(EDIT_IN_LENS_EDITOR_DATA_TEST_SUBJ); const isConfirmModalVisible = await this.testSubjects.exists('confirmModalConfirmButton'); @@ -139,9 +140,9 @@ export class DashboardPanelActionsService extends FtrService { } } - async clickInlineEdit() { + async clickInlineEdit(wrapper?: WebElementWrapper) { this.log.debug('clickInlineEditAction'); - await this.clickPanelAction(INLINE_EDIT_PANEL_DATA_TEST_SUBJ); + await this.clickPanelAction(EDIT_PANEL_DATA_TEST_SUBJ, wrapper); await this.header.waitUntilLoadingHasFinished(); await this.common.waitForTopNavToBeVisible(); } @@ -307,12 +308,9 @@ export class DashboardPanelActionsService extends FtrService { await this.expectExistsPanelAction(REMOVE_PANEL_DATA_TEST_SUBJ, title); } - async expectExistsEditPanelAction(title = '', allowsInlineEditing?: boolean) { + async expectExistsEditPanelAction(title = '') { this.log.debug('expectExistsEditPanelAction'); - let testSubj = EDIT_PANEL_DATA_TEST_SUBJ; - if (allowsInlineEditing) { - testSubj = INLINE_EDIT_PANEL_DATA_TEST_SUBJ; - } + const testSubj = EDIT_PANEL_DATA_TEST_SUBJ; await this.expectExistsPanelAction(testSubj, title); } diff --git a/test/functional/services/data_grid.ts b/test/functional/services/data_grid.ts index 3b17a31d624b..4500bc5b9715 100644 --- a/test/functional/services/data_grid.ts +++ b/test/functional/services/data_grid.ts @@ -499,14 +499,6 @@ export class DataGridService extends FtrService { return await detailsRow.findAllByTestSubject('~docTableRowAction'); } - public async getAnchorDetailsRow(): Promise { - const table = await this.getTable(); - - return await table.findByCssSelector( - '[data-test-subj~="docTableAnchorRow"] + [data-test-subj~="docTableDetailsRow"]' - ); - } - public async openColMenuByField(field: string) { await this.retry.waitFor('header cell action being displayed', async () => { // to prevent flakiness @@ -671,24 +663,6 @@ export class DataGridService extends FtrService { await sampleSizeInput.type(String(newValue)); } - public async getDetailsRow(): Promise { - const detailRows = await this.getDetailsRows(); - return detailRows[0]; - } - - public async getTableDocViewRow( - detailsRow: WebElementWrapper, - fieldName: string - ): Promise { - return await detailsRow.findByTestSubject(`~tableDocViewRow-${fieldName}`); - } - - public async getRemoveInclusiveFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~removeInclusiveFilterButton`); - } - public async showFieldCellActionInFlyout(fieldName: string, actionName: string): Promise { const cellSelector = ['addFilterForValueButton', 'addFilterOutValueButton'].includes(actionName) ? `tableDocViewRow-${fieldName}-value` diff --git a/test/functional/services/doc_table.ts b/test/functional/services/doc_table.ts deleted file mode 100644 index 0ca243b7b412..000000000000 --- a/test/functional/services/doc_table.ts +++ /dev/null @@ -1,176 +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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public - * License v3.0 only", or the "Server Side Public License, v 1". - */ - -import { WebElementWrapper } from '@kbn/ftr-common-functional-ui-services'; -import { FtrService } from '../ftr_provider_context'; - -interface SelectOptions { - isAnchorRow?: boolean; - rowIndex?: number; -} - -export class DocTableService extends FtrService { - private readonly testSubjects = this.ctx.getService('testSubjects'); - private readonly retry = this.ctx.getService('retry'); - private readonly header = this.ctx.getPageObject('header'); - - public async getTable(selector?: string) { - return await this.testSubjects.find(selector ? selector : 'docTable'); - } - - public async getRowsText() { - const table = await this.getTable(); - const $ = await table.parseDomContent(); - return $.findTestSubjects('~docTableRow') - .toArray() - .map((row: any) => $(row).text().trim()); - } - - public async getBodyRows(): Promise { - const table = await this.getTable(); - return await table.findAllByTestSubject('~docTableRow'); - } - - public async getAnchorRow(): Promise { - const table = await this.getTable(); - return await table.findByTestSubject('~docTableAnchorRow'); - } - - public async getRow({ - isAnchorRow = false, - rowIndex = 0, - }: SelectOptions = {}): Promise { - return isAnchorRow ? await this.getAnchorRow() : (await this.getBodyRows())[rowIndex]; - } - - public async getDetailsRow(): Promise { - const table = await this.getTable(); - return await table.findByCssSelector('[data-test-subj~="docTableDetailsRow"]'); - } - - public async getAnchorDetailsRow(): Promise { - const table = await this.getTable(); - return await table.findByCssSelector( - '[data-test-subj~="docTableAnchorRow"] + [data-test-subj~="docTableDetailsRow"]' - ); - } - - public async clickRowToggle( - options: SelectOptions = { isAnchorRow: false, rowIndex: 0 } - ): Promise { - const row = await this.getRow(options); - const toggle = await row.findByTestSubject('~docTableExpandToggleColumn'); - await toggle.click(); - } - - public async getDetailsRows(): Promise { - const table = await this.getTable(); - return await table.findAllByCssSelector( - '[data-test-subj~="docTableRow"] + [data-test-subj~="docTableDetailsRow"]' - ); - } - - public async getRowActions({ isAnchorRow = false, rowIndex = 0 }: SelectOptions = {}): Promise< - WebElementWrapper[] - > { - const detailsRow = isAnchorRow - ? await this.getAnchorDetailsRow() - : (await this.getDetailsRows())[rowIndex]; - return await detailsRow.findAllByTestSubject('~docTableRowAction'); - } - - public async getFields(options: { isAnchorRow: boolean } = { isAnchorRow: false }) { - const table = await this.getTable(); - const $ = await table.parseDomContent(); - const rowLocator = options.isAnchorRow ? '~docTableAnchorRow' : '~docTableRow'; - const rows = $.findTestSubjects(rowLocator).toArray(); - return rows.map((row: any) => - $(row) - .find('[data-test-subj~="docTableField"]') - .toArray() - .map((field: any) => $(field).text()) - ); - } - - public async getHeaderFields(selector?: string): Promise { - const table = await this.getTable(selector); - const $ = await table.parseDomContent(); - return $.findTestSubjects('~docTableHeaderField') - .toArray() - .map((field: any) => $(field).text().trim()); - } - - public async getHeaders(selector?: string): Promise { - return this.getHeaderFields(selector); - } - - public async getTableDocViewRow( - detailsRow: WebElementWrapper, - fieldName: string - ): Promise { - return await detailsRow.findByTestSubject(`~tableDocViewRow-${fieldName}`); - } - - public async getAddInclusiveFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~addInclusiveFilterButton`); - } - - public async addInclusiveFilter(detailsRow: WebElementWrapper, fieldName: string): Promise { - const tableDocViewRow = await this.getTableDocViewRow(detailsRow, fieldName); - const addInclusiveFilterButton = await this.getAddInclusiveFilterButton(tableDocViewRow); - await addInclusiveFilterButton.click(); - await this.header.awaitGlobalLoadingIndicatorHidden(); - } - - public async getRemoveInclusiveFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~removeInclusiveFilterButton`); - } - - public async removeInclusiveFilter( - detailsRow: WebElementWrapper, - fieldName: string - ): Promise { - const tableDocViewRow = await this.getTableDocViewRow(detailsRow, fieldName); - const addInclusiveFilterButton = await this.getRemoveInclusiveFilterButton(tableDocViewRow); - await addInclusiveFilterButton.click(); - await this.header.awaitGlobalLoadingIndicatorHidden(); - } - - public async getAddExistsFilterButton( - tableDocViewRow: WebElementWrapper - ): Promise { - return await tableDocViewRow.findByTestSubject(`~addExistsFilterButton`); - } - - public async addExistsFilter(detailsRow: WebElementWrapper, fieldName: string): Promise { - const tableDocViewRow = await this.getTableDocViewRow(detailsRow, fieldName); - const addInclusiveFilterButton = await this.getAddExistsFilterButton(tableDocViewRow); - await addInclusiveFilterButton.click(); - await this.header.awaitGlobalLoadingIndicatorHidden(); - } - - public async toggleRowExpanded({ - isAnchorRow = false, - rowIndex = 0, - }: SelectOptions = {}): Promise { - await this.clickRowToggle({ isAnchorRow, rowIndex }); - await this.header.awaitGlobalLoadingIndicatorHidden(); - return await this.retry.try(async () => { - const row = isAnchorRow ? await this.getAnchorRow() : (await this.getBodyRows())[rowIndex]; - const detailsRow = await row.findByXpath( - './following-sibling::*[@data-test-subj="docTableDetailsRow"]' - ); - return detailsRow.findByTestSubject('~docViewer'); - }); - } -} diff --git a/test/functional/services/field_editor.ts b/test/functional/services/field_editor.ts index 07bcaf98959b..0739159bcf91 100644 --- a/test/functional/services/field_editor.ts +++ b/test/functional/services/field_editor.ts @@ -90,9 +90,11 @@ export class FieldEditorService extends FtrService { public async setColorFormat(value: string, color: string, backgroundColor?: string) { await this.testSubjects.click('colorEditorAddColor'); await this.testSubjects.setValue('~colorEditorKeyPattern', value); - await this.testSubjects.setValue('~colorEditorColorPicker', color); + await this.testSubjects.click('~colorEditorColorPicker'); + await this.testSubjects.setValue('~euiColorPickerInput_bottom', color); if (backgroundColor) { - await this.testSubjects.setValue('~colorEditorBackgroundPicker', backgroundColor); + await this.testSubjects.click('~colorEditorBackgroundPicker'); + await this.testSubjects.setValue('~euiColorPickerInput_bottom', backgroundColor); } } diff --git a/test/functional/services/index.ts b/test/functional/services/index.ts index 77df85ef3e56..ccdc8cfec395 100644 --- a/test/functional/services/index.ts +++ b/test/functional/services/index.ts @@ -30,7 +30,6 @@ import { DashboardDrilldownPanelActionsProvider, DashboardDrilldownsManageProvider, } from './dashboard'; -import { DocTableService } from './doc_table'; import { EmbeddingService } from './embedding'; import { FilterBarService } from './filter_bar'; import { FlyoutService } from './flyout'; @@ -62,7 +61,6 @@ export const services = { ...commonFunctionalUIServices, filterBar: FilterBarService, queryBar: QueryBarService, - docTable: DocTableService, png: PngService, screenshots: ScreenshotsService, snapshots: SnapshotsService, diff --git a/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts b/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts index 0a7a15f0c62e..2afd1e13d040 100644 --- a/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts +++ b/test/plugin_functional/plugins/core_plugin_deprecations/server/plugin.ts @@ -18,7 +18,11 @@ async function getDeprecations({ savedObjectsClient, }: GetDeprecationsContext): Promise { const deprecations: DeprecationsDetails[] = []; - const { total } = await savedObjectsClient.find({ type: 'test-deprecations-plugin', perPage: 1 }); + const { total } = await savedObjectsClient.find({ + type: 'test-deprecations-plugin', + perPage: 1, + namespaces: ['*'], + }); deprecations.push({ title: 'CorePluginDeprecationsPlugin plugin is deprecated', diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 83ef8629a6ef..8047994039e7 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -163,6 +163,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'monitoring.ui.enabled (boolean?)', 'monitoring.ui.min_interval_seconds (number?)', 'monitoring.ui.show_license_expiration (boolean?)', + 'monitoring.ui.logs.index (string?)', 'newsfeed.fetchInterval (duration?)', 'newsfeed.mainInterval (duration?)', 'newsfeed.service.pathTemplate (string?)', @@ -353,6 +354,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) { 'xpack.upgrade_assistant.featureSet.migrateSystemIndices (boolean?)', 'xpack.upgrade_assistant.featureSet.mlSnapshots (boolean?)', 'xpack.upgrade_assistant.featureSet.reindexCorrectiveActions (boolean?)', + 'xpack.upgrade_assistant.featureSet.migrateDataStreams (boolean?)', 'xpack.upgrade_assistant.ui.enabled (boolean?)', 'xpack.observability.unsafe.alertDetails.metrics.enabled (boolean?)', 'xpack.observability.unsafe.alertDetails.logs.enabled (boolean?)', diff --git a/tsconfig.base.json b/tsconfig.base.json index 23be79df3418..c690ecf1a7f9 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -96,6 +96,8 @@ "@kbn/app-link-test-plugin/*": ["test/plugin_functional/plugins/app_link_test/*"], "@kbn/application-usage-test-plugin": ["x-pack/test/usage_collection/plugins/application_usage_test"], "@kbn/application-usage-test-plugin/*": ["x-pack/test/usage_collection/plugins/application_usage_test/*"], + "@kbn/asset-inventory-plugin": ["x-pack/plugins/asset_inventory"], + "@kbn/asset-inventory-plugin/*": ["x-pack/plugins/asset_inventory/*"], "@kbn/audit-log-plugin": ["x-pack/test/security_api_integration/plugins/audit_log"], "@kbn/audit-log-plugin/*": ["x-pack/test/security_api_integration/plugins/audit_log/*"], "@kbn/avc-banner": ["packages/kbn-avc-banner"], @@ -756,6 +758,10 @@ "@kbn/default-nav-management/*": ["packages/default-nav/management/*"], "@kbn/default-nav-ml": ["packages/default-nav/ml"], "@kbn/default-nav-ml/*": ["packages/default-nav/ml/*"], + "@kbn/dependency-ownership": ["packages/kbn-dependency-ownership"], + "@kbn/dependency-ownership/*": ["packages/kbn-dependency-ownership/*"], + "@kbn/dependency-usage": ["packages/kbn-dependency-usage"], + "@kbn/dependency-usage/*": ["packages/kbn-dependency-usage/*"], "@kbn/dev-cli-errors": ["packages/kbn-dev-cli-errors"], "@kbn/dev-cli-errors/*": ["packages/kbn-dev-cli-errors/*"], "@kbn/dev-cli-runner": ["packages/kbn-dev-cli-runner"], @@ -1530,8 +1536,12 @@ "@kbn/saved-objects-tagging-oss-plugin/*": ["src/plugins/saved_objects_tagging_oss/*"], "@kbn/saved-objects-tagging-plugin": ["x-pack/plugins/saved_objects_tagging"], "@kbn/saved-objects-tagging-plugin/*": ["x-pack/plugins/saved_objects_tagging/*"], + "@kbn/saved-search-component": ["packages/kbn-saved-search-component"], + "@kbn/saved-search-component/*": ["packages/kbn-saved-search-component/*"], "@kbn/saved-search-plugin": ["src/plugins/saved_search"], "@kbn/saved-search-plugin/*": ["src/plugins/saved_search/*"], + "@kbn/scout": ["packages/kbn-scout"], + "@kbn/scout/*": ["packages/kbn-scout/*"], "@kbn/screenshot-mode-example-plugin": ["examples/screenshot_mode_example"], "@kbn/screenshot-mode-example-plugin/*": ["examples/screenshot_mode_example/*"], "@kbn/screenshot-mode-plugin": ["src/plugins/screenshot_mode"], @@ -1846,6 +1856,8 @@ "@kbn/stdio-dev-helpers/*": ["packages/kbn-stdio-dev-helpers/*"], "@kbn/storybook": ["packages/kbn-storybook"], "@kbn/storybook/*": ["packages/kbn-storybook/*"], + "@kbn/streams-app-plugin": ["x-pack/plugins/streams_app"], + "@kbn/streams-app-plugin/*": ["x-pack/plugins/streams_app/*"], "@kbn/streams-plugin": ["x-pack/plugins/streams"], "@kbn/streams-plugin/*": ["x-pack/plugins/streams/*"], "@kbn/synthetics-e2e": ["x-pack/plugins/observability_solution/synthetics/e2e"], diff --git a/versions.json b/versions.json index 0843e7d91262..67e0a6ac4932 100644 --- a/versions.json +++ b/versions.json @@ -24,7 +24,7 @@ "previousMajor": true }, { - "version": "8.15.5", + "version": "8.15.6", "branch": "8.15", "previousMajor": true }, diff --git a/x-pack/.gitignore b/x-pack/.gitignore index 0e0e9aba8446..97efbef318c9 100644 --- a/x-pack/.gitignore +++ b/x-pack/.gitignore @@ -12,3 +12,4 @@ /.env /.kibana-plugin-helpers.dev.* .cache +**/ui_tests/output diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 7c97dcf1b722..213c3f06f34a 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -112,7 +112,9 @@ "xpack.observabilityLogsOverview": [ "packages/observability/logs_overview/src/components" ], - "xpack.osquery": ["plugins/osquery"], + "xpack.osquery": [ + "plugins/osquery" + ], "xpack.painlessLab": "plugins/painless_lab", "xpack.profiling": [ "plugins/observability_solution/profiling" @@ -148,6 +150,9 @@ "xpack.securitySolutionEss": "plugins/security_solution_ess", "xpack.securitySolutionServerless": "plugins/security_solution_serverless", "xpack.sessionView": "plugins/session_view", + "xpack.streams": [ + "plugins/streams_app" + ], "xpack.slo": "plugins/observability_solution/slo", "xpack.snapshotRestore": "plugins/snapshot_restore", "xpack.spaces": "plugins/spaces", diff --git a/x-pack/.telemetryrc.json b/x-pack/.telemetryrc.json index b0a8b45c02de..51abf578ae5f 100644 --- a/x-pack/.telemetryrc.json +++ b/x-pack/.telemetryrc.json @@ -10,5 +10,25 @@ "output": "plugins/telemetry_collection_xpack/schema/xpack_monitoring.json", "root": "plugins/monitoring/server/telemetry_collection/", "exclude": [] + }, + { + "output": "plugins/telemetry_collection_xpack/schema/xpack_platform.json", + "root": "platform/", + "exclude": [] + }, + { + "output": "plugins/telemetry_collection_xpack/schema/xpack_observability.json", + "root": "solutions/observability", + "exclude": [] + }, + { + "output": "plugins/telemetry_collection_xpack/schema/xpack_search.json", + "root": "solutions/search", + "exclude": [] + }, + { + "output": "plugins/telemetry_collection_xpack/schema/xpack_security.json", + "root": "solutions/security", + "exclude": [] } ] diff --git a/x-pack/examples/alerting_example/server/plugin.ts b/x-pack/examples/alerting_example/server/plugin.ts index 43b3bc82c441..bf79d564222d 100644 --- a/x-pack/examples/alerting_example/server/plugin.ts +++ b/x-pack/examples/alerting_example/server/plugin.ts @@ -9,9 +9,10 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { i18n } from '@kbn/i18n'; // import directly to support examples functional tests (@kbn-test/src/functional_tests/lib/babel_register_for_test_plugins.js) import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; -import { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { ruleType as alwaysFiringRule } from './rule_types/always_firing'; import { ruleType as peopleInSpaceRule } from './rule_types/astros'; @@ -22,7 +23,7 @@ import { ALERTING_EXAMPLE_APP_ID } from '../common/constants'; // this plugin's dependencies export interface AlertingExampleDeps { - alerting: AlertingSetup; + alerting: AlertingServerSetup; features: FeaturesPluginSetup; } @@ -43,15 +44,54 @@ export class AlertingExamplePlugin implements Plugin {isSaveModalVisible && ( {}} onClose={() => setIsSaveModalVisible(false)} /> diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx index 055050de3f4c..68d7140badb3 100644 --- a/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/app.tsx @@ -24,7 +24,6 @@ import type { CoreStart } from '@kbn/core/public'; import { LensConfigBuilder } from '@kbn/lens-embeddable-utils/config_builder/config_builder'; import type { DataView } from '@kbn/data-views-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import type { StartDependencies } from './plugin'; import { LensChart } from './embeddable'; import { MultiPaneFlyout } from './flyout'; @@ -46,137 +45,128 @@ export const App = (props: { ); return ( - - - - - - - - - - - - - - + + + + + + + + + + + + + - -

        #3: Embeddable inside a flyout

        -
        - - -

        - In case you do not want to use a push flyout, you can check this example.{' '} -
        - In this example, we have a Lens embeddable inside a flyout and we want to - render the inline editing Component in a second slot of the same flyout. -

        -
        - - - - { - setIsFlyoutVisible(true); - setPanelActive(3); +

        #3: Embeddable inside a flyout

        +
        + + +

        + In case you do not want to use a push flyout, you can check this example.
        + In this example, we have a Lens embeddable inside a flyout and we want to render + the inline editing Component in a second slot of the same flyout. +

        +
        + + + + { + setIsFlyoutVisible(true); + setPanelActive(3); + }} + > + Show flyout + + {isFlyoutVisible ? ( + { + setIsinlineEditingVisible(false); + if (container) { + ReactDOM.unmountComponentAtNode(container); + } + }} + onCancelCb={() => { + setIsinlineEditingVisible(false); + if (container) { + ReactDOM.unmountComponentAtNode(container); + } + }} + isESQL + isActive + /> + ), + }} + inlineEditingContent={{ + visible: isInlineEditingVisible, + }} + setContainer={setContainer} + onClose={() => { + setIsFlyoutVisible(false); + setIsinlineEditingVisible(false); + setPanelActive(null); + if (container) { + ReactDOM.unmountComponentAtNode(container); + } }} - > - Show flyout - - {isFlyoutVisible ? ( - { - setIsinlineEditingVisible(false); - if (container) { - ReactDOM.unmountComponentAtNode(container); - } - }} - onCancelCb={() => { - setIsinlineEditingVisible(false); - if (container) { - ReactDOM.unmountComponentAtNode(container); - } - }} - isESQL - isActive - /> - ), - }} - inlineEditingContent={{ - visible: isInlineEditingVisible, - }} - setContainer={setContainer} - onClose={() => { - setIsFlyoutVisible(false); - setIsinlineEditingVisible(false); - setPanelActive(null); - if (container) { - ReactDOM.unmountComponentAtNode(container); - } - }} - /> - ) : null} - - -
        -
        -
        -
        -
        -
        -
        + /> + ) : null} + +
        + + +
        + + + ); }; diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx index 717a8b2d20f8..a63264485bf5 100644 --- a/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/embeddable.tsx @@ -64,13 +64,13 @@ export const LensChart = (props: { ( isLoading: boolean, adapters: InlineEditLensEmbeddableContext['lensEvent']['adapters'] | undefined, - lensEmbeddableOutput$?: InlineEditLensEmbeddableContext['lensEvent']['embeddableOutput$'] + dataLoading$?: InlineEditLensEmbeddableContext['lensEvent']['dataLoading$'] ) => { const adapterTables = adapters?.tables?.tables; if (adapterTables && !isLoading) { setLensLoadEvent({ adapters, - embeddableOutput$: lensEmbeddableOutput$, + dataLoading$, }); } }, diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx b/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx index 411538e2df2c..86bf0757220d 100644 --- a/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx +++ b/x-pack/examples/lens_embeddable_inline_editing_example/public/mount.tsx @@ -10,6 +10,7 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { EuiCallOut } from '@elastic/eui'; import type { CoreSetup, AppMountParameters } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { StartDependencies } from './plugin'; export const mount = @@ -21,10 +22,15 @@ export const mount = const dataView = await plugins.dataViews.getDefaultDataView(); const stateHelpers = await plugins.lens.stateHelperApi(); - const i18nCore = core.i18n; - const reactElement = ( - + {dataView ? ( You need at least one dataview for this demo to work

        )} -
        + ); render(reactElement, element); diff --git a/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json b/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json index e4727650106b..104bfbeeacd7 100644 --- a/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json +++ b/x-pack/examples/lens_embeddable_inline_editing_example/tsconfig.json @@ -19,8 +19,8 @@ "@kbn/developer-examples-plugin", "@kbn/data-views-plugin", "@kbn/ui-actions-plugin", - "@kbn/kibana-react-plugin", "@kbn/lens-embeddable-utils", "@kbn/ui-theme", + "@kbn/react-kibana-context-render", ] } diff --git a/x-pack/examples/testing_embedded_lens/public/app.tsx b/x-pack/examples/testing_embedded_lens/public/app.tsx index 9aa6a40fe20c..699db0d0dc64 100644 --- a/x-pack/examples/testing_embedded_lens/public/app.tsx +++ b/x-pack/examples/testing_embedded_lens/public/app.tsx @@ -29,7 +29,6 @@ import type { TypedLensByValueInput, PersistedIndexPatternLayer, XYState, - LensEmbeddableInput, DateHistogramIndexPatternColumn, DatatableVisualizationState, HeatmapVisualizationState, @@ -42,7 +41,6 @@ import type { MetricVisualizationState, } from '@kbn/lens-plugin/public'; import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { CodeEditor, HJsonLang } from '@kbn/code-editor'; import type { StartDependencies } from './plugin'; import { @@ -496,269 +494,256 @@ export const App = (props: { const [overrides, setOverrides] = useState(); return ( - - - - - - - - - - -

        - This app embeds a Lens visualization by specifying the configuration. Data - fetching and rendering is completely managed by Lens itself. -

        -

        - The editor on the right hand side make it possible to paste a Lens - attributes configuration, and have it rendered. Presets are available to - have a starting configuration, and new presets can be saved as well (not - persisted). -

        -

        - The Open with Lens button will take the current configuration and navigate - to a prefilled editor. -

        - - - - - - - - - - - + + + + + + + + + +

        + This app embeds a Lens visualization by specifying the configuration. Data + fetching and rendering is completely managed by Lens itself. +

        +

        + The editor on the right hand side make it possible to paste a Lens attributes + configuration, and have it rendered. Presets are available to have a starting + configuration, and new presets can be saved as well (not persisted). +

        +

        + The Open with Lens button will take the current configuration and navigate to + a prefilled editor. +

        + + + + + + + + + + + + + { + setIsSaveModalVisible(true); + }} + > + Save Visualization + + + {props.defaultDataView?.isTimeBased() ? ( { - setIsSaveModalVisible(true); - }} - > - Save Visualization - - - {props.defaultDataView?.isTimeBased() ? ( - - { - setTime( - time.to === 'now' - ? { - from: '2015-09-18T06:31:44.000Z', - to: '2015-09-23T18:31:44.000Z', - } - : { - from: 'now-5d', - to: 'now', - } - ); - }} - > - {time.to === 'now' ? 'Change time range' : 'Reset time range'} - - - ) : null} - - { - props.plugins.lens.navigateToPrefilledEditor( - { - id: '', - timeRange: time, - attributes: currentAttributes, - }, - { - openInNewTab: true, - } + setTime( + time.to === 'now' + ? { + from: '2015-09-18T06:31:44.000Z', + to: '2015-09-23T18:31:44.000Z', + } + : { + from: 'now-5d', + to: 'now', + } ); }} > - Open in Lens (new tab) + {time.to === 'now' ? 'Change time range' : 'Reset time range'} - -

        State: {isLoading ? 'Loading...' : 'Rendered'}

        -
        -
        - - - { - setIsLoading(val); - }} - onBrushEnd={({ range }) => { - setTime({ - from: new Date(range[0]).toISOString(), - to: new Date(range[1]).toISOString(), - }); - }} - onFilter={(_data) => { - // call back event for on filter event - }} - onTableRowClick={(_data) => { - // call back event for on table row click event - }} - disableTriggers={!enableTriggers} - viewMode={ViewMode.VIEW} - withDefaultActions={enableDefaultAction} - extraActions={ - enableExtraAction - ? [ - { - id: 'testAction', - type: 'link', - getIconType: () => 'save', - async isCompatible( - context: ActionExecutionContext - ): Promise { - return true; - }, - execute: async (context: ActionExecutionContext) => { - alert('I am an extra action'); - return; - }, - getDisplayName: () => 'Extra action', - }, - ] - : undefined - } - /> - - - - {isSaveModalVisible && ( - {}} - onClose={() => setIsSaveModalVisible(false)} - /> - )} - - - - - - -

        Paste or edit here your Lens document

        -
        -
        -
        - - - ({ value: i, text: id }))} - value={undefined} - onChange={(e) => switchChartPreset(+e.target.value)} - aria-label="Load from a preset" - prepend={'Load preset'} - /> - - - { - const attributes = checkAndParseSO(currentSO.current); - if (attributes) { - const label = `custom-chart-${chartCounter}`; - addChartConfiguration([ - ...loadedCharts, + ) : null} + + { + props.plugins.lens.navigateToPrefilledEditor( + { + id: '', + timeRange: time, + attributes: currentAttributes, + }, + { + openInNewTab: true, + } + ); + }} + > + Open in Lens (new tab) + + + +

        State: {isLoading ? 'Loading...' : 'Rendered'}

        +
        +
        + + + { + setIsLoading(val); + }} + onBrushEnd={({ range }) => { + setTime({ + from: new Date(range[0]).toISOString(), + to: new Date(range[1]).toISOString(), + }); + }} + onFilter={(_data) => { + // call back event for on filter event + }} + onTableRowClick={(_data) => { + // call back event for on table row click event + }} + disableTriggers={!enableTriggers} + viewMode={ViewMode.VIEW} + withDefaultActions={enableDefaultAction} + extraActions={ + enableExtraAction + ? [ { - id: label, - attributes, + id: 'testAction', + type: 'link', + getIconType: () => 'save', + async isCompatible( + context: ActionExecutionContext + ): Promise { + return true; + }, + execute: async (context: ActionExecutionContext) => { + alert('I am an extra action'); + return; + }, + getDisplayName: () => 'Extra action', }, - ]); - chartCounter++; - alert(`The preset has been saved as "${label}"`); - } - }} - > - Save as preset - - - {hasParsingErrorDebounced && currentSO.current !== currentValid && ( - -

        Check the spec

        -
        - )} - - - - { - const isValid = Boolean(checkAndParseSO(newSO)); - setErrorFlag(!isValid); - currentSO.current = newSO; - if (isValid) { - // reset the debounced error - setErrorDebounced(isValid); - saveValidSO(newSO); - } - }} - /> - - - - - - - - - - - + ] + : undefined + } + /> + + + + {isSaveModalVisible && ( + {}} + onClose={() => setIsSaveModalVisible(false)} + /> + )} + + + + + + +

        Paste or edit here your Lens document

        +
        +
        +
        + + + ({ value: i, text: id }))} + value={undefined} + onChange={(e) => switchChartPreset(+e.target.value)} + aria-label="Load from a preset" + prepend={'Load preset'} + /> + + + { + const attributes = checkAndParseSO(currentSO.current); + if (attributes) { + const label = `custom-chart-${chartCounter}`; + addChartConfiguration([ + ...loadedCharts, + { + id: label, + attributes, + }, + ]); + chartCounter++; + alert(`The preset has been saved as "${label}"`); + } + }} + > + Save as preset + + + {hasParsingErrorDebounced && currentSO.current !== currentValid && ( + +

        Check the spec

        +
        + )} +
        + + + { + const isValid = Boolean(checkAndParseSO(newSO)); + setErrorFlag(!isValid); + currentSO.current = newSO; + if (isValid) { + // reset the debounced error + setErrorDebounced(isValid); + saveValidSO(newSO); + } + }} + /> + + +
        +
        + + + + + + ); }; diff --git a/x-pack/examples/testing_embedded_lens/public/mount.tsx b/x-pack/examples/testing_embedded_lens/public/mount.tsx index d0f58eb6050b..04099e125b96 100644 --- a/x-pack/examples/testing_embedded_lens/public/mount.tsx +++ b/x-pack/examples/testing_embedded_lens/public/mount.tsx @@ -11,6 +11,7 @@ import { EuiCallOut } from '@elastic/eui'; import type { CoreSetup, AppMountParameters } from '@kbn/core/public'; import type { TypedLensByValueInput } from '@kbn/lens-plugin/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import type { StartDependencies } from './plugin'; export const mount = @@ -24,10 +25,15 @@ export const mount = const dataView = await plugins.data.indexPatterns.getDefault(); const stateHelpers = await plugins.lens.stateHelperApi(); - const i18nCore = core.i18n; - const reactElement = ( - + {dataView ? ( This demo only works if your default index pattern is set and time based

        )} -
        + ); render(reactElement, element); diff --git a/x-pack/examples/testing_embedded_lens/tsconfig.json b/x-pack/examples/testing_embedded_lens/tsconfig.json index 90cf691a3529..efa0ebd803d9 100644 --- a/x-pack/examples/testing_embedded_lens/tsconfig.json +++ b/x-pack/examples/testing_embedded_lens/tsconfig.json @@ -21,8 +21,8 @@ "@kbn/developer-examples-plugin", "@kbn/data-views-plugin", "@kbn/ui-actions-plugin", - "@kbn/kibana-react-plugin", "@kbn/core-ui-settings-browser", "@kbn/code-editor", + "@kbn/react-kibana-context-render", ] } diff --git a/x-pack/examples/triggers_actions_ui_example/public/components/alerts_table_sandbox.tsx b/x-pack/examples/triggers_actions_ui_example/public/components/alerts_table_sandbox.tsx index 738f4b6fb480..5b46a3cd3340 100644 --- a/x-pack/examples/triggers_actions_ui_example/public/components/alerts_table_sandbox.tsx +++ b/x-pack/examples/triggers_actions_ui_example/public/components/alerts_table_sandbox.tsx @@ -7,7 +7,6 @@ import React from 'react'; import { TriggersAndActionsUIPublicPluginStart } from '@kbn/triggers-actions-ui-plugin/public'; import { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; -import { AlertConsumers } from '@kbn/rule-data-utils'; interface SandboxProps { triggersActionsUi: TriggersAndActionsUIPublicPluginStart; @@ -19,12 +18,7 @@ export const AlertsTableSandbox = ({ triggersActionsUi }: SandboxProps) => { id: 'observabilityCases', configurationId: 'observabilityCases', alertsTableConfigurationRegistry, - featureIds: [ - AlertConsumers.INFRASTRUCTURE, - AlertConsumers.APM, - AlertConsumers.OBSERVABILITY, - AlertConsumers.LOGS, - ], + ruleTypeIds: ['.es-query'], query: { bool: { filter: [], diff --git a/x-pack/examples/triggers_actions_ui_example/server/plugin.ts b/x-pack/examples/triggers_actions_ui_example/server/plugin.ts index 6d55bbb2cb55..6bf6c1fd1442 100644 --- a/x-pack/examples/triggers_actions_ui_example/server/plugin.ts +++ b/x-pack/examples/triggers_actions_ui_example/server/plugin.ts @@ -8,7 +8,7 @@ import { Plugin, CoreSetup } from '@kbn/core/server'; import { PluginSetupContract as ActionsSetup } from '@kbn/actions-plugin/server'; -import { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { getConnectorType as getSystemLogExampleConnectorType, @@ -17,7 +17,7 @@ import { // this plugin's dependencies export interface TriggersActionsUiExampleDeps { - alerting: AlertingSetup; + alerting: AlertingServerSetup; actions: ActionsSetup; } export class TriggersActionsUiExamplePlugin diff --git a/x-pack/examples/triggers_actions_ui_example/tsconfig.json b/x-pack/examples/triggers_actions_ui_example/tsconfig.json index 601f23edd264..458a4a99d589 100644 --- a/x-pack/examples/triggers_actions_ui_example/tsconfig.json +++ b/x-pack/examples/triggers_actions_ui_example/tsconfig.json @@ -19,7 +19,6 @@ "@kbn/alerting-plugin", "@kbn/triggers-actions-ui-plugin", "@kbn/developer-examples-plugin", - "@kbn/rule-data-utils", "@kbn/data-plugin", "@kbn/i18n-react", "@kbn/shared-ux-router", diff --git a/x-pack/packages/ai-infra/product-doc-common/src/indices.ts b/x-pack/packages/ai-infra/product-doc-common/src/indices.ts index b48cacf79fd2..90e416ff48c4 100644 --- a/x-pack/packages/ai-infra/product-doc-common/src/indices.ts +++ b/x-pack/packages/ai-infra/product-doc-common/src/indices.ts @@ -7,9 +7,9 @@ import type { ProductName } from './product'; -export const productDocIndexPrefix = '.kibana-ai-product-doc'; -export const productDocIndexPattern = `${productDocIndexPrefix}-*`; +export const productDocIndexPrefix = '.kibana_ai_product_doc'; +export const productDocIndexPattern = `${productDocIndexPrefix}_*`; export const getProductDocIndexName = (productName: ProductName): string => { - return `${productDocIndexPrefix}-${productName.toLowerCase()}`; + return `${productDocIndexPrefix}_${productName.toLowerCase()}`; }; diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx index 12cb747d148c..00879b38932a 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_body.tsx @@ -7,6 +7,7 @@ import { EuiCallOut, + euiCanAnimate, EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, @@ -14,6 +15,7 @@ import { euiScrollBarStyles, EuiSpacer, useEuiTheme, + UseEuiTheme, } from '@elastic/eui'; import { css, keyframes } from '@emotion/css'; import { i18n } from '@kbn/i18n'; @@ -28,7 +30,6 @@ import { type Feedback, } from '@kbn/observability-ai-assistant-plugin/public'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { euiThemeVars } from '@kbn/ui-theme'; import { findLastIndex } from 'lodash'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import type { UseKnowledgeBaseResult } from '../hooks/use_knowledge_base'; @@ -56,14 +57,16 @@ const timelineClassName = (scrollBarStyles: string) => css` ${scrollBarStyles} `; -const promptEditorClassname = css` +const promptEditorClassname = (euiTheme: UseEuiTheme['euiTheme']) => css` overflow: hidden; - transition: height ${euiThemeVars.euiAnimSpeedFast} ${euiThemeVars.euiAnimSlightResistance}; + ${euiCanAnimate} { + transition: height ${euiTheme.animation.fast} ${euiTheme.animation.resistance}; + } `; -const incorrectLicenseContainer = css` +const incorrectLicenseContainer = (euiTheme: UseEuiTheme['euiTheme']) => css` height: 100%; - padding: ${euiThemeVars.euiPanelPaddingModifiers.paddingMedium}; + padding: ${euiTheme.size.base}; `; const chatBodyContainerClassNameWithError = css` @@ -86,11 +89,13 @@ const fadeInAnimation = keyframes` } `; -const animClassName = css` +const animClassName = (euiTheme: UseEuiTheme['euiTheme']) => css` height: 100%; opacity: 0; - animation: ${fadeInAnimation} ${euiThemeVars.euiAnimSpeedNormal} - ${euiThemeVars.euiAnimSlightBounce} ${euiThemeVars.euiAnimSpeedNormal} forwards; + ${euiCanAnimate} { + animation: ${fadeInAnimation} ${euiTheme.animation.normal} ${euiTheme.animation.bounce} + ${euiTheme.animation.normal} forwards; + } `; const containerClassName = css` @@ -127,8 +132,9 @@ export function ChatBody({ }) { const license = useLicense(); const hasCorrectLicense = license?.hasAtLeast('enterprise'); - const euiTheme = useEuiTheme(); - const scrollBarStyles = euiScrollBarStyles(euiTheme); + const theme = useEuiTheme(); + const scrollBarStyles = euiScrollBarStyles(theme); + const { euiTheme } = theme; const chatService = useAIAssistantChatService(); @@ -310,7 +316,7 @@ export function ChatBody({ if (!hasCorrectLicense && !initialConversationId) { footer = ( <> - + @@ -347,7 +353,7 @@ export function ChatBody({ hasBorder={false} hasShadow={false} paddingSize="m" - className={animClassName} + className={animClassName(euiTheme)} > {connectors.connectors?.length === 0 || messages.length === 1 ? ( @@ -503,7 +509,9 @@ export function ChatBody({ saveTitle(newTitle); }} onToggleFlyoutPositionMode={onToggleFlyoutPositionMode} - navigateToConversation={navigateToConversation} + navigateToConversation={ + initialMessages?.length && !initialConversationId ? undefined : navigateToConversation + } /> diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.tsx index e55daf640082..c4b4fcba0329 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_header.tsx @@ -104,7 +104,9 @@ export function ChatHeader({ size={breakpoint === 'xs' ? 'xs' : 's'} value={newTitle} className={css` - color: ${!!title ? theme.euiTheme.colors.text : theme.euiTheme.colors.subduedText}; + color: ${!!title + ? theme.euiTheme.colors.textParagraph + : theme.euiTheme.colors.textSubdued}; `} inputAriaLabel={i18n.translate('xpack.aiAssistant.chatHeader.editConversationInput', { defaultMessage: 'Edit conversation', diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/chat_item_title.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/chat_item_title.tsx index d6a26b0287e4..e38db0273086 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/chat_item_title.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/chat_item_title.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import { euiThemeVars } from '@kbn/ui-theme'; import React, { ReactNode } from 'react'; import { css } from '@emotion/react'; +import { useEuiTheme } from '@elastic/eui'; interface ChatItemTitleProps { actionsTrigger?: ReactNode; @@ -15,11 +15,14 @@ interface ChatItemTitleProps { } export function ChatItemTitle({ actionsTrigger, title }: ChatItemTitleProps) { + const { euiTheme } = useEuiTheme(); + const containerCSS = css` position: absolute; top: 2; - right: ${euiThemeVars.euiSizeS}; + right: ${euiTheme.size.s}; `; + return ( <> {title} diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/incorrect_license_panel.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/incorrect_license_panel.tsx index c7d9c649f49c..136f8d5918fb 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/incorrect_license_panel.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/incorrect_license_panel.tsx @@ -15,21 +15,22 @@ import { EuiPanel, EuiText, EuiTitle, + useEuiTheme, } from '@elastic/eui'; import { css } from '@emotion/css'; import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-theme'; import { elasticAiAssistantImage } from '@kbn/observability-ai-assistant-plugin/public'; import { UPGRADE_LICENSE_TITLE } from '../i18n'; import { useLicenseManagementLocator } from '../hooks/use_license_management_locator'; -const incorrectLicenseContainer = css` - height: 100%; - padding: ${euiThemeVars.euiPanelPaddingModifiers.paddingMedium}; -`; - export function IncorrectLicensePanel() { const handleNavigateToLicenseManagement = useLicenseManagementLocator(); + const { euiTheme } = useEuiTheme(); + + const incorrectLicenseContainer = css` + height: 100%; + padding: ${euiTheme.size.base}; + `; return ( diff --git a/x-pack/packages/kbn-ai-assistant/src/chat/welcome_message_connectors.tsx b/x-pack/packages/kbn-ai-assistant/src/chat/welcome_message_connectors.tsx index af358c49f2c5..376ea8ad58ae 100644 --- a/x-pack/packages/kbn-ai-assistant/src/chat/welcome_message_connectors.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/chat/welcome_message_connectors.tsx @@ -15,9 +15,10 @@ import { EuiSpacer, EuiText, EuiIconTip, + useEuiTheme, + euiCanAnimate, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { euiThemeVars } from '@kbn/ui-theme'; import { isHttpFetchError } from '@kbn/core-http-browser'; import type { UseGenAIConnectorsResult } from '../hooks/use_genai_connectors'; @@ -30,10 +31,6 @@ const fadeInAnimation = keyframes` } `; -const fadeInClassName = css` - animation: ${fadeInAnimation} ${euiThemeVars.euiAnimSpeedNormal} ease-in-out; -`; - export function WelcomeMessageConnectors({ connectors, onSetupConnectorClick, @@ -41,6 +38,14 @@ export function WelcomeMessageConnectors({ connectors: UseGenAIConnectorsResult; onSetupConnectorClick?: () => void; }) { + const { euiTheme } = useEuiTheme(); + + const fadeInClassName = css` + ${euiCanAnimate} { + animation: ${fadeInAnimation} ${euiTheme.animation.normal} ease-in-out; + } + `; + if (connectors.error) { const isForbiddenError = isHttpFetchError(connectors.error) && diff --git a/x-pack/packages/kbn-ai-assistant/src/conversation/conversation_view.tsx b/x-pack/packages/kbn-ai-assistant/src/conversation/conversation_view.tsx index fb74ff7647a2..4e705b183aeb 100644 --- a/x-pack/packages/kbn-ai-assistant/src/conversation/conversation_view.tsx +++ b/x-pack/packages/kbn-ai-assistant/src/conversation/conversation_view.tsx @@ -6,7 +6,6 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner, EuiSpacer, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/css'; -import { euiThemeVars } from '@kbn/ui-theme'; import React, { useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import type { AssistantScope } from '@kbn/ai-assistant-common'; @@ -105,7 +104,7 @@ export const ConversationView: React.FC = ({ const conversationListContainerName = css` min-width: 250px; width: 250px; - border-right: solid 1px ${euiThemeVars.euiColorLightShade}; + border-right: solid 1px ${euiTheme.border.color}; `; const sidebarContainerClass = css` @@ -117,8 +116,8 @@ export const ConversationView: React.FC = ({ height: calc(100% - 56px); background-color: ${euiTheme.colors.lightestShade}; width: ${isSecondSlotVisible ? SECOND_SLOT_CONTAINER_WIDTH : 0}px; - border-top: solid 1px ${euiThemeVars.euiColorLightShade}; - border-left: solid 1px ${euiThemeVars.euiColorLightShade}; + border-top: solid 1px ${euiTheme.border.color}; + border-left: solid 1px ${euiTheme.border.color}; .euiFlyoutHeader { padding: ${euiTheme.size.m}; diff --git a/x-pack/packages/kbn-ai-assistant/tsconfig.json b/x-pack/packages/kbn-ai-assistant/tsconfig.json index 286bf8d5d101..5ba1b161bccb 100644 --- a/x-pack/packages/kbn-ai-assistant/tsconfig.json +++ b/x-pack/packages/kbn-ai-assistant/tsconfig.json @@ -22,7 +22,6 @@ "@kbn/triggers-actions-ui-plugin", "@kbn/actions-plugin", "@kbn/i18n-react", - "@kbn/ui-theme", "@kbn/core", "@kbn/observability-ai-assistant-plugin", "@kbn/security-plugin", diff --git a/x-pack/packages/kbn-cloud-security-posture/common/constants.ts b/x-pack/packages/kbn-cloud-security-posture/common/constants.ts index a24d676dc6f8..9112dba4b9a4 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/constants.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/constants.ts @@ -47,3 +47,8 @@ export const VULNERABILITIES_SEVERITY: Record = { CRITICAL: 'CRITICAL', UNKNOWN: 'UNKNOWN', }; + +export const MISCONFIGURATION_STATUS: Record = { + PASSED: 'passed', + FAILED: 'failed', +}; diff --git a/x-pack/packages/kbn-cloud-security-posture/common/index.ts b/x-pack/packages/kbn-cloud-security-posture/common/index.ts index d5ee781c39b2..4065f7ca331a 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/index.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/index.ts @@ -28,7 +28,9 @@ export * from './constants'; export { extractErrorMessage, buildMutedRulesFilter, - buildEntityFlyoutPreviewQuery, + buildGenericEntityFlyoutPreviewQuery, + buildMisconfigurationEntityFlyoutPreviewQuery, + buildVulnerabilityEntityFlyoutPreviewQuery, } from './utils/helpers'; export { getAbbreviatedNumber } from './utils/get_abbreviated_number'; export { UiMetricService } from './utils/ui_metrics'; diff --git a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts index 04cb76f4441c..6b85d2ead28f 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.test.ts @@ -9,8 +9,10 @@ import { extractErrorMessage, defaultErrorMessage, buildMutedRulesFilter, - buildEntityFlyoutPreviewQuery, buildEntityAlertsQuery, + buildGenericEntityFlyoutPreviewQuery, + buildMisconfigurationEntityFlyoutPreviewQuery, + buildVulnerabilityEntityFlyoutPreviewQuery, } from './helpers'; const fallbackMessage = 'thisIsAFallBackMessage'; @@ -145,7 +147,7 @@ describe('test helper methods', () => { }); }); - describe('buildEntityFlyoutPreviewQueryTest', () => { + describe('buildGenericEntityFlyoutPreviewQuery', () => { it('should return the correct query when given field and query', () => { const field = 'host.name'; const query = 'exampleHost'; @@ -162,10 +164,10 @@ describe('test helper methods', () => { }, }; - expect(buildEntityFlyoutPreviewQuery(field, query)).toEqual(expectedQuery); + expect(buildGenericEntityFlyoutPreviewQuery(field, query)).toEqual(expectedQuery); }); - it('should return the correct query when given field and empty query', () => { + it('should return the correct query when given field and empty query and empty status', () => { const field = 'host.name'; const expectedQuery = { bool: { @@ -180,12 +182,143 @@ describe('test helper methods', () => { }, }; - expect(buildEntityFlyoutPreviewQuery(field)).toEqual(expectedQuery); + expect(buildGenericEntityFlyoutPreviewQuery(field)).toEqual(expectedQuery); + }); + + it('should return the correct query when given field and queryValue and status but empty queryField', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const status = 'pass'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildGenericEntityFlyoutPreviewQuery(field, query, status)).toEqual(expectedQuery); + }); + + it('should return the correct query when given field and queryValue and queryField but empty status', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const emptyStatus = undefined; + const queryField = 'some.field'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildGenericEntityFlyoutPreviewQuery(field, query, emptyStatus, queryField)).toEqual( + expectedQuery + ); + }); + + it('should return the correct query when given all the parameters', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const emptyStatus = 'some.status'; + const queryField = 'some.field'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ term: { 'some.field': 'some.status' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildGenericEntityFlyoutPreviewQuery(field, query, emptyStatus, queryField)).toEqual( + expectedQuery + ); + }); + }); + + describe('buildMisconfigurationEntityFlyoutPreviewQuery', () => { + it('should return the correct query when given field, queryValue, status and queryType Misconfiguration', () => { + const field = 'host.name'; + const queryValue = 'exampleHost'; + const status = 'pass'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ term: { 'result.evaluation': 'pass' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildMisconfigurationEntityFlyoutPreviewQuery(field, queryValue, status)).toEqual( + expectedQuery + ); + }); + }); + describe('buildVulnerabilityEntityFlyoutPreviewQuery', () => { + it('should return the correct query when given field, queryValue, status and queryType Vulnerability', () => { + const field = 'host.name'; + const queryValue = 'exampleHost'; + const status = 'low'; + const expectedQuery = { + bool: { + filter: [ + { + bool: { + should: [{ term: { 'host.name': 'exampleHost' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ term: { 'vulnerability.severity': 'low' } }], + minimum_should_match: 1, + }, + }, + ], + }, + }; + + expect(buildVulnerabilityEntityFlyoutPreviewQuery(field, queryValue, status)).toEqual( + expectedQuery + ); }); }); describe('buildEntityAlertsQuery', () => { - const getExpectedAlertsQuery = (size?: number) => { + const getExpectedAlertsQuery = (size?: number, severity?: string) => { return { size: size || 0, _source: false, @@ -202,20 +335,30 @@ describe('test helper methods', () => { filter: [ { bool: { - must: [], - filter: [ + should: [ { - match_phrase: { - 'host.name': { - query: 'exampleHost', - }, + term: { + 'host.name': 'exampleHost', }, }, ], - should: [], - must_not: [], + minimum_should_match: 1, }, }, + severity + ? { + bool: { + should: [ + { + term: { + 'kibana.alert.severity': 'low', + }, + }, + ], + minimum_should_match: 1, + }, + } + : undefined, { range: { '@timestamp': { @@ -229,7 +372,7 @@ describe('test helper methods', () => { 'kibana.alert.workflow_status': ['open', 'acknowledged'], }, }, - ], + ].filter(Boolean), }, }, }; @@ -256,5 +399,18 @@ describe('test helper methods', () => { expect(buildEntityAlertsQuery(field, to, from, query)).toEqual(getExpectedAlertsQuery(size)); }); + + it('should return the correct query when given severity query', () => { + const field = 'host.name'; + const query = 'exampleHost'; + const to = 'Tomorrow'; + const from = 'Today'; + const size = undefined; + const severity = 'low'; + + expect(buildEntityAlertsQuery(field, to, from, query, size, severity)).toEqual( + getExpectedAlertsQuery(size, 'low') + ); + }); }); }); diff --git a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts index bd531fa63804..ac2e27b70878 100644 --- a/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts +++ b/x-pack/packages/kbn-cloud-security-posture/common/utils/helpers.ts @@ -43,7 +43,12 @@ export const buildMutedRulesFilter = ( return mutedRulesFilterQuery; }; -export const buildEntityFlyoutPreviewQuery = (field: string, queryValue?: string) => { +export const buildGenericEntityFlyoutPreviewQuery = ( + field: string, + queryValue?: string, + status?: string, + queryField?: string +) => { return { bool: { filter: [ @@ -59,17 +64,52 @@ export const buildEntityFlyoutPreviewQuery = (field: string, queryValue?: string minimum_should_match: 1, }, }, - ], + status && queryField + ? { + bool: { + should: [ + { + term: { + [queryField]: status, + }, + }, + ], + minimum_should_match: 1, + }, + } + : undefined, + ].filter(Boolean), }, }; }; +// Higher-order function for Misconfiguration +export const buildMisconfigurationEntityFlyoutPreviewQuery = ( + field: string, + queryValue?: string, + status?: string +) => { + const queryField = 'result.evaluation'; + return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField); +}; + +// Higher-order function for Vulnerability +export const buildVulnerabilityEntityFlyoutPreviewQuery = ( + field: string, + queryValue?: string, + status?: string +) => { + const queryField = 'vulnerability.severity'; + return buildGenericEntityFlyoutPreviewQuery(field, queryValue, status, queryField); +}; + export const buildEntityAlertsQuery = ( field: string, to: string, from: string, queryValue?: string, - size?: number + size?: number, + severity?: string ) => { return { size: size || 0, @@ -87,20 +127,30 @@ export const buildEntityAlertsQuery = ( filter: [ { bool: { - must: [], - filter: [ + should: [ { - match_phrase: { - [field]: { - query: queryValue, - }, + term: { + [field]: `${queryValue || ''}`, }, }, ], - should: [], - must_not: [], + minimum_should_match: 1, }, }, + severity + ? { + bool: { + should: [ + { + term: { + 'kibana.alert.severity': severity, + }, + }, + ], + minimum_should_match: 1, + }, + } + : undefined, { range: { '@timestamp': { @@ -114,7 +164,7 @@ export const buildEntityAlertsQuery = ( 'kibana.alert.workflow_status': ['open', 'acknowledged'], }, }, - ], + ].filter(Boolean), }, }, }; diff --git a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx index 898e12b5b4c0..6826c47b270c 100644 --- a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/default_edge.tsx @@ -49,6 +49,8 @@ export function DefaultEdge({ path={edgePath} style={{ stroke: euiTheme.colors[color], + }} + css={{ strokeDasharray: '2,2', }} markerEnd={ diff --git a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx index 58ecea3bc3be..5a3e2f8b72b2 100644 --- a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/edge/styles.tsx @@ -128,7 +128,7 @@ export const SvgDefsMarker = () => { const { euiTheme } = useEuiTheme(); return ( - + diff --git a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx index 97b8928c421e..a3dd064d16ab 100644 --- a/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx +++ b/x-pack/packages/kbn-cloud-security-posture/graph/src/components/node/edge_group_node.tsx @@ -16,7 +16,7 @@ export const EdgeGroupNode: React.FC = memo((props: NodeProps) => { <> { return (
        diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts index d4d436e981cc..3e22fdea8066 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/constants/component_constants.ts @@ -11,3 +11,6 @@ export const statusColors = { failed: euiThemeVars.euiColorVis9, unknown: euiThemeVars.euiColorLightShade, }; + +export const HOST_NAME = 'host.name'; +export const USER_NAME = 'user.name'; diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts index 9b126332b567..c8e36898fed1 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_misconfigurations.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { buildGenericEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { useMisconfigurationPreview } from './use_misconfiguration_preview'; export const useHasMisconfigurations = (field: 'host.name' | 'user.name', value: string) => { const { data } = useMisconfigurationPreview({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildGenericEntityFlyoutPreviewQuery(field, value), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts index 336892ee888a..ae7e951ce931 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/hooks/use_has_vulnerabilities.ts @@ -5,13 +5,13 @@ * 2.0. */ -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { buildGenericEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { useVulnerabilitiesPreview } from './use_vulnerabilities_preview'; import { hasVulnerabilitiesData } from '../utils/vulnerability_helpers'; export const useHasVulnerabilities = (field: 'host.name' | 'user.name', value: string) => { const { data: vulnerabilitiesData } = useVulnerabilitiesPreview({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildGenericEntityFlyoutPreviewQuery(field, value), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts index 493e58519bd9..2c7be37de50d 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/types.ts @@ -58,7 +58,7 @@ export interface CspClientPluginStartDeps { export interface CspBaseEsQuery { query?: { bool: { - filter: estypes.QueryDslQueryContainer[]; + filter: Array | undefined; }; }; } diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts index 898f9990a1a9..e2503b7a38a2 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.test.ts @@ -10,6 +10,7 @@ import { getVulnerabilityStats } from './vulnerability_helpers'; import { i18n } from '@kbn/i18n'; describe('getVulnerabilitiesAggregationCount', () => { + const mockFilterFunction = jest.fn(); it('should return empty array when all severity count is 0', () => { const result = getVulnerabilityStats({ critical: 0, high: 0, medium: 0, low: 0, none: 0 }); expect(result).toEqual([]); @@ -17,8 +18,12 @@ describe('getVulnerabilitiesAggregationCount', () => { it('should return stats for low, medium, high, and critical vulnerabilities', () => { const result = getVulnerabilityStats({ critical: 1, high: 2, medium: 3, low: 4, none: 5 }); + const resultWithoutFunctions = result.map((item) => { + const { filter, reset, ...rest } = item; + return rest; + }); - expect(result).toEqual([ + expect(resultWithoutFunctions).toEqual([ { key: i18n.translate( 'xpack.securitySolution.flyout.right.insights.vulnerabilities.noneVulnerabilitiesText', @@ -28,6 +33,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 5, color: '#aaa', + isCurrentFilter: false, }, { key: i18n.translate( @@ -38,6 +44,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 4, color: euiThemeVars.euiColorVis0, + isCurrentFilter: false, }, { key: i18n.translate( @@ -48,6 +55,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 3, color: euiThemeVars.euiColorVis5_behindText, + isCurrentFilter: false, }, { key: i18n.translate( @@ -58,6 +66,7 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 2, color: euiThemeVars.euiColorVis9_behindText, + isCurrentFilter: false, }, { key: i18n.translate( @@ -68,7 +77,43 @@ describe('getVulnerabilitiesAggregationCount', () => { ), count: 1, color: euiThemeVars.euiColorDanger, + isCurrentFilter: false, }, ]); }); + + it('should return correct stats with correct onClick functions', () => { + const result = getVulnerabilityStats( + { critical: 1, high: 2, medium: 3, low: 4, none: 5 }, + mockFilterFunction + ); + const event = { stopPropagation: jest.fn() } as unknown as React.MouseEvent< + SVGElement, + MouseEvent + >; + result[1].filter?.(); + expect(mockFilterFunction).toHaveBeenCalledWith('LOW'); + result[1].reset?.(event); + expect(mockFilterFunction).toHaveBeenCalledWith(''); + }); + + it('should identify correct currentFilter', () => { + const currentFilter = 'LOW'; + const result = getVulnerabilityStats( + { critical: 1, high: 2, medium: 3, low: 4, none: 5 }, + mockFilterFunction, + currentFilter + ); + + // Make sure that Low is set to Current Filter + expect(result[1].isCurrentFilter).toBe(true); + expect(result[1].key).toBe('Low'); + + // Make sure only Low is set as Current Filter and no other severity + result.forEach((item) => { + if (item.key !== 'Low') { + expect(item.isCurrentFilter).toBe(false); + } + }); + }); }); diff --git a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts index c8782daf3530..e1bec795ad44 100644 --- a/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts +++ b/x-pack/packages/kbn-cloud-security-posture/public/src/utils/vulnerability_helpers.ts @@ -14,6 +14,9 @@ interface VulnerabilitiesDistributionBarProps { key: string; count: number; color: string; + isCurrentFilter?: boolean; + filter?: () => void; + reset?: (event: any) => void; } interface VulnerabilityCounts { @@ -30,7 +33,9 @@ export const hasVulnerabilitiesData = (counts: VulnerabilityCounts): boolean => }; export const getVulnerabilityStats = ( - counts: VulnerabilityCounts + counts: VulnerabilityCounts, + filterFunction?: (filter: string) => void, + currentFilter?: string ): VulnerabilitiesDistributionBarProps[] => { const vulnerabilityStats: VulnerabilitiesDistributionBarProps[] = []; @@ -50,6 +55,14 @@ export const getVulnerabilityStats = ( ), count: counts.none, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.UNKNOWN), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.UNKNOWN); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.UNKNOWN, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.low > 0) vulnerabilityStats.push({ @@ -61,6 +74,14 @@ export const getVulnerabilityStats = ( ), count: counts.low, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.LOW), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.LOW); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.LOW, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.medium > 0) @@ -73,6 +94,14 @@ export const getVulnerabilityStats = ( ), count: counts.medium, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.MEDIUM), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.MEDIUM); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.MEDIUM, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.high > 0) vulnerabilityStats.push({ @@ -84,6 +113,14 @@ export const getVulnerabilityStats = ( ), count: counts.high, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.HIGH), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.HIGH); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.HIGH, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); if (counts.critical > 0) vulnerabilityStats.push({ @@ -95,6 +132,14 @@ export const getVulnerabilityStats = ( ), count: counts.critical, color: getSeverityStatusColor(VULNERABILITIES_SEVERITY.CRITICAL), + filter: () => { + filterFunction?.(VULNERABILITIES_SEVERITY.CRITICAL); + }, + isCurrentFilter: currentFilter === VULNERABILITIES_SEVERITY.CRITICAL, + reset: (event: React.MouseEvent) => { + filterFunction?.(''); + event?.stopPropagation(); + }, }); return vulnerabilityStats; diff --git a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx index c2ec745cc5c6..63c8adf37e5b 100644 --- a/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx +++ b/x-pack/packages/kbn-elastic-assistant/impl/assistant_context/constants.tsx @@ -8,6 +8,7 @@ import { KnowledgeBaseConfig } from '../assistant/types'; export const ATTACK_DISCOVERY_STORAGE_KEY = 'attackDiscovery'; +export const DEFEND_INSIGHTS_STORAGE_KEY = 'defendInsights'; export const DEFAULT_ASSISTANT_NAMESPACE = 'elasticAssistantDefault'; export const LAST_CONVERSATION_ID_LOCAL_STORAGE_KEY = 'lastConversationId'; export const MAX_ALERTS_LOCAL_STORAGE_KEY = 'maxAlerts'; diff --git a/x-pack/packages/kbn-elastic-assistant/index.ts b/x-pack/packages/kbn-elastic-assistant/index.ts index 7ec65c960126..7f9ce6fe36c2 100644 --- a/x-pack/packages/kbn-elastic-assistant/index.ts +++ b/x-pack/packages/kbn-elastic-assistant/index.ts @@ -83,6 +83,7 @@ export { /** The default maximum number of alerts to be sent as context when generating Attack discoveries */ DEFAULT_ATTACK_DISCOVERY_MAX_ALERTS, DEFAULT_LATEST_ALERTS, + DEFEND_INSIGHTS_STORAGE_KEY, KNOWLEDGE_BASE_LOCAL_STORAGE_KEY, /** The local storage key that specifies the maximum number of alerts to send as context */ MAX_ALERTS_LOCAL_STORAGE_KEY, diff --git a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts index 5df10e11bb7e..c24da00d7724 100644 --- a/x-pack/packages/kbn-entities-schema/src/schema/entity.ts +++ b/x-pack/packages/kbn-entities-schema/src/schema/entity.ts @@ -25,8 +25,9 @@ export interface MetadataRecord { export interface EntityV2 { 'entity.id': string; - 'entity.last_seen_timestamp': string; 'entity.type': string; + 'entity.display_name': string; + 'entity.last_seen_timestamp'?: string; [metadata: string]: any; } diff --git a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_overview.ts b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_overview.ts index 9983bdee41e2..679abc3d7f96 100644 --- a/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_overview.ts +++ b/x-pack/packages/kbn-slo-schema/src/rest_specs/routes/get_overview.ts @@ -18,10 +18,6 @@ const getOverviewResponseSchema = t.type({ degrading: t.number, stale: t.number, healthy: t.number, - worst: t.type({ - value: t.number, - id: t.string, - }), noData: t.number, burnRateRules: t.number, burnRateActiveAlerts: t.number, diff --git a/x-pack/packages/kbn-slo-schema/src/schema/slo.ts b/x-pack/packages/kbn-slo-schema/src/schema/slo.ts index 0576f1cf328e..c292d355b486 100644 --- a/x-pack/packages/kbn-slo-schema/src/schema/slo.ts +++ b/x-pack/packages/kbn-slo-schema/src/schema/slo.ts @@ -27,16 +27,26 @@ const objectiveSchema = t.intersection([ t.partial({ timesliceTarget: t.number, timesliceWindow: durationType }), ]); -const settingsSchema = t.type({ +const settingsSchema = t.intersection([ + t.type({ + syncDelay: durationType, + frequency: durationType, + preventInitialBackfill: t.boolean, + }), + t.partial({ syncField: t.union([t.string, t.null]) }), +]); + +const groupBySchema = allOrAnyStringOrArray; + +const optionalSettingsSchema = t.partial({ syncDelay: durationType, frequency: durationType, preventInitialBackfill: t.boolean, + syncField: t.union([t.string, t.null]), }); -const groupBySchema = allOrAnyStringOrArray; - -const optionalSettingsSchema = t.partial({ ...settingsSchema.props }); const tagsSchema = t.array(t.string); + // id cannot contain special characters and spaces const sloIdSchema = new t.Type( 'sloIdSchema', diff --git a/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx b/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx index d9f68fe7ef89..6e44f01cbbd6 100644 --- a/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx +++ b/x-pack/packages/ml/aiops_components/src/document_count_chart/document_count_chart.tsx @@ -136,6 +136,8 @@ export interface DocumentCountChartProps { dataTestSubj?: string; /** Optional change point metadata */ changePoint?: DocumentCountStatsChangePoint; + /** Whether the brush should be non-interactive */ + nonInteractive?: boolean; } const SPEC_ID = 'document_count'; @@ -190,6 +192,7 @@ export const DocumentCountChart: FC = (props) => { barHighlightColorOverride, deviationBrush = {}, baselineBrush = {}, + nonInteractive, } = props; const { data, uiSettings, fieldFormats, charts } = dependencies; @@ -470,6 +473,7 @@ export const DocumentCountChart: FC = (props) => { marginLeft={mlBrushMarginLeft} snapTimestamps={snapTimestamps} width={mlBrushWidth} + nonInteractive={nonInteractive} /> diff --git a/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx b/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx index 08b9fc562829..932f509e164d 100644 --- a/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx +++ b/x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx @@ -88,6 +88,11 @@ interface DualBrushProps { * Width */ width: number; + /** + * Whether the brush should be non-interactive. When true, the brush is still visible + * but cannot be moved or resized by the user. + */ + nonInteractive?: boolean; } /** @@ -98,7 +103,16 @@ interface DualBrushProps { * @returns The DualBrush component. */ export const DualBrush: FC = (props) => { - const { windowParameters, min, max, onChange, marginLeft, snapTimestamps, width } = props; + const { + windowParameters, + min, + max, + onChange, + marginLeft, + snapTimestamps, + width, + nonInteractive, + } = props; const d3BrushContainer = useRef(null); const brushes = useRef([]); @@ -301,6 +315,10 @@ export const DualBrush: FC = (props) => { .attr('rx', BRUSH_HANDLE_ROUNDED_CORNER) .attr('ry', BRUSH_HANDLE_ROUNDED_CORNER); + if (nonInteractive) { + mlBrushSelection.merge(mlBrushSelection).attr('pointer-events', 'none'); + } + mlBrushSelection.exit().remove(); } @@ -355,6 +373,7 @@ export const DualBrush: FC = (props) => { deviationMax, snapTimestamps, onChange, + nonInteractive, ]); return ( diff --git a/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx b/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx index 173f33e08f0b..7308185f99b6 100644 --- a/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx +++ b/x-pack/packages/ml/aiops_components/src/progress_controls/progress_controls.tsx @@ -40,6 +40,7 @@ interface ProgressControlProps { shouldRerunAnalysis: boolean; runAnalysisDisabled?: boolean; analysisInfo?: React.ReactNode; + isAnalysisControlsDisabled?: boolean; } /** @@ -63,6 +64,7 @@ export const ProgressControls: FC> = (pr shouldRerunAnalysis, runAnalysisDisabled = false, analysisInfo = null, + isAnalysisControlsDisabled = false, } = props; const progressOutput = Math.round(progress * 100); @@ -73,47 +75,55 @@ export const ProgressControls: FC> = (pr return ( - - {!isRunning && ( - - - - - - {shouldRerunAnalysis && ( - <> - - - - - )} - - - )} - {isRunning && ( - - - - )} - - {(progress === 1 || isRunning === false) && !isBrushCleared ? ( + {!isAnalysisControlsDisabled && ( + + {!isRunning && ( + + + + + + {shouldRerunAnalysis && ( + <> + + + + + )} + + + )} + {isRunning && ( + + + + )} + + )} + + {(progress === 1 || isRunning === false) && !isBrushCleared && !isAnalysisControlsDisabled ? ( ( {children} ); @@ -34,7 +38,7 @@ describe('useAlertsHistory', () => { const end = '2023-05-10T00:00:00.000Z'; const ruleId = 'cfd36e60-ef22-11ed-91eb-b7893acacfe2'; - afterEach(() => { + beforeEach(() => { jest.clearAllMocks(); }); @@ -44,7 +48,7 @@ describe('useAlertsHistory', () => { () => useAlertsHistory({ http, - featureIds: [AlertConsumers.APM], + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, }), @@ -61,16 +65,13 @@ describe('useAlertsHistory', () => { }); it('returns no data when API error', async () => { - const http = { - post: jest.fn().mockImplementation(() => { - throw new Error('ES error'); - }), - } as unknown as HttpSetup; + mockServices.http.post.mockRejectedValueOnce(new Error('ES error')); + const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, }), @@ -87,54 +88,53 @@ describe('useAlertsHistory', () => { }); it('returns the alert history chart data', async () => { - const http = { - post: jest.fn().mockResolvedValue({ - hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, - histogramTriggeredAlerts: { - buckets: [ - { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, - { key_as_string: '2023-04-11T00:00:00.000Z', key: 1681171200000, doc_count: 0 }, - { key_as_string: '2023-04-12T00:00:00.000Z', key: 1681257600000, doc_count: 0 }, - { key_as_string: '2023-04-13T00:00:00.000Z', key: 1681344000000, doc_count: 0 }, - { key_as_string: '2023-04-14T00:00:00.000Z', key: 1681430400000, doc_count: 0 }, - { key_as_string: '2023-04-15T00:00:00.000Z', key: 1681516800000, doc_count: 0 }, - { key_as_string: '2023-04-16T00:00:00.000Z', key: 1681603200000, doc_count: 0 }, - { key_as_string: '2023-04-17T00:00:00.000Z', key: 1681689600000, doc_count: 0 }, - { key_as_string: '2023-04-18T00:00:00.000Z', key: 1681776000000, doc_count: 0 }, - { key_as_string: '2023-04-19T00:00:00.000Z', key: 1681862400000, doc_count: 0 }, - { key_as_string: '2023-04-20T00:00:00.000Z', key: 1681948800000, doc_count: 0 }, - { key_as_string: '2023-04-21T00:00:00.000Z', key: 1682035200000, doc_count: 0 }, - { key_as_string: '2023-04-22T00:00:00.000Z', key: 1682121600000, doc_count: 0 }, - { key_as_string: '2023-04-23T00:00:00.000Z', key: 1682208000000, doc_count: 0 }, - { key_as_string: '2023-04-24T00:00:00.000Z', key: 1682294400000, doc_count: 0 }, - { key_as_string: '2023-04-25T00:00:00.000Z', key: 1682380800000, doc_count: 0 }, - { key_as_string: '2023-04-26T00:00:00.000Z', key: 1682467200000, doc_count: 0 }, - { key_as_string: '2023-04-27T00:00:00.000Z', key: 1682553600000, doc_count: 0 }, - { key_as_string: '2023-04-28T00:00:00.000Z', key: 1682640000000, doc_count: 0 }, - { key_as_string: '2023-04-29T00:00:00.000Z', key: 1682726400000, doc_count: 0 }, - { key_as_string: '2023-04-30T00:00:00.000Z', key: 1682812800000, doc_count: 0 }, - { key_as_string: '2023-05-01T00:00:00.000Z', key: 1682899200000, doc_count: 0 }, - { key_as_string: '2023-05-02T00:00:00.000Z', key: 1682985600000, doc_count: 0 }, - { key_as_string: '2023-05-03T00:00:00.000Z', key: 1683072000000, doc_count: 0 }, - { key_as_string: '2023-05-04T00:00:00.000Z', key: 1683158400000, doc_count: 0 }, - { key_as_string: '2023-05-05T00:00:00.000Z', key: 1683244800000, doc_count: 0 }, - { key_as_string: '2023-05-06T00:00:00.000Z', key: 1683331200000, doc_count: 0 }, - { key_as_string: '2023-05-07T00:00:00.000Z', key: 1683417600000, doc_count: 0 }, - { key_as_string: '2023-05-08T00:00:00.000Z', key: 1683504000000, doc_count: 0 }, - { key_as_string: '2023-05-09T00:00:00.000Z', key: 1683590400000, doc_count: 0 }, - { key_as_string: '2023-05-10T00:00:00.000Z', key: 1683676800000, doc_count: 32 }, - ], - }, + mockServices.http.post.mockResolvedValueOnce({ + hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, + histogramTriggeredAlerts: { + buckets: [ + { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, + { key_as_string: '2023-04-11T00:00:00.000Z', key: 1681171200000, doc_count: 0 }, + { key_as_string: '2023-04-12T00:00:00.000Z', key: 1681257600000, doc_count: 0 }, + { key_as_string: '2023-04-13T00:00:00.000Z', key: 1681344000000, doc_count: 0 }, + { key_as_string: '2023-04-14T00:00:00.000Z', key: 1681430400000, doc_count: 0 }, + { key_as_string: '2023-04-15T00:00:00.000Z', key: 1681516800000, doc_count: 0 }, + { key_as_string: '2023-04-16T00:00:00.000Z', key: 1681603200000, doc_count: 0 }, + { key_as_string: '2023-04-17T00:00:00.000Z', key: 1681689600000, doc_count: 0 }, + { key_as_string: '2023-04-18T00:00:00.000Z', key: 1681776000000, doc_count: 0 }, + { key_as_string: '2023-04-19T00:00:00.000Z', key: 1681862400000, doc_count: 0 }, + { key_as_string: '2023-04-20T00:00:00.000Z', key: 1681948800000, doc_count: 0 }, + { key_as_string: '2023-04-21T00:00:00.000Z', key: 1682035200000, doc_count: 0 }, + { key_as_string: '2023-04-22T00:00:00.000Z', key: 1682121600000, doc_count: 0 }, + { key_as_string: '2023-04-23T00:00:00.000Z', key: 1682208000000, doc_count: 0 }, + { key_as_string: '2023-04-24T00:00:00.000Z', key: 1682294400000, doc_count: 0 }, + { key_as_string: '2023-04-25T00:00:00.000Z', key: 1682380800000, doc_count: 0 }, + { key_as_string: '2023-04-26T00:00:00.000Z', key: 1682467200000, doc_count: 0 }, + { key_as_string: '2023-04-27T00:00:00.000Z', key: 1682553600000, doc_count: 0 }, + { key_as_string: '2023-04-28T00:00:00.000Z', key: 1682640000000, doc_count: 0 }, + { key_as_string: '2023-04-29T00:00:00.000Z', key: 1682726400000, doc_count: 0 }, + { key_as_string: '2023-04-30T00:00:00.000Z', key: 1682812800000, doc_count: 0 }, + { key_as_string: '2023-05-01T00:00:00.000Z', key: 1682899200000, doc_count: 0 }, + { key_as_string: '2023-05-02T00:00:00.000Z', key: 1682985600000, doc_count: 0 }, + { key_as_string: '2023-05-03T00:00:00.000Z', key: 1683072000000, doc_count: 0 }, + { key_as_string: '2023-05-04T00:00:00.000Z', key: 1683158400000, doc_count: 0 }, + { key_as_string: '2023-05-05T00:00:00.000Z', key: 1683244800000, doc_count: 0 }, + { key_as_string: '2023-05-06T00:00:00.000Z', key: 1683331200000, doc_count: 0 }, + { key_as_string: '2023-05-07T00:00:00.000Z', key: 1683417600000, doc_count: 0 }, + { key_as_string: '2023-05-08T00:00:00.000Z', key: 1683504000000, doc_count: 0 }, + { key_as_string: '2023-05-09T00:00:00.000Z', key: 1683590400000, doc_count: 0 }, + { key_as_string: '2023-05-10T00:00:00.000Z', key: 1683676800000, doc_count: 32 }, + ], }, - }), - } as unknown as HttpSetup; + }, + }); + const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, }), @@ -155,26 +155,24 @@ describe('useAlertsHistory', () => { it('calls http post including instanceId query', async () => { const controller = new AbortController(); const signal = controller.signal; - const mockedHttpPost = jest.fn(); - const http = { - post: mockedHttpPost.mockResolvedValue({ - hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, - histogramTriggeredAlerts: { - buckets: [ - { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, - ], - }, + mockServices.http.post.mockResolvedValueOnce({ + hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, + histogramTriggeredAlerts: { + buckets: [ + { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, + ], }, - }), - } as unknown as HttpSetup; + }, + }); const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], + consumers: ['foo'], ruleId, dateRange: { from: start, to: end }, instanceId: 'instance-1', @@ -187,9 +185,10 @@ describe('useAlertsHistory', () => { await act(async () => { await waitFor(() => result.current.isSuccess); }); - expect(mockedHttpPost).toBeCalledWith('/internal/rac/alerts/find', { + + expect(mockServices.http.post).toBeCalledWith('/internal/rac/alerts/find', { body: - '{"size":0,"feature_ids":["apm"],"query":{"bool":{"must":[' + + '{"size":0,"rule_type_ids":["apm"],"consumers":["foo"],"query":{"bool":{"must":[' + '{"term":{"kibana.alert.rule.uuid":"cfd36e60-ef22-11ed-91eb-b7893acacfe2"}},' + '{"term":{"kibana.alert.instance.id":"instance-1"}},' + '{"range":{"kibana.alert.time_range":{"from":"2023-04-10T00:00:00.000Z","to":"2023-05-10T00:00:00.000Z"}}}]}},' + @@ -204,26 +203,23 @@ describe('useAlertsHistory', () => { it('calls http post without * instanceId query', async () => { const controller = new AbortController(); const signal = controller.signal; - const mockedHttpPost = jest.fn(); - const http = { - post: mockedHttpPost.mockResolvedValue({ - hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, - aggregations: { - avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, - histogramTriggeredAlerts: { - buckets: [ - { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, - ], - }, + mockServices.http.post.mockResolvedValueOnce({ + hits: { total: { value: 32, relation: 'eq' }, max_score: null, hits: [] }, + aggregations: { + avgTimeToRecoverUS: { doc_count: 28, recoveryTime: { value: 134959464.2857143 } }, + histogramTriggeredAlerts: { + buckets: [ + { key_as_string: '2023-04-10T00:00:00.000Z', key: 1681084800000, doc_count: 0 }, + ], }, - }), - } as unknown as HttpSetup; + }, + }); const { result, waitFor } = renderHook( () => useAlertsHistory({ - http, - featureIds: [AlertConsumers.APM], + ...mockServices, + ruleTypeIds: ['apm'], ruleId, dateRange: { from: start, to: end }, instanceId: '*', @@ -236,9 +232,10 @@ describe('useAlertsHistory', () => { await act(async () => { await waitFor(() => result.current.isSuccess); }); - expect(mockedHttpPost).toBeCalledWith('/internal/rac/alerts/find', { + + expect(mockServices.http.post).toBeCalledWith('/internal/rac/alerts/find', { body: - '{"size":0,"feature_ids":["apm"],"query":{"bool":{"must":[' + + '{"size":0,"rule_type_ids":["apm"],"query":{"bool":{"must":[' + '{"term":{"kibana.alert.rule.uuid":"cfd36e60-ef22-11ed-91eb-b7893acacfe2"}},' + '{"range":{"kibana.alert.time_range":{"from":"2023-04-10T00:00:00.000Z","to":"2023-05-10T00:00:00.000Z"}}}]}},' + '"aggs":{"histogramTriggeredAlerts":{"date_histogram":{"field":"kibana.alert.start","fixed_interval":"1d",' + diff --git a/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts b/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts index 193acb63f845..d045fab2e635 100644 --- a/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts +++ b/x-pack/packages/observability/alert_details/src/hooks/use_alerts_history.ts @@ -14,14 +14,14 @@ import { ALERT_START, ALERT_STATUS, ALERT_TIME_RANGE, - ValidFeatureId, } from '@kbn/rule-data-utils'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; import { useQuery } from '@tanstack/react-query'; export interface Props { http: HttpSetup | undefined; - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; ruleId: string; dateRange: { from: string; @@ -49,13 +49,15 @@ export const EMPTY_ALERTS_HISTORY = { }; export function useAlertsHistory({ - featureIds, + ruleTypeIds, + consumers, ruleId, dateRange, http, instanceId, }: Props): UseAlertsHistory { - const enabled = !!featureIds.length; + const enabled = !!ruleTypeIds.length; + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['useAlertsHistory'], queryFn: async ({ signal }) => { @@ -63,7 +65,8 @@ export function useAlertsHistory({ throw new Error('Http client is missing'); } return fetchTriggeredAlertsHistory({ - featureIds, + ruleTypeIds, + consumers, http, ruleId, dateRange, @@ -74,6 +77,7 @@ export function useAlertsHistory({ refetchOnWindowFocus: false, enabled, }); + return { data: isInitialLoading ? EMPTY_ALERTS_HISTORY : data ?? EMPTY_ALERTS_HISTORY, isLoading: enabled && (isInitialLoading || isLoading || isRefetching), @@ -101,14 +105,16 @@ interface AggsESResponse { } export async function fetchTriggeredAlertsHistory({ - featureIds, + ruleTypeIds, + consumers, http, ruleId, dateRange, signal, instanceId, }: { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; http: HttpSetup; ruleId: string; dateRange: { @@ -123,7 +129,8 @@ export async function fetchTriggeredAlertsHistory({ signal, body: JSON.stringify({ size: 0, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, query: { bool: { must: [ diff --git a/x-pack/packages/observability/alert_details/tsconfig.json b/x-pack/packages/observability/alert_details/tsconfig.json index a349651fdff7..d1b4c3fb2ce2 100644 --- a/x-pack/packages/observability/alert_details/tsconfig.json +++ b/x-pack/packages/observability/alert_details/tsconfig.json @@ -17,9 +17,9 @@ ], "kbn_references": [ "@kbn/i18n", - "@kbn/core-http-browser", "@kbn/rule-data-utils", "@kbn/core", - "@kbn/rule-registry-plugin" + "@kbn/rule-registry-plugin", + "@kbn/core-http-browser-mocks" ] } diff --git a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx index c2b1a0989c2e..fdb059d97194 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_categories/log_categories_result_content.tsx @@ -76,7 +76,6 @@ export const LogCategoriesResultContent: React.FC void; logCategory: LogCategory; - categoryDetailsServiceState: StateFrom; dependencies: LogCategoriesFlyoutDependencies; logsSource: ResolvedIndexNameLogsSourceConfiguration; documentFilters?: QueryDslQueryContainer[]; @@ -51,7 +55,6 @@ interface LogCategoryDetailsFlyoutProps { export const LogCategoryDetailsFlyout: React.FC = ({ onCloseFlyout, logCategory, - categoryDetailsServiceState, dependencies, logsSource, documentFilters, @@ -61,11 +64,19 @@ export const LogCategoryDetailsFlyout: React.FC = prefix: 'flyoutTitle', }); + const categoryFilter = useMemo(() => { + return createCategoryQuery(logsSource.messageField)(logCategory.terms); + }, [logCategory.terms, logsSource.messageField]); + + const documentAndCategoryFilters = useMemo(() => { + return [...(documentFilters ?? []), categoryFilter]; + }, [categoryFilter, documentFilters]); + const linkFilters = useMemo(() => { return [ ...(documentFilters ? documentFilters.map((filter) => ({ filter })) : []), { - filter: createCategoryQuery(logsSource.messageField)(logCategory.terms), + filter: categoryFilter, meta: { name: i18n.translate( 'xpack.observabilityLogsOverview.logCategoryDetailsFlyout.discoverLinkFilterName', @@ -79,7 +90,20 @@ export const LogCategoryDetailsFlyout: React.FC = }, }, ]; - }, [documentFilters, logCategory.terms, logsSource.messageField]); + }, [categoryFilter, documentFilters, logCategory.terms]); + + const filters = useMemo(() => { + return documentAndCategoryFilters.map((filter) => + buildCustomFilter( + logsSource.indexName, + filter, + false, + false, + 'Document filters', + FilterStateStore.APP_STATE + ) + ); + }, [documentAndCategoryFilters, logsSource.indexName]); return ( onCloseFlyout()} aria-labelledby={flyoutTitleId}> @@ -107,32 +131,12 @@ export const LogCategoryDetailsFlyout: React.FC = - - {categoryDetailsServiceState.matches({ hasCategory: 'fetchingDocuments' }) ? ( - - ) : categoryDetailsServiceState.matches({ hasCategory: 'error' }) ? ( - - ) : ( - - )} + + ); diff --git a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx index 6b43fa86fe49..0101a2496415 100644 --- a/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx +++ b/x-pack/packages/observability/logs_overview/src/components/log_category_details/log_category_document_examples_table.tsx @@ -5,147 +5,45 @@ * 2.0. */ -import { EuiBasicTable, EuiBasicTableColumn, EuiSpacer, EuiText } from '@elastic/eui'; -import React, { useMemo } from 'react'; -import { i18n } from '@kbn/i18n'; -import { DataGridDensity, ROWS_HEIGHT_OPTIONS } from '@kbn/unified-data-table'; -import moment from 'moment'; -import type { SettingsStart } from '@kbn/core-ui-settings-browser'; -import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import { CoreStart } from '@kbn/core-lifecycle-browser'; -import { getLogLevelBadgeCell, LazySummaryColumn } from '@kbn/discover-contextual-components'; -import type { LogCategoryDocument } from '../../services/category_details_service/types'; -import { type ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; +import React from 'react'; +import { LazySavedSearchComponent } from '@kbn/saved-search-component'; +import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { DataViewsContract } from '@kbn/data-views-plugin/public'; +import { ISearchStartSearchSource } from '@kbn/data-plugin/common'; +import { Filter } from '@kbn/es-query'; +import { ResolvedIndexNameLogsSourceConfiguration } from '../../utils/logs_source'; export interface LogCategoryDocumentExamplesTableDependencies { - core: CoreStart; - uiSettings: SettingsStart; - fieldFormats: FieldFormatsStart; - share: SharePluginStart; + embeddable: EmbeddableStart; + dataViews: DataViewsContract; + searchSource: ISearchStartSearchSource; } export interface LogCategoryDocumentExamplesTableProps { dependencies: LogCategoryDocumentExamplesTableDependencies; - categoryDocuments: LogCategoryDocument[]; logsSource: ResolvedIndexNameLogsSourceConfiguration; + filters: Filter[]; } -const TimestampCell = ({ - dependencies, - timestamp, -}: { - dependencies: LogCategoryDocumentExamplesTableDependencies; - timestamp?: string | number; -}) => { - const dateFormat = useMemo( - () => dependencies.uiSettings.client.get('dateFormat'), - [dependencies.uiSettings.client] - ); - if (!timestamp) return null; - - if (dateFormat) { - return <>{moment(timestamp).format(dateFormat)}; - } else { - return <>{timestamp}; - } -}; - -const LogLevelBadgeCell = getLogLevelBadgeCell('log.level'); - export const LogCategoryDocumentExamplesTable: React.FC = ({ - categoryDocuments, dependencies, + filters, logsSource, }) => { - const columns: Array> = [ - { - field: 'row', - name: 'Timestamp', - width: '25%', - render: (row: any) => { - return ( - - ); - }, - }, - { - field: 'row', - name: 'Log level', - width: '10%', - render: (row: any) => { - return ( - {}} - closePopover={() => {}} - /> - ); - }, - }, - { - field: 'row', - name: 'Summary', - width: '65%', - render: (row: any) => { - return ( - {}} - closePopover={() => {}} - density={DataGridDensity.COMPACT} - rowHeight={ROWS_HEIGHT_OPTIONS.single} - shouldShowFieldHandler={() => false} - core={dependencies.core} - share={dependencies.share} - /> - ); - }, - }, - ]; return ( - <> - - {i18n.translate( - 'xpack.observabilityLogsOverview.logCategoryDocumentExamplesTable.documentCountText', - { - defaultMessage: 'Displaying the latest {documentsCount} documents.', - values: { - documentsCount: categoryDocuments.length, - }, - } - )} - - - - + ); }; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts index 958f71754860..40dc0d1eca12 100644 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_details_service.ts @@ -7,40 +7,24 @@ import { MachineImplementationsFrom, assign, setup } from 'xstate5'; import { LogCategory } from '../../types'; -import { getPlaceholderFor } from '../../utils/xstate5_utils'; -import { - CategoryDetailsServiceDependencies, - LogCategoryDocument, - LogCategoryDetailsParams, -} from './types'; -import { getCategoryDocuments } from './category_documents'; +import { CategoryDetailsServiceDependencies, LogCategoryDetailsParams } from './types'; export const categoryDetailsService = setup({ types: { input: {} as LogCategoryDetailsParams, - output: {} as { - categoryDocuments: LogCategoryDocument[] | null; - }, + output: {} as {}, context: {} as { parameters: LogCategoryDetailsParams; - error?: Error; expandedRowIndex: number | null; expandedCategory: LogCategory | null; - categoryDocuments: LogCategoryDocument[]; }, - events: {} as - | { - type: 'cancel'; - } - | { - type: 'setExpandedCategory'; - rowIndex: number | null; - category: LogCategory | null; - }, - }, - actors: { - getCategoryDocuments: getPlaceholderFor(getCategoryDocuments), + events: {} as { + type: 'setExpandedCategory'; + rowIndex: number | null; + category: LogCategory | null; + }, }, + actors: {}, actions: { storeCategory: assign( ({ context, event }, params: { category: LogCategory | null; rowIndex: number | null }) => ({ @@ -48,22 +32,10 @@ export const categoryDetailsService = setup({ expandedRowIndex: params.rowIndex, }) ), - storeDocuments: assign( - ({ context, event }, params: { categoryDocuments: LogCategoryDocument[] }) => ({ - categoryDocuments: params.categoryDocuments, - }) - ), - storeError: assign((_, params: { error: unknown }) => ({ - error: params.error instanceof Error ? params.error : new Error(String(params.error)), - })), }, guards: { hasCategory: (_guardArgs, params: { expandedCategory: LogCategory | null }) => params.expandedCategory !== null, - hasDocumentExamples: ( - _guardArgs, - params: { categoryDocuments: LogCategoryDocument[] | null } - ) => params.categoryDocuments !== null && params.categoryDocuments.length > 0, }, }).createMachine({ /** @xstate-layout N4IgpgJg5mDOIC5QGMCGAXMUD2AnAlgF5gAy2UsAdMtgK4B26+9UAItsrQLZiOwDEEbPTCVmAN2wBrUWkw4CxMhWp1GzNh2690sBBI4Z8wgNoAGALrmLiUAAdssfE2G2QAD0QBmMwA5KACy+AQFmob4AjABMwQBsADQgAJ6IkYEAnJkA7FmxZlERmQGxAL4liXJYeESk5FQ0DEws7Jw8fILCogYy1BhVirUqDerNWm26+vSScsb01iYRNkggDk4u9G6eCD7+QSFhftFxiSkIvgCsWZSxEVlRsbFZ52Zm515lFX0KNcr1ak2aVo6ARCERiKbSWRfapKOqqRoaFraPiTaZGUyWExRJb2RzOWabbx+QLBULhI7FE7eWL+F45GnRPIRZkfECVb6wob-RFjYH8MC4XB4Sh2AA2GAAZnguL15DDBn8EaMgSiDDMMVZLG5VvjXMstjsSftyTFKclEOdzgFKF5zukvA8zBFnl50udWez5b94SNAcjdPw0PRkGBRdZtXj1oTtsS9mTDqaEuaEBF8udKFkIr5fK6olkzOksgEPdCBt6JWB0MgABYaADKqC4YsgAGFS-g4B0wd0oXKBg2m6LW+24OHljqo-rEMzbpQos8-K7fC9CknTrF0rEbbb0oVMoWIgF3eU2e3OVQK1XaywB82IG2+x2BAKhbgReL0FLcDLPf3G3eH36J8x1xNYCSnFNmSuecXhzdJlydTcqQQLJfHSOc0PyLJN3SMxYiPEtH3PShLxret-yHe8RwEIMQzDLVx0jcDQC2GdoIXOCENXZDsyiOcAiiKJ0iiPDLi8V1CKA4jSOvKAACUwC4VBmA0QDvk7UEughHpfxqBSlJUlg1OqUcGNA3UNggrMs347IjzdaIvGQwSvECXI8k3Z43gEiJJI5BUSMrMiWH05T6FU6j+UFYUxUlaVZSksBQsMqBjIIUycRWJi9RY6dIn8KIAjsu1zkc5CAmiG1fBiaIzB8B0QmPT4iICmSNGS8KjMi2jQxArKwJyjw8pswriocqInOTLwIi3ASD1yQpswCd5WXobAIDgNxdPPCMBss3KEAAWjXRBDvTfcLsu9Jlr8r04WGAEkXGeBGL26MBOQzIt2ut4cwmirCt8W6yzhNqbwo4dH0216LOjTMIjnBdYhK1DYgdHjihtZbUIdWIXJuYGflBoLZI6iKoZe8zJwOw9KtGt1kbuTcsmQrwi0oeCQjzZ5blwt1Cek5TKN22GIIKZbAgKC45pyLyeLwtz4Kyabs1QgWAs0kXqaGhBxdcnzpaE2XXmch0MORmaBJeLwjbKMogA */ @@ -71,7 +43,6 @@ export const categoryDetailsService = setup({ context: ({ input }) => ({ expandedCategory: null, expandedRowIndex: null, - categoryDocuments: [], parameters: input, }), initial: 'idle', @@ -79,38 +50,6 @@ export const categoryDetailsService = setup({ idle: { on: { setExpandedCategory: { - target: 'checkingCategoryState', - actions: [ - { - type: 'storeCategory', - params: ({ event }) => event, - }, - ], - }, - }, - }, - checkingCategoryState: { - always: [ - { - guard: { - type: 'hasCategory', - params: ({ event, context }) => { - return { - expandedCategory: context.expandedCategory, - }; - }, - }, - target: '#hasCategory.fetchingDocuments', - }, - { target: 'idle' }, - ], - }, - hasCategory: { - id: 'hasCategory', - initial: 'fetchingDocuments', - on: { - setExpandedCategory: { - target: 'checkingCategoryState', actions: [ { type: 'storeCategory', @@ -119,73 +58,13 @@ export const categoryDetailsService = setup({ ], }, }, - states: { - fetchingDocuments: { - invoke: { - src: 'getCategoryDocuments', - id: 'fetchCategoryDocumentExamples', - input: ({ context }) => ({ - ...context.parameters, - categoryTerms: context.expandedCategory!.terms, - }), - onDone: [ - { - guard: { - type: 'hasDocumentExamples', - params: ({ event }) => { - return event.output; - }, - }, - target: 'hasData', - actions: [ - { - type: 'storeDocuments', - params: ({ event }) => { - return event.output; - }, - }, - ], - }, - { - target: 'noData', - actions: [ - { - type: 'storeDocuments', - params: ({ event }) => { - return { categoryDocuments: [] }; - }, - }, - ], - }, - ], - onError: { - target: 'error', - actions: [ - { - type: 'storeError', - params: ({ event }) => ({ error: event.error }), - }, - ], - }, - }, - }, - hasData: {}, - noData: {}, - error: {}, - }, }, }, - output: ({ context }) => ({ - categoryDocuments: context.categoryDocuments, - }), + output: ({ context }) => ({}), }); export const createCategoryDetailsServiceImplementations = ({ search, }: CategoryDetailsServiceDependencies): MachineImplementationsFrom< typeof categoryDetailsService -> => ({ - actors: { - getCategoryDocuments: getCategoryDocuments({ search }), - }, -}); +> => ({}); diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts deleted file mode 100644 index b513fa79fc68..000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/category_documents.ts +++ /dev/null @@ -1,63 +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 { ISearchGeneric } from '@kbn/search-types'; -import { fromPromise } from 'xstate5'; -import { lastValueFrom } from 'rxjs'; -import { flattenHit } from '@kbn/data-service'; -import { LogCategoryDocument, LogCategoryDocumentsParams } from './types'; -import { createGetLogCategoryDocumentsRequestParams } from './queries'; - -export const getCategoryDocuments = ({ search }: { search: ISearchGeneric }) => - fromPromise< - { - categoryDocuments: LogCategoryDocument[]; - }, - LogCategoryDocumentsParams - >( - async ({ - input: { - index, - endTimestamp, - startTimestamp, - timeField, - messageField, - categoryTerms, - additionalFilters = [], - dataView, - }, - signal, - }) => { - const requestParams = createGetLogCategoryDocumentsRequestParams({ - index, - timeField, - messageField, - startTimestamp, - endTimestamp, - additionalFilters, - categoryTerms, - }); - - const { rawResponse } = await lastValueFrom( - search({ params: requestParams }, { abortSignal: signal }) - ); - - const categoryDocuments: LogCategoryDocument[] = - rawResponse.hits?.hits.map((hit) => { - return { - row: { - raw: hit._source, - flattened: flattenHit(hit, dataView), - }, - }; - }) ?? []; - - return { - categoryDocuments, - }; - } - ); diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts deleted file mode 100644 index cd1053077c33..000000000000 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/queries.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { createCategoryQuery } from '../categorize_logs_service/queries'; - -export const createGetLogCategoryDocumentsRequestParams = ({ - index, - timeField, - messageField, - startTimestamp, - endTimestamp, - additionalFilters = [], - categoryTerms = '', - documentCount = 20, -}: { - startTimestamp: string; - endTimestamp: string; - index: string; - timeField: string; - messageField: string; - additionalFilters?: QueryDslQueryContainer[]; - categoryTerms?: string; - documentCount?: number; -}) => { - return { - index, - size: documentCount, - track_total_hits: false, - sort: [{ [timeField]: { order: 'desc' } }], - query: { - bool: { - filter: [ - { - exists: { - field: messageField, - }, - }, - { - range: { - [timeField]: { - gte: startTimestamp, - lte: endTimestamp, - format: 'strict_date_time', - }, - }, - }, - createCategoryQuery(messageField)(categoryTerms), - ...additionalFilters, - ], - }, - }, - }; -}; diff --git a/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts b/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts index 72369275578e..9c3327632055 100644 --- a/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts +++ b/x-pack/packages/observability/logs_overview/src/services/category_details_service/types.ts @@ -8,11 +8,6 @@ import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; import { ISearchGeneric } from '@kbn/search-types'; import { type DataView } from '@kbn/data-views-plugin/common'; -import type { DataTableRecord } from '@kbn/discover-utils'; - -export interface LogCategoryDocument { - row: Pick; -} export interface LogCategoryDetailsParams { additionalFilters: QueryDslQueryContainer[]; @@ -27,5 +22,3 @@ export interface LogCategoryDetailsParams { export interface CategoryDetailsServiceDependencies { search: ISearchGeneric; } - -export type LogCategoryDocumentsParams = LogCategoryDetailsParams & { categoryTerms: string }; diff --git a/x-pack/packages/observability/logs_overview/tsconfig.json b/x-pack/packages/observability/logs_overview/tsconfig.json index 29595ce0162f..610ef8cc0126 100644 --- a/x-pack/packages/observability/logs_overview/tsconfig.json +++ b/x-pack/packages/observability/logs_overview/tsconfig.json @@ -34,12 +34,9 @@ "@kbn/es-query", "@kbn/router-utils", "@kbn/share-plugin", - "@kbn/field-formats-plugin", - "@kbn/data-service", - "@kbn/discover-utils", "@kbn/discover-plugin", - "@kbn/unified-data-table", - "@kbn/discover-contextual-components", - "@kbn/core-lifecycle-browser", + "@kbn/embeddable-plugin", + "@kbn/data-plugin", + "@kbn/saved-search-component", ] } diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.test.ts index 22cee17bb1a6..aa25821b4ac1 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.test.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.test.ts @@ -37,4 +37,16 @@ describe('unflattenObject', () => { }, }); }); + + it('handles null values correctly', () => { + expect( + unflattenObject({ + 'agent.name': null, + }) + ).toEqual({ + agent: { + name: null, + }, + }); + }); }); diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts index 83508d5d2dbf..8a4493905f1d 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/object/unflatten_object.ts @@ -6,13 +6,17 @@ */ import { set } from '@kbn/safer-lodash-set'; +import { DedotObject } from '@kbn/utility-types'; -export function unflattenObject(source: Record, target: Record = {}) { +export function unflattenObject>( + source: T, + target: Record = {} +): DedotObject { // eslint-disable-next-line guard-for-in for (const key in source) { const val = source[key as keyof typeof source]; if (Array.isArray(val)) { - const unflattenedArray = val.map((item) => { + const unflattenedArray = val.map((item: unknown) => { if (item && typeof item === 'object' && !Array.isArray(item)) { return unflattenObject(item); } @@ -23,5 +27,6 @@ export function unflattenObject(source: Record, target: Record; } diff --git a/x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json b/x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json index 7954cdc946e9..e2226268918a 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json +++ b/x-pack/packages/observability/observability_utils/observability_utils_common/tsconfig.json @@ -19,5 +19,6 @@ "@kbn/es-query", "@kbn/safer-lodash-set", "@kbn/inference-common", + "@kbn/utility-types", ] } diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts index 78ed20a582bc..92c7b8d19e53 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/client/create_observability_es_client.ts @@ -10,12 +10,15 @@ import type { FieldCapsRequest, FieldCapsResponse, MsearchRequest, + ScalarValue, SearchResponse, } from '@elastic/elasticsearch/lib/api/types'; import { withSpan } from '@kbn/apm-utils'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; -import type { ESQLSearchResponse, ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; -import { Required } from 'utility-types'; +import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; +import { Required, ValuesType } from 'utility-types'; +import { DedotObject } from '@kbn/utility-types'; +import { unflattenObject } from '@kbn/task-manager-plugin/server/metrics/lib'; import { esqlResultToPlainObjects } from '../esql_result_to_plain_objects'; type SearchRequest = ESSearchRequest & { @@ -24,19 +27,52 @@ type SearchRequest = ESSearchRequest & { size: number | boolean; }; -type EsqlQueryParameters = EsqlQueryRequest & { parseOutput?: boolean }; -type EsqlOutputParameters = Omit & { - parseOutput?: true; - format?: 'json'; - columnar?: false; -}; +export interface EsqlOptions { + transform?: 'none' | 'plain' | 'unflatten'; +} + +export type EsqlValue = ScalarValue | ScalarValue[]; + +export type EsqlOutput = Record; + +type MaybeUnflatten, TApply> = TApply extends true + ? DedotObject + : T; + +interface UnparsedEsqlResponseOf { + columns: Array<{ name: keyof TOutput; type: string }>; + values: Array>>; +} -type EsqlParameters = EsqlOutputParameters | EsqlQueryParameters; +interface ParsedEsqlResponseOf< + TOutput extends EsqlOutput, + TOptions extends EsqlOptions | undefined = { transform: 'none' } +> { + hits: Array< + MaybeUnflatten< + { + [key in keyof TOutput]: TOutput[key]; + }, + TOptions extends { transform: 'unflatten' } ? true : false + > + >; +} export type InferEsqlResponseOf< - TOutput = unknown, - TParameters extends EsqlParameters = EsqlParameters -> = TParameters extends EsqlOutputParameters ? TOutput[] : ESQLSearchResponse; + TOutput extends EsqlOutput, + TOptions extends EsqlOptions | undefined = { transform: 'none' } +> = TOptions extends { transform: 'plain' | 'unflatten' } + ? ParsedEsqlResponseOf + : UnparsedEsqlResponseOf; + +export type ObservabilityESSearchRequest = SearchRequest; + +export type ObservabilityEsQueryRequest = Omit; + +export type ParsedEsqlResponse = ParsedEsqlResponseOf; +export type UnparsedEsqlResponse = UnparsedEsqlResponseOf; + +export type EsqlQueryResponse = UnparsedEsqlResponse | ParsedEsqlResponse; /** * An Elasticsearch Client with a fully typed `search` method and built-in @@ -57,14 +93,18 @@ export interface ObservabilityElasticsearchClient { operationName: string, request: Required ): Promise; - esql( + esql( operationName: string, - parameters: TQueryParams - ): Promise>; - esql( + parameters: ObservabilityEsQueryRequest + ): Promise>; + esql< + TOutput extends EsqlOutput = EsqlOutput, + TEsqlOptions extends EsqlOptions = { transform: 'none' } + >( operationName: string, - parameters: TQueryParams - ): Promise>; + parameters: ObservabilityEsQueryRequest, + options: TEsqlOptions + ): Promise>; client: ElasticsearchClient; } @@ -109,32 +149,41 @@ export function createObservabilityEsClient({ }); }); }, - esql( + esql( operationName: string, - { parseOutput = true, format = 'json', columnar = false, ...parameters }: TSearchRequest - ) { - logger.trace(() => `Request (${operationName}):\n${JSON.stringify(parameters, null, 2)}`); - return withSpan({ name: operationName, labels: { plugin } }, () => { - return client.esql.query( - { ...parameters, format, columnar }, - { - querystring: { - drop_null_columns: true, - }, - } - ); - }) - .then((response) => { - logger.trace(() => `Response (${operationName}):\n${JSON.stringify(response, null, 2)}`); - - const esqlResponse = response as unknown as ESQLSearchResponse; - - const shouldParseOutput = parseOutput && !columnar && format === 'json'; - return shouldParseOutput ? esqlResultToPlainObjects(esqlResponse) : esqlResponse; - }) - .catch((error) => { - throw error; - }); + parameters: ObservabilityEsQueryRequest, + options?: EsqlOptions + ): Promise> { + return callWithLogger(operationName, parameters, () => { + return client.esql + .query( + { ...parameters }, + { + querystring: { + drop_null_columns: true, + }, + } + ) + .then((response) => { + const esqlResponse = response as unknown as UnparsedEsqlResponseOf; + + const transform = options?.transform ?? 'none'; + + if (transform === 'none') { + return esqlResponse; + } + + const parsedResponse = { hits: esqlResultToPlainObjects(esqlResponse) }; + + if (transform === 'plain') { + return parsedResponse; + } + + return { + hits: parsedResponse.hits.map((hit) => unflattenObject(hit)), + }; + }) as Promise>; + }); }, search( operationName: string, diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.test.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.test.ts index 4557d0ba0bdd..55d77368cfdf 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.test.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.test.ts @@ -27,40 +27,15 @@ describe('esqlResultToPlainObjects', () => { expect(output).toEqual([{ name: 'Foo Bar' }]); }); - it('should return columns without "text" or "keyword" in their names', () => { + it('should not unflatten objects', () => { const result: ESQLSearchResponse = { columns: [ - { name: 'name.text', type: 'text' }, - { name: 'age', type: 'keyword' }, - ], - values: [ - ['Foo Bar', 30], - ['Foo Qux', 25], - ], - }; - const output = esqlResultToPlainObjects(result); - expect(output).toEqual([ - { name: 'Foo Bar', age: 30 }, - { name: 'Foo Qux', age: 25 }, - ]); - }); - - it('should handle mixed columns correctly', () => { - const result: ESQLSearchResponse = { - columns: [ - { name: 'name', type: 'text' }, - { name: 'name.text', type: 'text' }, - { name: 'age', type: 'keyword' }, - ], - values: [ - ['Foo Bar', 'Foo Bar', 30], - ['Foo Qux', 'Foo Qux', 25], + { name: 'name', type: 'keyword' }, + { name: 'name.nested', type: 'keyword' }, ], + values: [['Foo Bar', 'Bar Foo']], }; const output = esqlResultToPlainObjects(result); - expect(output).toEqual([ - { name: 'Foo Bar', age: 30 }, - { name: 'Foo Qux', age: 25 }, - ]); + expect(output).toEqual([{ name: 'Foo Bar', 'name.nested': 'Bar Foo' }]); }); }); diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts index 34781153532c..53f54b608ca3 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/es/esql_result_to_plain_objects.ts @@ -6,28 +6,24 @@ */ import type { ESQLSearchResponse } from '@kbn/es-types'; -import { unflattenObject } from '@kbn/observability-utils-common/object/unflatten_object'; -export function esqlResultToPlainObjects( - result: ESQLSearchResponse -): TDocument[] { - return result.values.map((row) => { - return unflattenObject( - row.reduce>((acc, value, index) => { - const column = result.columns[index]; +export function esqlResultToPlainObjects< + TDocument extends Record = Record +>(result: ESQLSearchResponse): TDocument[] { + return result.values.map((row): TDocument => { + return row.reduce>((acc, value, index) => { + const column = result.columns[index]; - if (!column) { - return acc; - } + if (!column) { + return acc; + } - // Removes the type suffix from the column name - const name = column.name.replace(/\.(text|keyword)$/, ''); - if (!acc[name]) { - acc[name] = value; - } + const name = column.name; + if (!acc[name]) { + acc[name] = value; + } - return acc; - }, {}) - ) as TDocument; + return acc; + }, {}) as TDocument; }); } diff --git a/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json b/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json index f51d93089c62..f6dd781184b8 100644 --- a/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json +++ b/x-pack/packages/observability/observability_utils/observability_utils_server/tsconfig.json @@ -24,5 +24,7 @@ "@kbn/alerting-plugin", "@kbn/rule-registry-plugin", "@kbn/rule-data-utils", + "@kbn/utility-types", + "@kbn/task-manager-plugin", ] } diff --git a/x-pack/packages/security-solution/distribution_bar/README.md b/x-pack/packages/security-solution/distribution_bar/README.md new file mode 100644 index 000000000000..51edea2dd184 --- /dev/null +++ b/x-pack/packages/security-solution/distribution_bar/README.md @@ -0,0 +1,10 @@ +# Security Solution's Distribution Bar + +The DistributionBar component visually represents data distribution, such as critical, high, medium, and low alerts. + +## Storybook + +General look of the component can be checked visually running the following storybook: +`yarn storybook security_solution_packages` + +Note that all the interactions are mocked. \ No newline at end of file diff --git a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx index f2d1099d17c5..0942cace2326 100644 --- a/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx +++ b/x-pack/packages/security-solution/distribution_bar/src/distribution_bar.tsx @@ -12,7 +12,15 @@ import { css } from '@emotion/react'; /** DistributionBar component props */ export interface DistributionBarProps { /** distribution data points */ - stats: Array<{ key: string; count: number; color: string; label?: React.ReactNode }>; + stats: Array<{ + key: string; + count: number; + color: string; + label?: React.ReactNode; + isCurrentFilter?: boolean; + filter?: () => void; + reset?: (event: React.MouseEvent) => void; + }>; /** hide the label above the bar at first render */ hideLastTooltip?: boolean; /** data-test-subj used for querying the component in tests */ @@ -36,6 +44,7 @@ const useStyles = () => { position: relative; border-radius: 2px; height: 5px; + min-width: 10px; // prevents bar from shrinking too small `, empty: css` background-color: ${euiTheme.colors.lightShade}; @@ -155,7 +164,19 @@ export const DistributionBar: React.FC = React.memo(functi const prettyNumber = numeral(stat.count).format('0,0a'); return ( -
        +
        { + if (event.key === 'Enter' || event.key === ' ') { + stat.filter?.(); + } + }} + tabIndex={0} + role="button" + >
        = React.memo(functi {stat.label ? stat.label : stat.key} + {stat.isCurrentFilter ? ( + + + + ) : undefined} diff --git a/x-pack/packages/security-solution/features/src/security/kibana_features.ts b/x-pack/packages/security-solution/features/src/security/kibana_features.ts index 2fb6b1198879..458b8f6fd1f1 100644 --- a/x-pack/packages/security-solution/features/src/security/kibana_features.ts +++ b/x-pack/packages/security-solution/features/src/security/kibana_features.ts @@ -41,6 +41,11 @@ const SECURITY_RULE_TYPES = [ NEW_TERMS_RULE_TYPE_ID, ]; +const alertingFeatures = SECURITY_RULE_TYPES.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [SERVER_APP_ID], +})); + export const getSecurityBaseKibanaFeature = ({ savedObjects, }: SecurityFeatureParams): BaseKibanaFeatureConfig => ({ @@ -59,7 +64,7 @@ export const getSecurityBaseKibanaFeature = ({ management: { insightsAndAlerting: ['triggersActions'], }, - alerting: SECURITY_RULE_TYPES, + alerting: alertingFeatures, description: i18n.translate( 'securitySolutionPackages.features.featureRegistry.securityGroupDescription', { @@ -87,12 +92,8 @@ export const getSecurityBaseKibanaFeature = ({ read: [], }, alerting: { - rule: { - all: SECURITY_RULE_TYPES, - }, - alert: { - all: SECURITY_RULE_TYPES, - }, + rule: { all: alertingFeatures }, + alert: { all: alertingFeatures }, }, management: { insightsAndAlerting: ['triggersActions'], @@ -109,10 +110,10 @@ export const getSecurityBaseKibanaFeature = ({ }, alerting: { rule: { - read: SECURITY_RULE_TYPES, + read: alertingFeatures, }, alert: { - all: SECURITY_RULE_TYPES, + all: alertingFeatures, }, }, management: { diff --git a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts index f5af4cd05ad2..06d6709ddcb4 100644 --- a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts +++ b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.styles.ts @@ -39,19 +39,19 @@ export const SolutionSideNavPanelStyles = ( // bottom inset to match timeline bar top shadow inset 0 -6px ${euiTheme.size.xs} -${euiTheme.size.xs} rgb(0 0 0 / 15%); `} +`; - .solutionSideNavPanelLink { - &:focus-within { - background-color: transparent; - a { - text-decoration: auto; - } +export const SolutionSideNavPanelItemStyles = (euiTheme: EuiThemeComputed<{}>) => css` + &:focus-within { + background-color: transparent; + a { + text-decoration: auto; } - &:hover { - background-color: ${transparentize(euiTheme.colors.primary, 0.1)}; - a { - text-decoration: underline; - } + } + &:hover { + background-color: ${transparentize(euiTheme.colors.lightShade, 0.5)}; + a { + text-decoration: underline; } } `; diff --git a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx index 248121872018..38cce27db1c4 100644 --- a/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx +++ b/x-pack/packages/security-solution/side_nav/src/solution_side_nav_panel.tsx @@ -48,6 +48,7 @@ import { SolutionSideNavPanelLinksGroupStyles, panelClassName, accordionButtonClassName, + SolutionSideNavPanelItemStyles, } from './solution_side_nav_panel.styles'; export interface SolutionSideNavPanelContentProps { @@ -354,7 +355,8 @@ interface SolutionSideNavPanelItemProps { const SolutionSideNavPanelItem: React.FC = React.memo( function SolutionSideNavPanelItem({ item, onClose }) { const { tracker } = useTelemetryContext(); - const panelLinkClassNames = classNames('solutionSideNavPanelLink'); + const { euiTheme } = useEuiTheme(); + const panelLinkClassNames = classNames(SolutionSideNavPanelItemStyles(euiTheme)); const { id, href, onClick, iconType, openInNewTab } = item; const onClickHandler = useCallback( (ev) => { diff --git a/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts b/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts index 1db1030da510..8f3d48a91005 100644 --- a/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts +++ b/x-pack/packages/security/authorization_core/src/actions/alerting.test.ts @@ -51,21 +51,3 @@ describe('#get', () => { ); }); }); - -test('#isValid', () => { - const alertingActions = new AlertingActions(); - expect(alertingActions.isValid('alerting:foo-ruleType/consumer/alertingType/bar-operation')).toBe( - true - ); - - expect( - alertingActions.isValid('api:alerting:foo-ruleType/consumer/alertingType/bar-operation') - ).toBe(false); - expect(alertingActions.isValid('api:foo-ruleType/consumer/alertingType/bar-operation')).toBe( - false - ); - - expect(alertingActions.isValid('alerting_foo-ruleType/consumer/alertingType/bar-operation')).toBe( - false - ); -}); diff --git a/x-pack/packages/security/authorization_core/src/actions/alerting.ts b/x-pack/packages/security/authorization_core/src/actions/alerting.ts index 18abac73ef8b..c1de9a1c65d2 100644 --- a/x-pack/packages/security/authorization_core/src/actions/alerting.ts +++ b/x-pack/packages/security/authorization_core/src/actions/alerting.ts @@ -40,12 +40,4 @@ export class AlertingActions implements AlertingActionsType { return `${this.prefix}${ruleTypeId}/${consumer}/${alertingEntity}/${operation}`; } - - /** - * Checks if the action is a valid alerting action. - * @param action The action string to check. - */ - public isValid(action: string) { - return action.startsWith(this.prefix); - } } diff --git a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts index db4aae642a56..c5af930cce4f 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.test.ts @@ -28,7 +28,6 @@ describe(`feature_privilege_builder`, () => { read: [], }, }, - savedObject: { all: [], read: [], @@ -59,10 +58,9 @@ describe(`feature_privilege_builder`, () => { alerting: { rule: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -83,15 +81,15 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", ] `); }); @@ -104,10 +102,9 @@ describe(`feature_privilege_builder`, () => { alerting: { alert: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -128,10 +125,10 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", ] `); }); @@ -144,14 +141,13 @@ describe(`feature_privilege_builder`, () => { alerting: { rule: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, alert: { all: [], - read: ['alert-type'], + read: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -172,19 +168,19 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", ] `); }); @@ -196,7 +192,7 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, }, @@ -221,34 +217,34 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", ] `); }); @@ -260,11 +256,10 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, }, - savedObject: { all: [], read: [], @@ -285,11 +280,11 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", - "alerting:alert-type/my-feature/alert/update", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/update", ] `); }); @@ -301,15 +296,14 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, alert: { - all: ['alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], read: [], }, }, - savedObject: { all: [], read: [], @@ -330,39 +324,39 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", - "alerting:alert-type/my-feature/alert/update", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/update", ] `); }); @@ -374,11 +368,10 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], - read: ['readonly-alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, - savedObject: { all: [], read: [], @@ -399,43 +392,43 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", - "alerting:readonly-alert-type/my-feature/rule/get", - "alerting:readonly-alert-type/my-feature/rule/getRuleState", - "alerting:readonly-alert-type/my-feature/rule/getAlertSummary", - "alerting:readonly-alert-type/my-feature/rule/getExecutionLog", - "alerting:readonly-alert-type/my-feature/rule/getActionErrorLog", - "alerting:readonly-alert-type/my-feature/rule/find", - "alerting:readonly-alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:readonly-alert-type/my-feature/rule/getBackfill", - "alerting:readonly-alert-type/my-feature/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", + "alerting:readonly-alert-type/my-consumer/rule/get", + "alerting:readonly-alert-type/my-consumer/rule/getRuleState", + "alerting:readonly-alert-type/my-consumer/rule/getAlertSummary", + "alerting:readonly-alert-type/my-consumer/rule/getExecutionLog", + "alerting:readonly-alert-type/my-consumer/rule/getActionErrorLog", + "alerting:readonly-alert-type/my-consumer/rule/find", + "alerting:readonly-alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type/my-consumer/rule/getBackfill", + "alerting:readonly-alert-type/my-consumer/rule/findBackfill", ] `); }); @@ -447,8 +440,8 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { alert: { - all: ['alert-type'], - read: ['readonly-alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], }, }, @@ -472,15 +465,15 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/alert/get", - "alerting:alert-type/my-feature/alert/find", - "alerting:alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:alert-type/my-feature/alert/getAlertSummary", - "alerting:alert-type/my-feature/alert/update", - "alerting:readonly-alert-type/my-feature/alert/get", - "alerting:readonly-alert-type/my-feature/alert/find", - "alerting:readonly-alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:readonly-alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/get", + "alerting:alert-type/my-consumer/alert/find", + "alerting:alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:alert-type/my-consumer/alert/getAlertSummary", + "alerting:alert-type/my-consumer/alert/update", + "alerting:readonly-alert-type/my-consumer/alert/get", + "alerting:readonly-alert-type/my-consumer/alert/find", + "alerting:readonly-alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:readonly-alert-type/my-consumer/alert/getAlertSummary", ] `); }); @@ -492,12 +485,128 @@ describe(`feature_privilege_builder`, () => { const privilege: FeatureKibanaPrivileges = { alerting: { rule: { - all: ['alert-type'], - read: ['readonly-alert-type'], + all: [{ ruleTypeId: 'alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], + }, + alert: { + all: [{ ruleTypeId: 'another-alert-type', consumers: ['my-consumer'] }], + read: [{ ruleTypeId: 'readonly-alert-type', consumers: ['my-consumer'] }], + }, + }, + + savedObject: { + all: [], + read: [], + }, + ui: [], + }; + + const feature = new KibanaFeature({ + id: 'my-feature', + name: 'my-feature', + app: [], + category: { id: 'foo', label: 'foo' }, + privileges: { + all: privilege, + read: privilege, + }, + }); + + expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` + Array [ + "alerting:alert-type/my-consumer/rule/get", + "alerting:alert-type/my-consumer/rule/getRuleState", + "alerting:alert-type/my-consumer/rule/getAlertSummary", + "alerting:alert-type/my-consumer/rule/getExecutionLog", + "alerting:alert-type/my-consumer/rule/getActionErrorLog", + "alerting:alert-type/my-consumer/rule/find", + "alerting:alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:alert-type/my-consumer/rule/getBackfill", + "alerting:alert-type/my-consumer/rule/findBackfill", + "alerting:alert-type/my-consumer/rule/create", + "alerting:alert-type/my-consumer/rule/delete", + "alerting:alert-type/my-consumer/rule/update", + "alerting:alert-type/my-consumer/rule/updateApiKey", + "alerting:alert-type/my-consumer/rule/enable", + "alerting:alert-type/my-consumer/rule/disable", + "alerting:alert-type/my-consumer/rule/muteAll", + "alerting:alert-type/my-consumer/rule/unmuteAll", + "alerting:alert-type/my-consumer/rule/muteAlert", + "alerting:alert-type/my-consumer/rule/unmuteAlert", + "alerting:alert-type/my-consumer/rule/snooze", + "alerting:alert-type/my-consumer/rule/bulkEdit", + "alerting:alert-type/my-consumer/rule/bulkDelete", + "alerting:alert-type/my-consumer/rule/bulkEnable", + "alerting:alert-type/my-consumer/rule/bulkDisable", + "alerting:alert-type/my-consumer/rule/unsnooze", + "alerting:alert-type/my-consumer/rule/runSoon", + "alerting:alert-type/my-consumer/rule/scheduleBackfill", + "alerting:alert-type/my-consumer/rule/deleteBackfill", + "alerting:readonly-alert-type/my-consumer/rule/get", + "alerting:readonly-alert-type/my-consumer/rule/getRuleState", + "alerting:readonly-alert-type/my-consumer/rule/getAlertSummary", + "alerting:readonly-alert-type/my-consumer/rule/getExecutionLog", + "alerting:readonly-alert-type/my-consumer/rule/getActionErrorLog", + "alerting:readonly-alert-type/my-consumer/rule/find", + "alerting:readonly-alert-type/my-consumer/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type/my-consumer/rule/getBackfill", + "alerting:readonly-alert-type/my-consumer/rule/findBackfill", + "alerting:another-alert-type/my-consumer/alert/get", + "alerting:another-alert-type/my-consumer/alert/find", + "alerting:another-alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type/my-consumer/alert/getAlertSummary", + "alerting:another-alert-type/my-consumer/alert/update", + "alerting:readonly-alert-type/my-consumer/alert/get", + "alerting:readonly-alert-type/my-consumer/alert/find", + "alerting:readonly-alert-type/my-consumer/alert/getAuthorizedAlertsIndices", + "alerting:readonly-alert-type/my-consumer/alert/getAlertSummary", + ] + `); + }); + + test('handles multiple rule types and consumers correctly', () => { + const actions = new Actions(); + const alertingFeaturePrivileges = new FeaturePrivilegeAlertingBuilder(actions); + + const privilege: FeatureKibanaPrivileges = { + alerting: { + rule: { + all: [ + { ruleTypeId: 'alert-type-1', consumers: ['my-consumer-1', 'my-consumer-2'] }, + { ruleTypeId: 'alert-type-2', consumers: ['my-consumer-3'] }, + ], + read: [ + { + ruleTypeId: 'readonly-alert-type-1', + consumers: ['my-read-consumer-1', 'my-read-consumer-2'], + }, + { + ruleTypeId: 'readonly-alert-type-2', + consumers: ['my-read-consumer-3', 'my-read-consumer-4'], + }, + ], }, alert: { - all: ['another-alert-type'], - read: ['readonly-alert-type'], + all: [ + { + ruleTypeId: 'another-alert-type-1', + consumers: ['my-consumer-another-1', 'my-consumer-another-2'], + }, + { + ruleTypeId: 'another-alert-type-2', + consumers: ['my-consumer-another-3', 'my-consumer-another-1'], + }, + ], + read: [ + { + ruleTypeId: 'readonly-another-alert-type-1', + consumers: ['my-read-other-consumer-1', 'my-read-other-consumer-2'], + }, + { + ruleTypeId: 'readonly-another-alert-type-2', + consumers: ['my-read-other-consumer-3', 'my-read-other-consumer-4'], + }, + ], }, }, @@ -521,52 +630,162 @@ describe(`feature_privilege_builder`, () => { expect(alertingFeaturePrivileges.getActions(privilege, feature)).toMatchInlineSnapshot(` Array [ - "alerting:alert-type/my-feature/rule/get", - "alerting:alert-type/my-feature/rule/getRuleState", - "alerting:alert-type/my-feature/rule/getAlertSummary", - "alerting:alert-type/my-feature/rule/getExecutionLog", - "alerting:alert-type/my-feature/rule/getActionErrorLog", - "alerting:alert-type/my-feature/rule/find", - "alerting:alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:alert-type/my-feature/rule/getBackfill", - "alerting:alert-type/my-feature/rule/findBackfill", - "alerting:alert-type/my-feature/rule/create", - "alerting:alert-type/my-feature/rule/delete", - "alerting:alert-type/my-feature/rule/update", - "alerting:alert-type/my-feature/rule/updateApiKey", - "alerting:alert-type/my-feature/rule/enable", - "alerting:alert-type/my-feature/rule/disable", - "alerting:alert-type/my-feature/rule/muteAll", - "alerting:alert-type/my-feature/rule/unmuteAll", - "alerting:alert-type/my-feature/rule/muteAlert", - "alerting:alert-type/my-feature/rule/unmuteAlert", - "alerting:alert-type/my-feature/rule/snooze", - "alerting:alert-type/my-feature/rule/bulkEdit", - "alerting:alert-type/my-feature/rule/bulkDelete", - "alerting:alert-type/my-feature/rule/bulkEnable", - "alerting:alert-type/my-feature/rule/bulkDisable", - "alerting:alert-type/my-feature/rule/unsnooze", - "alerting:alert-type/my-feature/rule/runSoon", - "alerting:alert-type/my-feature/rule/scheduleBackfill", - "alerting:alert-type/my-feature/rule/deleteBackfill", - "alerting:readonly-alert-type/my-feature/rule/get", - "alerting:readonly-alert-type/my-feature/rule/getRuleState", - "alerting:readonly-alert-type/my-feature/rule/getAlertSummary", - "alerting:readonly-alert-type/my-feature/rule/getExecutionLog", - "alerting:readonly-alert-type/my-feature/rule/getActionErrorLog", - "alerting:readonly-alert-type/my-feature/rule/find", - "alerting:readonly-alert-type/my-feature/rule/getRuleExecutionKPI", - "alerting:readonly-alert-type/my-feature/rule/getBackfill", - "alerting:readonly-alert-type/my-feature/rule/findBackfill", - "alerting:another-alert-type/my-feature/alert/get", - "alerting:another-alert-type/my-feature/alert/find", - "alerting:another-alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:another-alert-type/my-feature/alert/getAlertSummary", - "alerting:another-alert-type/my-feature/alert/update", - "alerting:readonly-alert-type/my-feature/alert/get", - "alerting:readonly-alert-type/my-feature/alert/find", - "alerting:readonly-alert-type/my-feature/alert/getAuthorizedAlertsIndices", - "alerting:readonly-alert-type/my-feature/alert/getAlertSummary", + "alerting:alert-type-1/my-consumer-1/rule/get", + "alerting:alert-type-1/my-consumer-1/rule/getRuleState", + "alerting:alert-type-1/my-consumer-1/rule/getAlertSummary", + "alerting:alert-type-1/my-consumer-1/rule/getExecutionLog", + "alerting:alert-type-1/my-consumer-1/rule/getActionErrorLog", + "alerting:alert-type-1/my-consumer-1/rule/find", + "alerting:alert-type-1/my-consumer-1/rule/getRuleExecutionKPI", + "alerting:alert-type-1/my-consumer-1/rule/getBackfill", + "alerting:alert-type-1/my-consumer-1/rule/findBackfill", + "alerting:alert-type-1/my-consumer-1/rule/create", + "alerting:alert-type-1/my-consumer-1/rule/delete", + "alerting:alert-type-1/my-consumer-1/rule/update", + "alerting:alert-type-1/my-consumer-1/rule/updateApiKey", + "alerting:alert-type-1/my-consumer-1/rule/enable", + "alerting:alert-type-1/my-consumer-1/rule/disable", + "alerting:alert-type-1/my-consumer-1/rule/muteAll", + "alerting:alert-type-1/my-consumer-1/rule/unmuteAll", + "alerting:alert-type-1/my-consumer-1/rule/muteAlert", + "alerting:alert-type-1/my-consumer-1/rule/unmuteAlert", + "alerting:alert-type-1/my-consumer-1/rule/snooze", + "alerting:alert-type-1/my-consumer-1/rule/bulkEdit", + "alerting:alert-type-1/my-consumer-1/rule/bulkDelete", + "alerting:alert-type-1/my-consumer-1/rule/bulkEnable", + "alerting:alert-type-1/my-consumer-1/rule/bulkDisable", + "alerting:alert-type-1/my-consumer-1/rule/unsnooze", + "alerting:alert-type-1/my-consumer-1/rule/runSoon", + "alerting:alert-type-1/my-consumer-1/rule/scheduleBackfill", + "alerting:alert-type-1/my-consumer-1/rule/deleteBackfill", + "alerting:alert-type-1/my-consumer-2/rule/get", + "alerting:alert-type-1/my-consumer-2/rule/getRuleState", + "alerting:alert-type-1/my-consumer-2/rule/getAlertSummary", + "alerting:alert-type-1/my-consumer-2/rule/getExecutionLog", + "alerting:alert-type-1/my-consumer-2/rule/getActionErrorLog", + "alerting:alert-type-1/my-consumer-2/rule/find", + "alerting:alert-type-1/my-consumer-2/rule/getRuleExecutionKPI", + "alerting:alert-type-1/my-consumer-2/rule/getBackfill", + "alerting:alert-type-1/my-consumer-2/rule/findBackfill", + "alerting:alert-type-1/my-consumer-2/rule/create", + "alerting:alert-type-1/my-consumer-2/rule/delete", + "alerting:alert-type-1/my-consumer-2/rule/update", + "alerting:alert-type-1/my-consumer-2/rule/updateApiKey", + "alerting:alert-type-1/my-consumer-2/rule/enable", + "alerting:alert-type-1/my-consumer-2/rule/disable", + "alerting:alert-type-1/my-consumer-2/rule/muteAll", + "alerting:alert-type-1/my-consumer-2/rule/unmuteAll", + "alerting:alert-type-1/my-consumer-2/rule/muteAlert", + "alerting:alert-type-1/my-consumer-2/rule/unmuteAlert", + "alerting:alert-type-1/my-consumer-2/rule/snooze", + "alerting:alert-type-1/my-consumer-2/rule/bulkEdit", + "alerting:alert-type-1/my-consumer-2/rule/bulkDelete", + "alerting:alert-type-1/my-consumer-2/rule/bulkEnable", + "alerting:alert-type-1/my-consumer-2/rule/bulkDisable", + "alerting:alert-type-1/my-consumer-2/rule/unsnooze", + "alerting:alert-type-1/my-consumer-2/rule/runSoon", + "alerting:alert-type-1/my-consumer-2/rule/scheduleBackfill", + "alerting:alert-type-1/my-consumer-2/rule/deleteBackfill", + "alerting:alert-type-2/my-consumer-3/rule/get", + "alerting:alert-type-2/my-consumer-3/rule/getRuleState", + "alerting:alert-type-2/my-consumer-3/rule/getAlertSummary", + "alerting:alert-type-2/my-consumer-3/rule/getExecutionLog", + "alerting:alert-type-2/my-consumer-3/rule/getActionErrorLog", + "alerting:alert-type-2/my-consumer-3/rule/find", + "alerting:alert-type-2/my-consumer-3/rule/getRuleExecutionKPI", + "alerting:alert-type-2/my-consumer-3/rule/getBackfill", + "alerting:alert-type-2/my-consumer-3/rule/findBackfill", + "alerting:alert-type-2/my-consumer-3/rule/create", + "alerting:alert-type-2/my-consumer-3/rule/delete", + "alerting:alert-type-2/my-consumer-3/rule/update", + "alerting:alert-type-2/my-consumer-3/rule/updateApiKey", + "alerting:alert-type-2/my-consumer-3/rule/enable", + "alerting:alert-type-2/my-consumer-3/rule/disable", + "alerting:alert-type-2/my-consumer-3/rule/muteAll", + "alerting:alert-type-2/my-consumer-3/rule/unmuteAll", + "alerting:alert-type-2/my-consumer-3/rule/muteAlert", + "alerting:alert-type-2/my-consumer-3/rule/unmuteAlert", + "alerting:alert-type-2/my-consumer-3/rule/snooze", + "alerting:alert-type-2/my-consumer-3/rule/bulkEdit", + "alerting:alert-type-2/my-consumer-3/rule/bulkDelete", + "alerting:alert-type-2/my-consumer-3/rule/bulkEnable", + "alerting:alert-type-2/my-consumer-3/rule/bulkDisable", + "alerting:alert-type-2/my-consumer-3/rule/unsnooze", + "alerting:alert-type-2/my-consumer-3/rule/runSoon", + "alerting:alert-type-2/my-consumer-3/rule/scheduleBackfill", + "alerting:alert-type-2/my-consumer-3/rule/deleteBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/get", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getRuleState", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getAlertSummary", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getExecutionLog", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getActionErrorLog", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/find", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/getBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-1/rule/findBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/get", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getRuleState", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getAlertSummary", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getExecutionLog", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getActionErrorLog", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/find", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/getBackfill", + "alerting:readonly-alert-type-1/my-read-consumer-2/rule/findBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/get", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getRuleState", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getAlertSummary", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getExecutionLog", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getActionErrorLog", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/find", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/getBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-3/rule/findBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/get", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getRuleState", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getAlertSummary", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getExecutionLog", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getActionErrorLog", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/find", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getRuleExecutionKPI", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/getBackfill", + "alerting:readonly-alert-type-2/my-read-consumer-4/rule/findBackfill", + "alerting:another-alert-type-1/my-consumer-another-1/alert/get", + "alerting:another-alert-type-1/my-consumer-another-1/alert/find", + "alerting:another-alert-type-1/my-consumer-another-1/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-1/my-consumer-another-1/alert/getAlertSummary", + "alerting:another-alert-type-1/my-consumer-another-1/alert/update", + "alerting:another-alert-type-1/my-consumer-another-2/alert/get", + "alerting:another-alert-type-1/my-consumer-another-2/alert/find", + "alerting:another-alert-type-1/my-consumer-another-2/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-1/my-consumer-another-2/alert/getAlertSummary", + "alerting:another-alert-type-1/my-consumer-another-2/alert/update", + "alerting:another-alert-type-2/my-consumer-another-3/alert/get", + "alerting:another-alert-type-2/my-consumer-another-3/alert/find", + "alerting:another-alert-type-2/my-consumer-another-3/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-2/my-consumer-another-3/alert/getAlertSummary", + "alerting:another-alert-type-2/my-consumer-another-3/alert/update", + "alerting:another-alert-type-2/my-consumer-another-1/alert/get", + "alerting:another-alert-type-2/my-consumer-another-1/alert/find", + "alerting:another-alert-type-2/my-consumer-another-1/alert/getAuthorizedAlertsIndices", + "alerting:another-alert-type-2/my-consumer-another-1/alert/getAlertSummary", + "alerting:another-alert-type-2/my-consumer-another-1/alert/update", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/get", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/find", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-1/alert/getAlertSummary", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/get", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/find", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-1/my-read-other-consumer-2/alert/getAlertSummary", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/get", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/find", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-3/alert/getAlertSummary", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/get", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/find", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/getAuthorizedAlertsIndices", + "alerting:readonly-another-alert-type-2/my-read-other-consumer-4/alert/getAlertSummary", ] `); }); diff --git a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts index c0b7fa2ea8ab..65c330b94c46 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/feature_privilege_builder/alerting.ts @@ -7,6 +7,7 @@ import { get, uniq } from 'lodash'; +import type { AlertingKibanaPrivilege } from '@kbn/features-plugin/common/alerting_kibana_privilege'; import type { FeatureKibanaPrivileges, KibanaFeature } from '@kbn/features-plugin/server'; import { BaseFeaturePrivilegeBuilder } from './feature_privilege_builder'; @@ -67,13 +68,14 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder ): string[] { const getAlertingPrivilege = ( operations: string[], - privilegedTypes: readonly string[], - alertingEntity: string, - consumer: string + privileges: AlertingKibanaPrivilege, + alertingEntity: string ) => - privilegedTypes.flatMap((type) => - operations.map((operation) => - this.actions.alerting.get(type, consumer, alertingEntity, operation) + privileges.flatMap(({ ruleTypeId, consumers }) => + consumers.flatMap((consumer) => + operations.map((operation) => + this.actions.alerting.get(ruleTypeId, consumer, alertingEntity, operation) + ) ) ); @@ -82,8 +84,8 @@ export class FeaturePrivilegeAlertingBuilder extends BaseFeaturePrivilegeBuilder const read = get(privilegeDefinition.alerting, `${entity}.read`) ?? []; return uniq([ - ...getAlertingPrivilege(allOperations[entity], all, entity, feature.id), - ...getAlertingPrivilege(readOperations[entity], read, entity, feature.id), + ...getAlertingPrivilege(allOperations[entity], all, entity), + ...getAlertingPrivilege(readOperations[entity], read, entity), ]); }; diff --git a/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts b/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts index 6af21d5357a7..22fb86f601b3 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/privileges.test.ts @@ -481,7 +481,7 @@ describe('features', () => { name: 'Feature Alpha', app: [], category: { id: 'alpha', label: 'alpha' }, - alerting: ['rule-type-1'], + alerting: [{ ruleTypeId: 'rule-type-1', consumers: ['alpha'] }], privileges: { all: { savedObject: { @@ -491,7 +491,7 @@ describe('features', () => { ui: ['all-alpha-ui'], app: ['all-alpha-app'], api: ['all-alpha-api'], - alerting: { rule: { all: ['rule-type-1'] } }, + alerting: { rule: { all: [{ ruleTypeId: 'rule-type-1', consumers: ['alpha'] }] } }, replacedBy: [{ feature: 'beta', privileges: ['all'] }], }, read: { @@ -514,7 +514,7 @@ describe('features', () => { name: 'Feature Beta', app: [], category: { id: 'beta', label: 'beta' }, - alerting: ['rule-type-1'], + alerting: [{ ruleTypeId: 'rule-type-1', consumers: ['beta'] }], privileges: { all: { savedObject: { @@ -524,7 +524,7 @@ describe('features', () => { ui: ['all-beta-ui'], app: ['all-beta-app'], api: ['all-beta-api'], - alerting: { rule: { all: ['rule-type-1'] } }, + alerting: { rule: { all: [{ ruleTypeId: 'rule-type-1', consumers: ['beta'] }] } }, }, read: { savedObject: { @@ -604,13 +604,8 @@ describe('features', () => { ...alertingOperations.map((operation) => actions.alerting.get('rule-type-1', 'alpha', 'rule', operation) ), - // To maintain compatibility with the new UI capabilities and new alerting entities that are - // feature specific: all.replacedBy: [{ feature: 'beta', privileges: ['all'] }] actions.ui.get('navLinks', 'all-beta-app'), actions.ui.get('beta', 'all-beta-ui'), - ...alertingOperations.map((operation) => - actions.alerting.get('rule-type-1', 'beta', 'rule', operation) - ), ]; const expectedReadPrivileges = [ diff --git a/x-pack/packages/security/authorization_core/src/privileges/privileges.ts b/x-pack/packages/security/authorization_core/src/privileges/privileges.ts index b81eaba5fa54..f266b2b9a708 100644 --- a/x-pack/packages/security/authorization_core/src/privileges/privileges.ts +++ b/x-pack/packages/security/authorization_core/src/privileges/privileges.ts @@ -94,17 +94,15 @@ export function privilegesFactory( // If a privilege is configured with `replacedBy`, it's part of the deprecated feature and // should be complemented with the subset of actions from the referenced privileges to // maintain backward compatibility. Namely, deprecated privileges should grant the same UI - // capabilities and alerting actions as the privileges that replace them, so that the - // client-side code can safely use only non-deprecated UI capabilities and users can still - // access previously created alerting rules and alerts. + // capabilities as the privileges that replace them, so that the client-side code can safely + // use only non-deprecated UI capabilities. const replacedBy = getReplacedByForPrivilege(privilegeId, privilege); if (replacedBy) { composablePrivileges.push({ featureId: feature.id, privilegeId, references: replacedBy, - actionsFilter: (action) => - actions.ui.isValid(action) || actions.alerting.isValid(action), + actionsFilter: (action) => actions.ui.isValid(action), }); } }; diff --git a/x-pack/packages/security/form_components/src/form_changes.test.tsx b/x-pack/packages/security/form_components/src/form_changes.test.tsx index 3223bb727ddf..1ce5e4d1e07d 100644 --- a/x-pack/packages/security/form_components/src/form_changes.test.tsx +++ b/x-pack/packages/security/form_components/src/form_changes.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import type { RevertFunction } from './form_changes'; import { useFormChanges } from './form_changes'; diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts b/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts index 433e3850cae2..9834765487a8 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.mock.ts @@ -22,7 +22,6 @@ const createActionsClientMock = () => { getBulk: jest.fn(), getOAuthAccessToken: jest.fn(), execute: jest.fn(), - ephemeralEnqueuedExecution: jest.fn(), bulkEnqueueExecution: jest.fn(), listTypes: jest.fn(), isActionTypeEnabled: jest.fn(), diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts index 99bcbf15ecfb..b977f8fb97cd 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.test.ts @@ -79,7 +79,6 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); const actionExecutor = actionExecutorMock.create(); const authorization = actionsAuthorizationMock.create(); -const ephemeralExecutionEnqueuer = jest.fn(); const bulkExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditLoggerMock.create(); @@ -138,7 +137,6 @@ beforeEach(() => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -613,7 +611,6 @@ describe('create()', () => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -739,7 +736,6 @@ describe('create()', () => { ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -801,7 +797,6 @@ describe('create()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -862,7 +857,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -899,7 +893,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -956,7 +949,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -999,7 +991,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1121,7 +1112,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1165,7 +1155,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1199,7 +1188,6 @@ describe('get()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1270,7 +1258,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1408,7 +1395,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1503,7 +1489,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1577,7 +1562,6 @@ describe('getBulk()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -1662,7 +1646,6 @@ describe('getOAuthAccessToken()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2097,7 +2080,6 @@ describe('delete()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2133,7 +2115,6 @@ describe('delete()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2653,7 +2634,6 @@ describe('update()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2696,7 +2676,6 @@ describe('update()', () => { }, ], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2782,7 +2761,6 @@ describe('execute()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2845,7 +2823,6 @@ describe('execute()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -2907,7 +2884,6 @@ describe('execute()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3180,7 +3156,6 @@ describe('isPreconfigured()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3230,7 +3205,6 @@ describe('isPreconfigured()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3282,7 +3256,6 @@ describe('isSystemAction()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -3332,7 +3305,6 @@ describe('isSystemAction()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/actions_client/actions_client.ts b/x-pack/plugins/actions/server/actions_client/actions_client.ts index 5c563fbd6aa8..e39cf8712894 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client.ts @@ -18,7 +18,6 @@ import { Logger, } from '@kbn/core/server'; import { AuditLogger } from '@kbn/security-plugin/server'; -import { RunNowResult } from '@kbn/task-manager-plugin/server'; import { IEventLogClient } from '@kbn/event-log-plugin/server'; import { KueryNode } from '@kbn/es-query'; import { Connector, ConnectorWithExtraFindData } from '../application/connector/types'; @@ -46,7 +45,6 @@ import { } from '../types'; import { PreconfiguredActionDisabledModificationError } from '../lib/errors/preconfigured_action_disabled_modification'; import { - ExecutionEnqueuer, ExecuteOptions as EnqueueExecutionOptions, BulkExecutionEnqueuer, ExecutionResponse, @@ -92,7 +90,6 @@ export interface ConstructorOptions { unsecuredSavedObjectsClient: SavedObjectsClientContract; inMemoryConnectors: InMemoryConnector[]; actionExecutor: ActionExecutorContract; - ephemeralExecutionEnqueuer: ExecutionEnqueuer; bulkExecutionEnqueuer: BulkExecutionEnqueuer; request: KibanaRequest; authorization: ActionsAuthorization; @@ -112,7 +109,6 @@ export interface ActionsClientContext { actionExecutor: ActionExecutorContract; request: KibanaRequest; authorization: ActionsAuthorization; - ephemeralExecutionEnqueuer: ExecutionEnqueuer; bulkExecutionEnqueuer: BulkExecutionEnqueuer; auditLogger?: AuditLogger; usageCounter?: UsageCounter; @@ -131,7 +127,6 @@ export class ActionsClient { unsecuredSavedObjectsClient, inMemoryConnectors, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization, @@ -148,7 +143,6 @@ export class ActionsClient { kibanaIndices, inMemoryConnectors, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization, @@ -504,18 +498,6 @@ export class ActionsClient { return this.context.bulkExecutionEnqueuer(this.context.unsecuredSavedObjectsClient, options); } - public async ephemeralEnqueuedExecution(options: EnqueueExecutionOptions): Promise { - await this.context.authorization.ensureAuthorized({ - operation: 'execute', - actionTypeId: options.actionTypeId, - }); - - return this.context.ephemeralExecutionEnqueuer( - this.context.unsecuredSavedObjectsClient, - options - ); - } - public async listTypes({ featureId, includeSystemActionTypes = false, diff --git a/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts b/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts index 7a1a0fb5e3d9..303254a66ea1 100644 --- a/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts +++ b/x-pack/plugins/actions/server/actions_client/actions_client_hooks.test.ts @@ -38,7 +38,6 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); const actionExecutor = actionExecutorMock.create(); const authorization = actionsAuthorizationMock.create(); -const ephemeralExecutionEnqueuer = jest.fn(); const bulkExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditLoggerMock.create(); @@ -131,7 +130,6 @@ beforeEach(() => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts index 0f86a8e582e3..5ff37776cf2d 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/get_all/get_all.test.ts @@ -52,7 +52,6 @@ const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); const scopedClusterClient = elasticsearchServiceMock.createScopedClusterClient(); const actionExecutor = actionExecutorMock.create(); const authorization = actionsAuthorizationMock.create(); -const ephemeralExecutionEnqueuer = jest.fn(); const bulkExecutionEnqueuer = jest.fn(); const request = httpServerMock.createKibanaRequest(); const auditLogger = auditLoggerMock.create(); @@ -78,7 +77,6 @@ describe('getAll()', () => { kibanaIndices, inMemoryConnectors: [], actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -134,7 +132,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -279,7 +276,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -382,7 +378,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -487,7 +482,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -579,7 +573,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -613,7 +606,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, @@ -690,7 +682,6 @@ describe('getAll()', () => { scopedClusterClient, kibanaIndices, actionExecutor, - ephemeralExecutionEnqueuer, bulkExecutionEnqueuer, request, authorization: authorization as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts b/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts index 9ff5e05d4550..056d535ce438 100644 --- a/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts +++ b/x-pack/plugins/actions/server/application/connector/methods/list_types/list_types.test.ts @@ -60,7 +60,6 @@ describe('listTypes()', () => { unsecuredSavedObjectsClient: savedObjectsClientMock.create(), inMemoryConnectors: [], actionExecutor: actionExecutorMock.create(), - ephemeralExecutionEnqueuer: jest.fn(), bulkExecutionEnqueuer: jest.fn(), request: httpServerMock.createKibanaRequest(), authorization: actionsAuthorizationMock.create() as unknown as ActionsAuthorization, diff --git a/x-pack/plugins/actions/server/create_execute_function.ts b/x-pack/plugins/actions/server/create_execute_function.ts index a92bff971955..539ada46a094 100644 --- a/x-pack/plugins/actions/server/create_execute_function.ts +++ b/x-pack/plugins/actions/server/create_execute_function.ts @@ -6,13 +6,8 @@ */ import { SavedObjectsBulkResponse, SavedObjectsClientContract, Logger } from '@kbn/core/server'; -import { RunNowResult, TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; -import { - RawAction, - ActionTypeRegistryContract, - InMemoryConnector, - ActionTaskExecutorParams, -} from './types'; +import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; +import { RawAction, ActionTypeRegistryContract, InMemoryConnector } from './types'; import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from './constants/saved_objects'; import { ExecuteOptions as ActionExecutorOptions } from './lib/action_executor'; import { extractSavedObjectReferences, isSavedObjectExecutionSource } from './lib'; @@ -215,43 +210,6 @@ export function createBulkExecutionEnqueuerFunction({ }; } -export function createEphemeralExecutionEnqueuerFunction({ - taskManager, - actionTypeRegistry, - inMemoryConnectors, - logger, -}: CreateExecuteFunctionOptions): ExecutionEnqueuer { - return async function execute( - unsecuredSavedObjectsClient: SavedObjectsClientContract, - { id, params, spaceId, source, consumer, apiKey, executionId }: ExecuteOptions - ): Promise { - const { connector } = await getConnector(unsecuredSavedObjectsClient, inMemoryConnectors, id); - - validateConnector({ id, connector, actionTypeRegistry }); - - const taskParams: ActionTaskExecutorParams = { - spaceId, - taskParams: { - actionId: id, - consumer, - // Saved Objects won't allow us to enforce unknown rather than any - // eslint-disable-next-line @typescript-eslint/no-explicit-any - params: params as Record, - ...(apiKey ? { apiKey } : {}), - ...(executionId ? { executionId } : {}), - }, - ...executionSourceAsSavedObjectReferences(source), - }; - - return taskManager.ephemeralRunNow({ - taskType: `actions:${connector.actionTypeId}`, - params: taskParams, - state: {}, - scope: ['actions'], - }); - }; -} - function validateConnector({ id, connector, @@ -287,21 +245,6 @@ function executionSourceAsSavedObjectReferences(executionSource: ActionExecutorO : {}; } -async function getConnector( - unsecuredSavedObjectsClient: SavedObjectsClientContract, - inMemoryConnectors: InMemoryConnector[], - actionId: string -): Promise<{ connector: InMemoryConnector | RawAction; isInMemory: boolean }> { - const inMemoryAction = inMemoryConnectors.find((action) => action.id === actionId); - - if (inMemoryAction) { - return { connector: inMemoryAction, isInMemory: true }; - } - - const { attributes } = await unsecuredSavedObjectsClient.get('action', actionId); - return { connector: attributes, isInMemory: false }; -} - async function getConnectors( unsecuredSavedObjectsClient: SavedObjectsClientContract, inMemoryConnectors: InMemoryConnector[], diff --git a/x-pack/plugins/actions/server/lib/action_executor.ts b/x-pack/plugins/actions/server/lib/action_executor.ts index b0f9db0ef700..799fdb80f39a 100644 --- a/x-pack/plugins/actions/server/lib/action_executor.ts +++ b/x-pack/plugins/actions/server/lib/action_executor.ts @@ -82,7 +82,6 @@ export interface ExecuteOptions { actionId: string; consumer?: string; executionId?: string; - isEphemeral?: boolean; params: Record; relatedSavedObjects?: RelatedSavedObjects; request: KibanaRequest; @@ -133,7 +132,6 @@ export class ActionExecutor { actionId, consumer, executionId, - isEphemeral, request, params, relatedSavedObjects, @@ -175,7 +173,6 @@ export class ActionExecutor { }, executeLabel: `execute_action`, executionId, - isEphemeral, namespace, params, relatedSavedObjects, @@ -367,7 +364,6 @@ export class ActionExecutor { checkCanExecuteFn, executeLabel, executionId, - isEphemeral, namespace, params, relatedSavedObjects, @@ -512,7 +508,6 @@ export class ActionExecutor { params: validatedParams, config: validatedConfig, secrets: validatedSecrets, - isEphemeral, taskInfo, configurationUtilities, logger, diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts index 9733b56638d7..0dc2b2f3f5c9 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.test.ts @@ -35,7 +35,6 @@ import { SavedObjectsErrorHelpers } from '@kbn/core-saved-objects-server'; const executeParamsFields = [ 'actionId', - 'isEphemeral', 'params', 'relatedSavedObjects', 'executionId', @@ -173,7 +172,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -233,7 +231,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '9', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [], @@ -289,7 +286,6 @@ describe('Task Runner Factory', () => { expect(pick(executeParams, [...executeParamsFields, 'consumer'])).toEqual({ actionId: '2', consumer: 'test-consumer', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -346,7 +342,6 @@ describe('Task Runner Factory', () => { expect(pick(executeParams, [...executeParamsFields, 'consumer'])).toEqual({ actionId: '2', consumer: 'test-consumer', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -407,7 +402,6 @@ describe('Task Runner Factory', () => { expect(pick(executeParams, [...executeParamsFields, 'consumer'])).toEqual({ actionId: '2', consumer: 'test-consumer', - isEphemeral: false, params: { baz: true }, relatedSavedObjects: [], executionId: '123abc', @@ -569,7 +563,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [], @@ -627,7 +620,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [ @@ -680,7 +672,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [ @@ -739,7 +730,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, request: { headers: { @@ -785,7 +775,6 @@ describe('Task Runner Factory', () => { const [executeParams] = mockedActionExecutor.execute.mock.calls[0]; expect(pick(executeParams, executeParamsFields)).toEqual({ actionId: '2', - isEphemeral: false, params: { baz: true }, executionId: '123abc', relatedSavedObjects: [], diff --git a/x-pack/plugins/actions/server/lib/task_runner_factory.ts b/x-pack/plugins/actions/server/lib/task_runner_factory.ts index cf1f9eed87c3..b718a32a2e4a 100644 --- a/x-pack/plugins/actions/server/lib/task_runner_factory.ts +++ b/x-pack/plugins/actions/server/lib/task_runner_factory.ts @@ -32,7 +32,6 @@ import { ActionTaskParams, ActionTypeExecutorResult, ActionTypeRegistryContract, - isPersistedActionTask, SpaceIdToNamespaceFunction, } from '../types'; import { ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE } from '../constants/saved_objects'; @@ -128,7 +127,6 @@ export class TaskRunnerFactory { executorResult = await actionExecutor.execute({ params, actionId: actionId as string, - isEphemeral: !isPersistedActionTask(actionTaskExecutorParams), request, taskInfo, executionId, @@ -209,19 +207,17 @@ export class TaskRunnerFactory { }, cleanup: async () => { // Cleanup action_task_params object now that we're done with it - if (isPersistedActionTask(actionTaskExecutorParams)) { - try { - await savedObjectsRepository.delete( - ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, - actionTaskExecutorParams.actionTaskParamsId, - { refresh: false, namespace: spaceIdToNamespace(actionTaskExecutorParams.spaceId) } - ); - } catch (e) { - // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) - logger.error( - `Failed to cleanup ${ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE} object [id="${actionTaskExecutorParams.actionTaskParamsId}"]: ${e.message}` - ); - } + try { + await savedObjectsRepository.delete( + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + actionTaskExecutorParams.actionTaskParamsId, + { refresh: false, namespace: spaceIdToNamespace(actionTaskExecutorParams.spaceId) } + ); + } catch (e) { + // Log error only, we shouldn't fail the task because of an error here (if ever there's retry logic) + logger.error( + `Failed to cleanup ${ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE} object [id="${actionTaskExecutorParams.actionTaskParamsId}"]: ${e.message}` + ); } }, }; @@ -252,45 +248,41 @@ async function getActionTaskParams( ): Promise { const { spaceId } = executorParams; const namespace = spaceIdToNamespace(spaceId); - if (isPersistedActionTask(executorParams)) { - try { - const actionTask = - await encryptedSavedObjectsClient.getDecryptedAsInternalUser( - ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, - executorParams.actionTaskParamsId, - { namespace } - ); - const { - attributes: { relatedSavedObjects }, - references, - } = actionTask; + try { + const actionTask = + await encryptedSavedObjectsClient.getDecryptedAsInternalUser( + ACTION_TASK_PARAMS_SAVED_OBJECT_TYPE, + executorParams.actionTaskParamsId, + { namespace } + ); + const { + attributes: { relatedSavedObjects }, + references, + } = actionTask; - const { actionId, relatedSavedObjects: injectedRelatedSavedObjects } = - injectSavedObjectReferences(references, relatedSavedObjects as RelatedSavedObjects); + const { actionId, relatedSavedObjects: injectedRelatedSavedObjects } = + injectSavedObjectReferences(references, relatedSavedObjects as RelatedSavedObjects); - return { - ...actionTask, - attributes: { - ...actionTask.attributes, - ...(actionId ? { actionId } : {}), - ...(relatedSavedObjects ? { relatedSavedObjects: injectedRelatedSavedObjects } : {}), - }, - }; - } catch (e) { - const errorSource = SavedObjectsErrorHelpers.isNotFoundError(e) - ? TaskErrorSource.USER - : TaskErrorSource.FRAMEWORK; - logger.error( - `Failed to load action task params ${executorParams.actionTaskParamsId}: ${e.message}`, - { tags: ['connector-run-failed', `${errorSource}-error`] } - ); - if (SavedObjectsErrorHelpers.isNotFoundError(e)) { - throw createRetryableError(createTaskRunError(e, errorSource), true); - } + return { + ...actionTask, + attributes: { + ...actionTask.attributes, + ...(actionId ? { actionId } : {}), + ...(relatedSavedObjects ? { relatedSavedObjects: injectedRelatedSavedObjects } : {}), + }, + }; + } catch (e) { + const errorSource = SavedObjectsErrorHelpers.isNotFoundError(e) + ? TaskErrorSource.USER + : TaskErrorSource.FRAMEWORK; + logger.error( + `Failed to load action task params ${executorParams.actionTaskParamsId}: ${e.message}`, + { tags: ['connector-run-failed', `${errorSource}-error`] } + ); + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { throw createRetryableError(createTaskRunError(e, errorSource), true); } - } else { - return { attributes: executorParams.taskParams, references: executorParams.references ?? [] }; + throw createRetryableError(createTaskRunError(e, errorSource), true); } } diff --git a/x-pack/plugins/actions/server/plugin.ts b/x-pack/plugins/actions/server/plugin.ts index 57304c176c13..012f602398e6 100644 --- a/x-pack/plugins/actions/server/plugin.ts +++ b/x-pack/plugins/actions/server/plugin.ts @@ -48,10 +48,7 @@ import { resolveCustomHosts } from './lib/custom_host_settings'; import { events } from './lib/event_based_telemetry'; import { ActionsClient } from './actions_client/actions_client'; import { ActionTypeRegistry } from './action_type_registry'; -import { - createEphemeralExecutionEnqueuerFunction, - createBulkExecutionEnqueuerFunction, -} from './create_execute_function'; +import { createBulkExecutionEnqueuerFunction } from './create_execute_function'; import { registerActionsUsageCollector } from './usage'; import { ActionExecutor, @@ -140,6 +137,7 @@ export interface PluginSetupContract { getActionsHealth: () => { hasPermanentEncryptionKey: boolean }; getActionsConfigurationUtilities: () => ActionsConfigurationUtilities; setEnabledConnectorTypes: (connectorTypes: EnabledConnectorTypes) => void; + isActionTypeEnabled(id: string, options?: { notifyUsage: boolean }): boolean; } @@ -168,6 +166,7 @@ export interface PluginStartContract { params: Params, variables: Record ): Params; + isSystemActionConnector: (connectorId: string) => boolean; } @@ -478,14 +477,6 @@ export class ActionsPlugin implements Plugin; @@ -238,27 +236,11 @@ export interface ActionTaskParams extends SavedObjectAttributes { source?: string; } -interface PersistedActionTaskExecutorParams { +export interface ActionTaskExecutorParams { spaceId: string; actionTaskParamsId: string; } -interface EphemeralActionTaskExecutorParams { - spaceId: string; - taskParams: ActionTaskParams; - references?: SavedObjectReference[]; -} - -export type ActionTaskExecutorParams = - | PersistedActionTaskExecutorParams - | EphemeralActionTaskExecutorParams; - -export function isPersistedActionTask( - actionTask: ActionTaskExecutorParams -): actionTask is PersistedActionTaskExecutorParams { - return typeof (actionTask as PersistedActionTaskExecutorParams).actionTaskParamsId === 'string'; -} - export interface ProxySettings { proxyUrl: string; proxyBypassHosts: Set | undefined; diff --git a/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts index 77dec7f15e15..2c09576cc2a2 100644 --- a/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts +++ b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.test.ts @@ -230,10 +230,11 @@ describe('ConnectorUsageReportingTask', () => { const response = await taskRunner.run(); expect(logger.warn).toHaveBeenCalledWith( - 'Missing required project id while running actions:connector_usage_reporting' + 'Missing required project id while running actions:connector_usage_reporting, reporting task will be deleted' ); expect(response).toEqual({ + shouldDeleteTask: true, state: { attempts: 0, lastReportedUsageDate, @@ -391,4 +392,27 @@ describe('ConnectorUsageReportingTask', () => { 'Usage data could not be pushed to usage-api. Stopped retrying after 5 attempts. Error:test-error' ); }); + + it('does not schedule the task when the project id is missing', async () => { + const core = createSetup(); + const taskManagerStart = taskManagerStartMock(); + + const task = new ConnectorUsageReportingTask({ + eventLogIndex: 'test-index', + projectId: undefined, + logger, + core, + taskManager: mockTaskManagerSetup, + config: { + url: 'usage-api', + ca: { + path: './ca.crt', + }, + }, + }); + + await task.start(taskManagerStart); + + expect(taskManagerStart.ensureScheduled).not.toBeCalled(); + }); }); diff --git a/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts index ce4471874900..ddaa930b15c3 100644 --- a/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts +++ b/x-pack/plugins/actions/server/usage/connector_usage_reporting_task.ts @@ -82,6 +82,9 @@ export class ConnectorUsageReportingTask { } public start = async (taskManager?: TaskManagerStartContract) => { + if (!this.projectId) { + return; + } if (!taskManager) { this.logger.error( `Missing required task manager service during start of ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}` @@ -111,10 +114,11 @@ export class ConnectorUsageReportingTask { if (!this.projectId) { this.logger.warn( - `Missing required project id while running ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}` + `Missing required project id while running ${CONNECTOR_USAGE_REPORTING_TASK_TYPE}, reporting task will be deleted` ); return { state, + shouldDeleteTask: true, }; } diff --git a/x-pack/plugins/ai_infra/product_doc_base/server/routes/installation.ts b/x-pack/plugins/ai_infra/product_doc_base/server/routes/installation.ts index dbede9f7d94d..1e6b5545ebb4 100644 --- a/x-pack/plugins/ai_infra/product_doc_base/server/routes/installation.ts +++ b/x-pack/plugins/ai_infra/product_doc_base/server/routes/installation.ts @@ -29,10 +29,10 @@ export const registerInstallationRoutes = ({ validate: false, options: { access: 'internal', - security: { - authz: { - requiredPrivileges: ['manage_llm_product_doc'], - }, + }, + security: { + authz: { + requiredPrivileges: ['manage_llm_product_doc'], }, }, }, @@ -56,13 +56,13 @@ export const registerInstallationRoutes = ({ validate: false, options: { access: 'internal', - security: { - authz: { - requiredPrivileges: ['manage_llm_product_doc'], - }, - }, timeout: { idleSocket: 20 * 60 * 1000 }, // install can take time. }, + security: { + authz: { + requiredPrivileges: ['manage_llm_product_doc'], + }, + }, }, async (ctx, req, res) => { const { documentationManager } = getServices(); @@ -90,10 +90,10 @@ export const registerInstallationRoutes = ({ validate: false, options: { access: 'internal', - security: { - authz: { - requiredPrivileges: ['manage_llm_product_doc'], - }, + }, + security: { + authz: { + requiredPrivileges: ['manage_llm_product_doc'], }, }, }, diff --git a/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts b/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts index 0e92d765a3d1..c4ad3c43ce07 100644 --- a/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts +++ b/x-pack/plugins/ai_infra/product_doc_base/server/services/inference_endpoint/utils/install_elser.ts @@ -23,7 +23,7 @@ export const installElser = async ({ inference_config: { service: 'elasticsearch', service_settings: { - num_allocations: 1, + adaptive_allocations: { enabled: true }, num_threads: 1, model_id: '.elser_model_2', }, diff --git a/x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx b/x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx new file mode 100644 index 000000000000..d3d74d391308 --- /dev/null +++ b/x-pack/plugins/aiops/public/cases/log_rate_analysis_attachment.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { memoize } from 'lodash'; +import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import type { PersistableStateAttachmentViewProps } from '@kbn/cases-plugin/public/client/attachment_framework/types'; +import { FIELD_FORMAT_IDS } from '@kbn/field-formats-plugin/common'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiDescriptionList } from '@elastic/eui'; +import type { + LogRateAnalysisEmbeddableWrapper, + LogRateAnalysisEmbeddableWrapperProps, +} from '../shared_components/log_rate_analysis_embeddable_wrapper'; + +export const initComponent = memoize( + (fieldFormats: FieldFormatsStart, LogRateAnalysisComponent: LogRateAnalysisEmbeddableWrapper) => { + return React.memo((props: PersistableStateAttachmentViewProps) => { + const { persistableStateAttachmentState } = props; + const dataFormatter = fieldFormats.deserialize({ + id: FIELD_FORMAT_IDS.DATE, + }); + const inputProps = + persistableStateAttachmentState as unknown as LogRateAnalysisEmbeddableWrapperProps; + + const listItems = [ + { + title: ( + + ), + description: `${dataFormatter.convert( + inputProps.timeRange.from + )} - ${dataFormatter.convert(inputProps.timeRange.to)}`, + }, + ]; + + return ( + <> + + + + ); + }); + } +); diff --git a/x-pack/plugins/aiops/public/cases/register_cases.tsx b/x-pack/plugins/aiops/public/cases/register_cases.tsx index b3b6efaf16d2..b98aca16fee7 100644 --- a/x-pack/plugins/aiops/public/cases/register_cases.tsx +++ b/x-pack/plugins/aiops/public/cases/register_cases.tsx @@ -12,8 +12,10 @@ import type { CasesPublicSetup } from '@kbn/cases-plugin/public'; import type { CoreStart } from '@kbn/core/public'; import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '@kbn/aiops-change-point-detection/constants'; import { CASES_ATTACHMENT_LOG_PATTERN } from '@kbn/aiops-log-pattern-analysis/constants'; +import { CASES_ATTACHMENT_LOG_RATE_ANALYSIS } from '@kbn/aiops-log-rate-analysis/constants'; import { getChangePointDetectionComponent, + getLogRateAnalysisEmbeddableWrapperComponent, getPatternAnalysisComponent, } from '../shared_components'; import type { AiopsPluginStartDeps } from '../types'; @@ -47,6 +49,14 @@ export function registerCases( }; }), }), + getAttachmentRemovalObject: () => ({ + event: ( + + ), + }), }); const LogPatternAttachmentComponent = getPatternAnalysisComponent(coreStart, pluginStart); @@ -71,5 +81,53 @@ export function registerCases( return { default: initComponent(pluginStart.fieldFormats, LogPatternAttachmentComponent) }; }), }), + getAttachmentRemovalObject: () => ({ + event: ( + + ), + }), + }); + + const LogRateAnalysisEmbeddableWrapperComponent = getLogRateAnalysisEmbeddableWrapperComponent( + coreStart, + pluginStart + ); + + cases.attachmentFramework.registerPersistableState({ + id: CASES_ATTACHMENT_LOG_RATE_ANALYSIS, + icon: 'machineLearningApp', + displayName: i18n.translate('xpack.aiops.logRateAnalysis.cases.attachmentName', { + defaultMessage: 'Log rate analysis', + }), + getAttachmentViewObject: () => ({ + event: ( + + ), + timelineAvatar: 'machineLearningApp', + children: React.lazy(async () => { + const { initComponent } = await import('./log_rate_analysis_attachment'); + + return { + default: initComponent( + pluginStart.fieldFormats, + LogRateAnalysisEmbeddableWrapperComponent + ), + }; + }), + }), + getAttachmentRemovalObject: () => ({ + event: ( + + ), + }), }); } diff --git a/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx b/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx index 9f4f6f1deb5b..b56493cf03bd 100644 --- a/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx +++ b/x-pack/plugins/aiops/public/components/document_count_content/document_count_content/document_count_content.tsx @@ -45,19 +45,25 @@ export const DocumentCountContent: FC = ({ const { documentStats } = useAppSelector((s) => s.logRateAnalysis); const { sampleProbability, totalCount, documentCountStats } = documentStats; + const isCasesEmbedding = embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.CASES; + + const isEmbeddedInDashboardOrCases = + embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD || isCasesEmbedding; + if (documentCountStats === undefined) { - return totalCount !== undefined && embeddingOrigin !== AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD ? ( + return totalCount !== undefined && !isEmbeddedInDashboardOrCases ? ( ) : null; } - if (embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD) { + if (isEmbeddedInDashboardOrCases) { return ( ); diff --git a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx index 5bf415c5ccfc..f4c25eafa5da 100644 --- a/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx +++ b/x-pack/plugins/aiops/public/components/log_categorization/log_categorization_for_embeddable/log_categorization_for_discover.tsx @@ -401,9 +401,6 @@ export const LogCategorizationDiscover: FC = ( ); const style = css({ overflowY: 'auto', - '.kbnDocTableWrapper': { - overflowX: 'hidden', - }, }); const actions = getActions(false); diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx index 89a8c9aee19a..0c0880ec3987 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_app_state.tsx @@ -25,6 +25,7 @@ import { AIOPS_STORAGE_KEYS } from '../../types/storage'; import { LogRateAnalysisPage } from './log_rate_analysis_page'; import { timeSeriesDataViewWarning } from '../../application/utils/time_series_dataview_check'; +import { FilterQueryContextProvider } from '../../hooks/use_filters_query'; const localStorage = new Storage(window.localStorage); @@ -58,6 +59,8 @@ export const LogRateAnalysisAppState: FC = ({ if (warning !== null) { return <>{warning}; } + const CasesContext = appContextValue.cases?.ui.getCasesContext() ?? React.Fragment; + const casesPermissions = appContextValue.cases?.helpers.canUseCases(); const datePickerDeps: DatePickerDependencies = { ...pick(appContextValue, ['data', 'http', 'notifications', 'theme', 'uiSettings', 'i18n']), @@ -67,17 +70,21 @@ export const LogRateAnalysisAppState: FC = ({ return ( - - - - - - - - - - - + + + + + + + + + + + + + + + ); }; diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx index c8c9bad1568a..d7e68ae42799 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_attachments_menu.tsx @@ -26,15 +26,29 @@ import { EuiSpacer, EuiSwitch, } from '@elastic/eui'; +import type { WindowParameters } from '@kbn/aiops-log-rate-analysis/window_parameters'; +import type { SignificantItem } from '@kbn/ml-agg-utils'; +import { useCasesModal } from '../../../hooks/use_cases_modal'; import { useDataSource } from '../../../hooks/use_data_source'; import type { LogRateAnalysisEmbeddableState } from '../../../embeddables/log_rate_analysis/types'; import { useAiopsAppContext } from '../../../hooks/use_aiops_app_context'; const SavedObjectSaveModalDashboard = withSuspense(LazySavedObjectSaveModalDashboard); -export const LogRateAnalysisAttachmentsMenu = () => { +interface LogRateAnalysisAttachmentsMenuProps { + windowParameters?: WindowParameters; + showLogRateAnalysisResults: boolean; + significantItems: SignificantItem[]; +} + +export const LogRateAnalysisAttachmentsMenu = ({ + windowParameters, + showLogRateAnalysisResults, + significantItems, +}: LogRateAnalysisAttachmentsMenuProps) => { const { application: { capabilities }, + cases, embeddable, } = useAiopsAppContext(); const { dataView } = useDataSource(); @@ -44,9 +58,19 @@ export const LogRateAnalysisAttachmentsMenu = () => { const [dashboardAttachmentReady, setDashboardAttachmentReady] = useState(false); const timeRange = useTimeRangeUpdates(); + const absoluteTimeRange = useTimeRangeUpdates(true); + + const openCasesModalCallback = useCasesModal(EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE); const canEditDashboards = capabilities.dashboard.createNew; + const { create: canCreateCase, update: canUpdateCase } = cases?.helpers?.canUseCases() ?? { + create: false, + update: false, + }; + + const isCasesAttachmentEnabled = showLogRateAnalysisResults && significantItems.length > 0; + const onSave: SaveModalDashboardProps['onSave'] = useCallback( ({ dashboardId, newTitle, newDescription }) => { const stateTransfer = embeddable!.getStateTransfer(); @@ -71,6 +95,19 @@ export const LogRateAnalysisAttachmentsMenu = () => { [dataView.id, embeddable, applyTimeRange, timeRange] ); + const caseAttachmentTooltipContent = useMemo(() => { + if (!showLogRateAnalysisResults) { + return i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseTooltipNoAnalysis', { + defaultMessage: 'Run the analysis first to add results to a case.', + }); + } + if (significantItems.length === 0) { + return i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseTooltipNoResults', { + defaultMessage: 'Cannot add to case because the analysis did not produce any results.', + }); + } + }, [showLogRateAnalysisResults, significantItems.length]); + const panels = useMemo>(() => { return [ { @@ -88,6 +125,31 @@ export const LogRateAnalysisAttachmentsMenu = () => { }, ] : []), + ...(canUpdateCase || canCreateCase + ? [ + { + name: i18n.translate('xpack.aiops.logRateAnalysis.attachToCaseLabel', { + defaultMessage: 'Add to case', + }), + 'data-test-subj': 'aiopsLogRateAnalysisAttachToCaseButton', + disabled: !isCasesAttachmentEnabled, + ...(!isCasesAttachmentEnabled + ? { + toolTipProps: { position: 'left' as const }, + toolTipContent: caseAttachmentTooltipContent, + } + : {}), + onClick: () => { + setIsActionMenuOpen(false); + openCasesModalCallback({ + dataViewId: dataView.id, + timeRange: absoluteTimeRange, + ...(windowParameters && { windowParameters }), + }); + }, + }, + ] + : []), ], }, { @@ -131,7 +193,18 @@ export const LogRateAnalysisAttachmentsMenu = () => { ), }, ]; - }, [canEditDashboards, applyTimeRange]); + }, [ + canEditDashboards, + canUpdateCase, + canCreateCase, + isCasesAttachmentEnabled, + caseAttachmentTooltipContent, + applyTimeRange, + openCasesModalCallback, + dataView.id, + absoluteTimeRange, + windowParameters, + ]); return ( <> diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx index 29ac8d0efffc..fb3c17634fd3 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_content/log_rate_analysis_content.tsx @@ -217,7 +217,13 @@ export const LogRateAnalysisContent: FC = ({ barColorOverride={barColorOverride} barHighlightColorOverride={barHighlightColorOverride} barStyleAccessor={barStyleAccessor} - attachmentsMenu={} + attachmentsMenu={ + + } /> )} diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx index 1eb4f8fd0af0..42fa509e6ce4 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis/log_rate_analysis_results.tsx @@ -333,6 +333,8 @@ export const LogRateAnalysisResults: FC = ({ }, 0); const foundGroups = groupTableItems.length > 0 && groupItemCount > 0; + const isAnalysisControlsDisabled = embeddingOrigin === AIOPS_EMBEDDABLE_ORIGIN.CASES; + return (
        = ({ onReset={onReset} shouldRerunAnalysis={shouldRerunAnalysis || searchQueryUpdated} analysisInfo={} + isAnalysisControlsDisabled={isAnalysisControlsDisabled} > <> {embeddingOrigin !== AIOPS_EMBEDDABLE_ORIGIN.DASHBOARD && ( diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx index 765f1435a93a..a9a030ecd16b 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_discover_action.tsx @@ -16,6 +16,7 @@ import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { TableActionButton } from './table_action_button'; import { getTableItemAsKQL } from './get_table_item_as_kql'; +import { useFilterQueryUpdates } from '../../hooks/use_filters_query'; const viewInDiscoverMessage = i18n.translate( 'xpack.aiops.logRateAnalysis.resultsTable.linksMenu.viewInDiscover', @@ -32,6 +33,10 @@ export const useViewInDiscoverAction = (dataViewId?: string): TableItemAction => [share?.url.locators] ); + // We cannot rely on the time range from AiOps App context because it is not always in sync with the time range used for analysis. + // E.g. In the case of an embeddable inside cases, the time range is fixed and not coming from the time picker. + const { timeRange } = useFilterQueryUpdates(); + const discoverUrlError = useMemo(() => { if (!application.capabilities.discover?.show) { const discoverNotEnabled = i18n.translate( @@ -69,7 +74,7 @@ export const useViewInDiscoverAction = (dataViewId?: string): TableItemAction => if (discoverLocator !== undefined) { const url = await discoverLocator.getRedirectUrl({ indexPatternId: dataViewId, - timeRange: data.query.timefilter.timefilter.getTime(), + timeRange, filters: data.query.filterManager.getFilters(), query: { language: SEARCH_QUERY_LANGUAGE.KUERY, diff --git a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx index d92ce014d68f..e96df8d140a1 100644 --- a/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx +++ b/x-pack/plugins/aiops/public/components/log_rate_analysis_results_table/use_view_in_log_pattern_analysis_action.tsx @@ -18,6 +18,7 @@ import { useAiopsAppContext } from '../../hooks/use_aiops_app_context'; import { TableActionButton } from './table_action_button'; import { getTableItemAsKQL } from './get_table_item_as_kql'; +import { useFilterQueryUpdates } from '../../hooks/use_filters_query'; const isLogPattern = (tableItem: SignificantItem | GroupTableItem) => isSignificantItem(tableItem) && tableItem.type === SIGNIFICANT_ITEM_TYPE.LOG_PATTERN; @@ -34,6 +35,10 @@ export const useViewInLogPatternAnalysisAction = (dataViewId?: string): TableIte const mlLocator = useMemo(() => share?.url.locators.get('ML_APP_LOCATOR'), [share?.url.locators]); + // We cannot rely on the time range from AiOps App context because it is not always in sync with the time range used for analysis. + // E.g. In the case of an embeddable inside cases, the time range is fixed and not coming from the time picker. + const { timeRange } = useFilterQueryUpdates(); + const generateLogPatternAnalysisUrl = async ( groupTableItem: GroupTableItem | SignificantItem ) => { @@ -57,7 +62,9 @@ export const useViewInLogPatternAnalysisAction = (dataViewId?: string): TableIte page: 'aiops/log_categorization', pageState: { index: dataViewId, - timeRange: data.query.timefilter.timefilter.getTime(), + globalState: { + time: timeRange, + }, appState, }, }); diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx index 592ec32cef12..6d1ea7d2e03c 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory.tsx @@ -37,6 +37,8 @@ import type { LogRateAnalysisEmbeddableState, } from './types'; +export type EmbeddableLogRateAnalysisType = typeof EMBEDDABLE_LOG_RATE_ANALYSIS_TYPE; + export const getLogRateAnalysisEmbeddableFactory = ( getStartServices: StartServicesAccessor ) => { diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts index 9d8a49b8f0e9..d155546e28bf 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/initialize_log_rate_analysis_analysis_controls.ts @@ -11,7 +11,7 @@ import type { LogRateAnalysisComponentApi, LogRateAnalysisEmbeddableState } from type LogRateAnalysisEmbeddableCustomState = Omit< LogRateAnalysisEmbeddableState, - 'timeRange' | 'title' | 'description' | 'hidePanelTitles' + 'timeRange' | 'title' | 'description' | 'hidePanelTitles' | 'windowParameters' >; export const initializeLogRateAnalysisControls = (rawState: LogRateAnalysisEmbeddableState) => { diff --git a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts index d2255e6dacb8..28a68cecd36f 100644 --- a/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts +++ b/x-pack/plugins/aiops/public/embeddables/log_rate_analysis/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { WindowParameters } from '@kbn/aiops-log-rate-analysis'; import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; import type { HasEditCapabilities, @@ -28,6 +29,7 @@ export type LogRateAnalysisEmbeddableApi = DefaultEmbeddableApi; diff --git a/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts b/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts index 8ec73a21f9bb..745506a0a1ae 100644 --- a/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts +++ b/x-pack/plugins/aiops/public/hooks/use_cases_modal.ts @@ -13,14 +13,21 @@ import type { EmbeddableChangePointChartType } from '../embeddables/change_point import { useAiopsAppContext } from './use_aiops_app_context'; import type { EmbeddablePatternAnalysisType } from '../embeddables/pattern_analysis/embeddable_pattern_analysis_factory'; import type { PatternAnalysisEmbeddableRuntimeState } from '../embeddables/pattern_analysis/types'; +import type { EmbeddableLogRateAnalysisType } from '../embeddables/log_rate_analysis/embeddable_log_rate_analysis_factory'; +import type { LogRateAnalysisEmbeddableRuntimeState } from '../embeddables/log_rate_analysis/types'; -type SupportedEmbeddableTypes = EmbeddableChangePointChartType | EmbeddablePatternAnalysisType; +type SupportedEmbeddableTypes = + | EmbeddableChangePointChartType + | EmbeddablePatternAnalysisType + | EmbeddableLogRateAnalysisType; type EmbeddableRuntimeState = T extends EmbeddableChangePointChartType ? ChangePointEmbeddableRuntimeState : T extends EmbeddablePatternAnalysisType ? PatternAnalysisEmbeddableRuntimeState + : T extends EmbeddableLogRateAnalysisType + ? LogRateAnalysisEmbeddableRuntimeState : never; /** diff --git a/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx b/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx index 9f2a88e73461..f08f4f0e68bd 100644 --- a/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx +++ b/x-pack/plugins/aiops/public/shared_components/log_rate_analysis_embeddable_wrapper.tsx @@ -10,10 +10,7 @@ import React, { useEffect, useMemo, useState, type FC } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; import type { Observable } from 'rxjs'; import { BehaviorSubject, combineLatest, distinctUntilChanged, map } from 'rxjs'; -import { createBrowserHistory } from 'history'; -import { UrlStateProvider } from '@kbn/ml-url-state'; -import { Router } from '@kbn/shared-ux-router'; import { AIOPS_EMBEDDABLE_ORIGIN } from '@kbn/aiops-common/constants'; import type { CoreStart } from '@kbn/core-lifecycle-browser'; import { UI_SETTINGS } from '@kbn/data-service'; @@ -22,6 +19,7 @@ import type { TimeRange } from '@kbn/es-query'; import { DatePickerContextProvider } from '@kbn/ml-date-picker'; import type { SignificantItem } from '@kbn/ml-agg-utils'; +import type { WindowParameters } from '@kbn/aiops-log-rate-analysis'; import { AiopsAppContext, type AiopsAppContextValue } from '../hooks/use_aiops_app_context'; import { DataSourceContextProvider } from '../hooks/use_data_source'; import { ReloadContextProvider } from '../hooks/use_reload'; @@ -60,6 +58,7 @@ export interface LogRateAnalysisEmbeddableWrapperProps { onLoading: (isLoading: boolean) => void; onRenderComplete: () => void; onError: (error: Error) => void; + windowParameters?: WindowParameters; } const LogRateAnalysisEmbeddableWrapperWithDeps: FC = ({ @@ -71,6 +70,7 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC timeRange, embeddingOrigin, lastReloadRequestTime, + windowParameters, }) => { const deps = useMemo(() => { const { lens, data, usageCollection, fieldFormats, charts, share, storage, unifiedSearch } = @@ -120,8 +120,6 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC ); }, [manualReload$]); - const history = createBrowserHistory(); - // We use the following pattern to track changes of dataViewId, and if there's // a change, we unmount and remount the complete inner component. This makes // sure the component is reinitialized correctly when the options of the @@ -150,26 +148,22 @@ const LogRateAnalysisEmbeddableWrapperWithDeps: FC }} > {showComponent && ( - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + )}
        ); diff --git a/x-pack/plugins/aiops/server/register_cases.ts b/x-pack/plugins/aiops/server/register_cases.ts index 5649c88ca632..ac126a74a5a2 100644 --- a/x-pack/plugins/aiops/server/register_cases.ts +++ b/x-pack/plugins/aiops/server/register_cases.ts @@ -9,6 +9,7 @@ import type { Logger } from '@kbn/core/server'; import type { CasesServerSetup } from '@kbn/cases-plugin/server'; import { CASES_ATTACHMENT_CHANGE_POINT_CHART } from '@kbn/aiops-change-point-detection/constants'; import { CASES_ATTACHMENT_LOG_PATTERN } from '@kbn/aiops-log-pattern-analysis/constants'; +import { CASES_ATTACHMENT_LOG_RATE_ANALYSIS } from '@kbn/aiops-log-rate-analysis/constants'; export function registerCasesPersistableState(cases: CasesServerSetup | undefined, logger: Logger) { if (cases) { @@ -19,6 +20,9 @@ export function registerCasesPersistableState(cases: CasesServerSetup | undefine cases.attachmentFramework.registerPersistableState({ id: CASES_ATTACHMENT_LOG_PATTERN, }); + cases.attachmentFramework.registerPersistableState({ + id: CASES_ATTACHMENT_LOG_RATE_ANALYSIS, + }); } catch (error) { logger.warn(`AIOPs failed to register cases persistable state`); } diff --git a/x-pack/plugins/aiops/tsconfig.json b/x-pack/plugins/aiops/tsconfig.json index 234420f01c52..7b4b8493e1ab 100644 --- a/x-pack/plugins/aiops/tsconfig.json +++ b/x-pack/plugins/aiops/tsconfig.json @@ -78,7 +78,6 @@ "@kbn/ui-theme", "@kbn/apm-utils", "@kbn/ml-field-stats-flyout", - "@kbn/shared-ux-router", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts index 95f07bf3f7bd..57a9499779ad 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/aggregate/schemas/v1.ts @@ -24,7 +24,8 @@ export const aggregateRulesRequestBodySchema = schema.object({ ) ), filter: schema.maybe(schema.string()), - filter_consumers: schema.maybe(schema.arrayOf(schema.string())), + rule_type_ids: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), }); export const aggregateRulesResponseBodySchema = schema.object({ diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts index 62cc67360b16..26e5283cede1 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/bulk_untrack_by_query/schemas/v1.ts @@ -9,5 +9,5 @@ import { schema } from '@kbn/config-schema'; export const bulkUntrackByQueryBodySchema = schema.object({ query: schema.arrayOf(schema.any()), - feature_ids: schema.arrayOf(schema.string()), + rule_type_ids: schema.arrayOf(schema.string()), }); diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts index 7722521d2b70..b8ebef499e7e 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/index.ts @@ -8,8 +8,13 @@ export { findRulesRequestQuerySchema } from './schemas/latest'; export type { FindRulesRequestQuery, FindRulesResponse } from './types/latest'; -export { findRulesRequestQuerySchema as findRulesRequestQuerySchemaV1 } from './schemas/v1'; +export { + findRulesRequestQuerySchema as findRulesRequestQuerySchemaV1, + findRulesInternalRequestBodySchema as findRulesInternalRequestBodySchemaV1, +} from './schemas/v1'; + export type { FindRulesRequestQuery as FindRulesRequestQueryV1, + FindRulesInternalRequestBody as FindRulesInternalRequestBodyV1, FindRulesResponse as FindRulesResponseV1, } from './types/latest'; diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts index 1dece949a955..06ebfdbacc54 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/schemas/v1.ts @@ -103,3 +103,35 @@ export const findRulesRequestQuerySchema = schema.object({ ) ), }); + +export const findRulesInternalRequestBodySchema = schema.object({ + per_page: schema.number({ + defaultValue: 10, + min: 0, + }), + page: schema.number({ + defaultValue: 1, + min: 1, + }), + search: schema.maybe(schema.string()), + default_search_operator: schema.oneOf([schema.literal('OR'), schema.literal('AND')], { + defaultValue: 'OR', + }), + search_fields: schema.maybe(schema.oneOf([schema.arrayOf(schema.string()), schema.string()])), + sort_field: schema.maybe(schema.string()), + sort_order: schema.maybe(schema.oneOf([schema.literal('asc'), schema.literal('desc')])), + has_reference: schema.maybe( + // use nullable as maybe is currently broken + // in config-schema + schema.nullable( + schema.object({ + type: schema.string(), + id: schema.string(), + }) + ) + ), + fields: schema.maybe(schema.arrayOf(schema.string())), + filter: schema.maybe(schema.string()), + rule_type_ids: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), +}); diff --git a/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts index 271e791282f4..e09b4871eabc 100644 --- a/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts +++ b/x-pack/plugins/alerting/common/routes/rule/apis/find/types/v1.ts @@ -7,9 +7,10 @@ import type { TypeOf } from '@kbn/config-schema'; import { RuleParamsV1, RuleResponseV1 } from '../../../response'; -import { findRulesRequestQuerySchemaV1 } from '..'; +import { findRulesRequestQuerySchemaV1, findRulesInternalRequestBodySchemaV1 } from '..'; export type FindRulesRequestQuery = TypeOf; +export type FindRulesInternalRequestBody = TypeOf; export interface FindRulesResponse { body: { diff --git a/x-pack/plugins/alerting/kibana.jsonc b/x-pack/plugins/alerting/kibana.jsonc index 0b5f930dbb34..b99c0a26c901 100644 --- a/x-pack/plugins/alerting/kibana.jsonc +++ b/x-pack/plugins/alerting/kibana.jsonc @@ -35,12 +35,11 @@ "usageCollection", "security", "monitoringCollection", - "spaces", - "serverless" + "spaces" ], "extraPublicDirs": [ "common", "common/parse_duration" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx index e6f58df8d3a7..367da7e65811 100644 --- a/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_archive_maintenance_window.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook, act } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useArchiveMaintenanceWindow } from './use_archive_maintenance_window'; diff --git a/x-pack/plugins/alerting/public/hooks/use_breadcrumbs.test.tsx b/x-pack/plugins/alerting/public/hooks/use_breadcrumbs.test.tsx index 9eb5970e86a9..f06fd2be6799 100644 --- a/x-pack/plugins/alerting/public/hooks/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_breadcrumbs.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useBreadcrumbs } from './use_breadcrumbs'; import { MAINTENANCE_WINDOW_DEEP_LINK_IDS } from '../../common'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; diff --git a/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx index 26d70f2d4e9a..12564df1bf1b 100644 --- a/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_create_maintenance_window.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook, act } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useCreateMaintenanceWindow } from './use_create_maintenance_window'; diff --git a/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx b/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx index d21b145aea93..b543d7940cd9 100644 --- a/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_find_maintenance_windows.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useFindMaintenanceWindows } from './use_find_maintenance_windows'; diff --git a/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx index 8b55812bd030..7e453d5d78d5 100644 --- a/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_finish_and_archive_maintenance_window.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook, act } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useFinishAndArchiveMaintenanceWindow } from './use_finish_and_archive_maintenance_window'; diff --git a/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx index 6041796fcc00..fc972eddeafe 100644 --- a/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_finish_maintenance_window.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook, act } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useFinishMaintenanceWindow } from './use_finish_maintenance_window'; diff --git a/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx index 3003f1003ce1..d58aebe0a157 100644 --- a/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_get_maintenance_window.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useGetMaintenanceWindow } from './use_get_maintenance_window'; diff --git a/x-pack/plugins/alerting/public/hooks/use_license.test.tsx b/x-pack/plugins/alerting/public/hooks/use_license.test.tsx index 0611a6ba86ae..f9d439607257 100644 --- a/x-pack/plugins/alerting/public/hooks/use_license.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_license.test.tsx @@ -6,7 +6,7 @@ */ import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useLicense } from './use_license'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; diff --git a/x-pack/plugins/alerting/public/hooks/use_navigation.test.tsx b/x-pack/plugins/alerting/public/hooks/use_navigation.test.tsx index 2ea981db2a4d..1b7c48ee684e 100644 --- a/x-pack/plugins/alerting/public/hooks/use_navigation.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_navigation.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useCreateMaintenanceWindowNavigation, diff --git a/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx b/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx index 6ba19c27c362..a1da94422c89 100644 --- a/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx +++ b/x-pack/plugins/alerting/public/hooks/use_update_maintenance_window.test.tsx @@ -4,8 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; + +import { waitFor, renderHook, act } from '@testing-library/react'; import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils'; import { useUpdateMaintenanceWindow } from './use_update_maintenance_window'; diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx index 7f3c25eeaf55..04bab61eb5c6 100644 --- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx +++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/create_maintenance_windows_form.tsx @@ -31,7 +31,6 @@ import { } from '@elastic/eui'; import { TIMEZONE_OPTIONS as UI_TIMEZONE_OPTIONS } from '@kbn/core-ui-settings-common'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { Filter } from '@kbn/es-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; import type { KibanaServerError } from '@kbn/kibana-utils-plugin/public'; @@ -73,7 +72,10 @@ const useDefaultTimezone = () => { } return { defaultTimezone: kibanaTz, isBrowser: false }; }; -const TIMEZONE_OPTIONS = UI_TIMEZONE_OPTIONS.map((n) => ({ label: n })) ?? [{ label: 'UTC' }]; + +const TIMEZONE_OPTIONS = UI_TIMEZONE_OPTIONS.map((timezoneOption) => ({ + label: timezoneOption, +})) ?? [{ label: 'UTC' }]; export const CreateMaintenanceWindowForm = React.memo((props) => { const { onCancel, onSuccess, initialValue, maintenanceWindowId } = props; @@ -203,6 +205,7 @@ export const CreateMaintenanceWindowForm = React.memo ruleType.category))]; }, [validRuleTypes]); - const featureIds = useMemo(() => { + const ruleTypeIds = useMemo(() => { if (!Array.isArray(validRuleTypes) || !Array.isArray(categoryIds) || !mounted) { return []; } - const featureIdsSet = new Set(); + const uniqueRuleTypeIds = new Set(); validRuleTypes.forEach((ruleType) => { if (categoryIds.includes(ruleType.category)) { - featureIdsSet.add(ruleType.producer as ValidFeatureId); + uniqueRuleTypeIds.add(ruleType.id); } }); - return [...featureIdsSet]; + return [...uniqueRuleTypeIds]; }, [validRuleTypes, categoryIds, mounted]); const onCategoryIdsChange = useCallback( @@ -476,7 +479,7 @@ export const CreateMaintenanceWindowForm = React.memo {() => ( { it('renders correctly', () => { appMockRenderer.render( { it('should hide the search bar if isEnabled is false', () => { appMockRenderer.render( { it('should render loading if isLoading is true', () => { appMockRenderer.render( { const { - featureIds, + ruleTypeIds, query, filters, errors = [], @@ -76,7 +75,7 @@ export const MaintenanceWindowScopedQuery = React.memo( { + const features = featuresPluginMock.createStart(); + const securityPluginStart = securityMock.createStart(); + const alertingAuthorizationClientFactoryParams: jest.Mocked = + { + ruleTypeRegistry: ruleTypeRegistryMock.create(), + getSpace: jest.fn(), + getSpaceId: jest.fn(), + features, + }; -const securityPluginSetup = securityMock.createSetup(); -const securityPluginStart = securityMock.createStart(); + beforeEach(() => { + jest.clearAllMocks(); + }); -const alertingAuthorizationClientFactoryParams: jest.Mocked = - { - ruleTypeRegistry: ruleTypeRegistryMock.create(), - getSpace: jest.fn(), - getSpaceId: jest.fn(), - features, - }; + it('creates an alerting authorization client with proper constructor arguments when security is enabled', async () => { + const factory = new AlertingAuthorizationClientFactory(); -beforeEach(() => { - jest.resetAllMocks(); -}); + factory.initialize({ + securityPluginStart, + ...alertingAuthorizationClientFactoryParams, + }); + + const request = mockRouter.createKibanaRequest(); + + await factory.create(request); -test('creates an alerting authorization client with proper constructor arguments when security is enabled', async () => { - const factory = new AlertingAuthorizationClientFactory(); - factory.initialize({ - securityPluginSetup, - securityPluginStart, - ...alertingAuthorizationClientFactoryParams, + const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); + expect(AlertingAuthorization.create).toHaveBeenCalledWith({ + request, + authorization: securityPluginStart.authz, + ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, + features: alertingAuthorizationClientFactoryParams.features, + getSpace: expect.any(Function), + getSpaceId: expect.any(Function), + }); }); - const request = mockRouter.createKibanaRequest(); - factory.create(request); + it('creates an alerting authorization client with proper constructor arguments', async () => { + const factory = new AlertingAuthorizationClientFactory(); + factory.initialize(alertingAuthorizationClientFactoryParams); + const request = mockRouter.createKibanaRequest(); - const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); - expect(AlertingAuthorization).toHaveBeenCalledWith({ - request, - authorization: securityPluginStart.authz, - ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, - features: alertingAuthorizationClientFactoryParams.features, - getSpace: expect.any(Function), - getSpaceId: expect.any(Function), + await factory.create(request); + + const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); + expect(AlertingAuthorization.create).toHaveBeenCalledWith({ + request, + ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, + features: alertingAuthorizationClientFactoryParams.features, + getSpace: expect.any(Function), + getSpaceId: expect.any(Function), + }); }); -}); -test('creates an alerting authorization client with proper constructor arguments', async () => { - const factory = new AlertingAuthorizationClientFactory(); - factory.initialize(alertingAuthorizationClientFactoryParams); - const request = mockRouter.createKibanaRequest(); + it('throws when trying to initialize again and it is already initialized', async () => { + const factory = new AlertingAuthorizationClientFactory(); + factory.initialize(alertingAuthorizationClientFactoryParams); + + expect(() => + factory.initialize(alertingAuthorizationClientFactoryParams) + ).toThrowErrorMatchingInlineSnapshot( + `"AlertingAuthorizationClientFactory already initialized"` + ); + }); - factory.create(request); + it('throws when trying to create an instance and the factory is not initialized', async () => { + const request = mockRouter.createKibanaRequest(); + const factory = new AlertingAuthorizationClientFactory(); - const { AlertingAuthorization } = jest.requireMock('./authorization/alerting_authorization'); - expect(AlertingAuthorization).toHaveBeenCalledWith({ - request, - ruleTypeRegistry: alertingAuthorizationClientFactoryParams.ruleTypeRegistry, - features: alertingAuthorizationClientFactoryParams.features, - getSpace: expect.any(Function), - getSpaceId: expect.any(Function), + await expect(() => factory.create(request)).rejects.toThrowErrorMatchingInlineSnapshot( + `"AlertingAuthorizationClientFactory must be initialized before calling create"` + ); }); }); diff --git a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts index ca366a6cee0e..8c5a772501f2 100644 --- a/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts +++ b/x-pack/plugins/alerting/server/alerting_authorization_client_factory.ts @@ -6,7 +6,7 @@ */ import { KibanaRequest } from '@kbn/core/server'; -import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; +import { SecurityPluginStart } from '@kbn/security-plugin/server'; import { FeaturesPluginStart } from '@kbn/features-plugin/server'; import { Space } from '@kbn/spaces-plugin/server'; import { AlertingAuthorization } from './authorization/alerting_authorization'; @@ -14,7 +14,6 @@ import { RuleTypeRegistry } from './types'; export interface AlertingAuthorizationClientFactoryOpts { ruleTypeRegistry: RuleTypeRegistry; - securityPluginSetup?: SecurityPluginSetup; securityPluginStart?: SecurityPluginStart; getSpace: (request: KibanaRequest) => Promise; getSpaceId: (request: KibanaRequest) => string; @@ -23,33 +22,39 @@ export interface AlertingAuthorizationClientFactoryOpts { export class AlertingAuthorizationClientFactory { private isInitialized = false; - private ruleTypeRegistry!: RuleTypeRegistry; - private securityPluginStart?: SecurityPluginStart; - private features!: FeaturesPluginStart; - private getSpace!: (request: KibanaRequest) => Promise; - private getSpaceId!: (request: KibanaRequest) => string; + // The reason this is protected is because we'll get type collisions otherwise because we're using a type guard assert + // to ensure the options member is instantiated before using it in various places + // See for more info: https://stackoverflow.com/questions/66206180/typescript-typeguard-attribut-with-method + protected options?: AlertingAuthorizationClientFactoryOpts; public initialize(options: AlertingAuthorizationClientFactoryOpts) { if (this.isInitialized) { throw new Error('AlertingAuthorizationClientFactory already initialized'); } this.isInitialized = true; - this.getSpace = options.getSpace; - this.ruleTypeRegistry = options.ruleTypeRegistry; - this.securityPluginStart = options.securityPluginStart; - this.features = options.features; - this.getSpaceId = options.getSpaceId; + this.options = options; } - public create(request: KibanaRequest): AlertingAuthorization { - const { securityPluginStart, features } = this; - return new AlertingAuthorization({ - authorization: securityPluginStart?.authz, + public async create(request: KibanaRequest): Promise { + this.validateInitialization(); + + return AlertingAuthorization.create({ + authorization: this.options.securityPluginStart?.authz, request, - getSpace: this.getSpace, - getSpaceId: this.getSpaceId, - ruleTypeRegistry: this.ruleTypeRegistry, - features: features!, + getSpace: this.options.getSpace, + getSpaceId: this.options.getSpaceId, + ruleTypeRegistry: this.options.ruleTypeRegistry, + features: this.options.features, }); } + + private validateInitialization(): asserts this is this & { + options: AlertingAuthorizationClientFactoryOpts; + } { + if (!this.isInitialized || this.options == null) { + throw new Error( + 'AlertingAuthorizationClientFactory must be initialized before calling create' + ); + } + } } diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts index 36bf830e47f7..903c8764d801 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.test.ts @@ -347,6 +347,7 @@ describe('Alerts Client', () => { rule: alertRuleData, kibanaVersion: '8.9.0', spaceId: 'space1', + isServerless: false, dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), }; maintenanceWindowsService.getMaintenanceWindows.mockReturnValue({ @@ -543,10 +544,58 @@ describe('Alerts Client', () => { }); describe('persistAlerts()', () => { - test('should index new alerts', async () => { - const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>( - alertsClientParams - ); + test('should index new alerts with refresh: wait_for in stateful', async () => { + const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>({ + ...alertsClientParams, + isServerless: false, + }); + + await alertsClient.initializeExecution(defaultExecutionOpts); + + // Report 2 new alerts + const alertExecutorService = alertsClient.factory(); + alertExecutorService.create('1').scheduleActions('default'); + alertExecutorService.create('2').scheduleActions('default'); + + await alertsClient.processAlerts(processAlertsOpts); + alertsClient.logAlerts(logAlertsOpts); + + await alertsClient.persistAlerts(); + + const { alertsToReturn } = alertsClient.getAlertsToSerialize(); + const uuid1 = alertsToReturn['1'].meta?.uuid; + const uuid2 = alertsToReturn['2'].meta?.uuid; + + expect(clusterClient.bulk).toHaveBeenCalledWith({ + index: '.alerts-test.alerts-default', + refresh: 'wait_for', + require_alias: !useDataStreamForAlerts, + body: [ + { + create: { _id: uuid1, ...(useDataStreamForAlerts ? {} : { require_alias: true }) }, + }, + // new alert doc + getNewIndexedAlertDoc({ [ALERT_UUID]: uuid1 }), + { + create: { _id: uuid2, ...(useDataStreamForAlerts ? {} : { require_alias: true }) }, + }, + // new alert doc + getNewIndexedAlertDoc({ [ALERT_UUID]: uuid2, [ALERT_INSTANCE_ID]: '2' }), + ], + }); + expect(maintenanceWindowsService.getMaintenanceWindows).toHaveBeenCalledWith({ + eventLogger: alertingEventLogger, + request: fakeRequest, + ruleTypeCategory: 'test', + spaceId: 'space1', + }); + }); + + test('should index new alerts with refresh: true in stateless', async () => { + const alertsClient = new AlertsClient<{}, {}, {}, 'default', 'recovered'>({ + ...alertsClientParams, + isServerless: true, + }); await alertsClient.initializeExecution(defaultExecutionOpts); @@ -659,7 +708,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -732,7 +781,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -867,7 +916,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -940,7 +989,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1039,7 +1088,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1196,7 +1245,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1314,7 +1363,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1518,7 +1567,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -1602,6 +1651,7 @@ describe('Alerts Client', () => { shouldWrite: false, }, }, + isServerless: false, request: fakeRequest, namespace: 'default', rule: alertRuleData, @@ -2451,7 +2501,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -2725,7 +2775,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -2826,7 +2876,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { @@ -2923,7 +2973,7 @@ describe('Alerts Client', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts index 1bfa1de9e96d..0c2340ba7cd2 100644 --- a/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts +++ b/x-pack/plugins/alerting/server/alerts_client/alerts_client.ts @@ -73,6 +73,7 @@ export interface AlertsClientParams extends CreateAlertsClientParams { elasticsearchClientPromise: Promise; kibanaVersion: string; dataStreamAdapter: DataStreamAdapter; + isServerless: boolean; } interface AlertsAffectedByMaintenanceWindows { @@ -109,6 +110,7 @@ export class AlertsClient< private runTimestampString: string | undefined; private rule: AlertRule; private ruleType: UntypedNormalizedRuleType; + private readonly isServerless: boolean; private indexTemplateAndPattern: IIndexPatternString; @@ -143,6 +145,7 @@ export class AlertsClient< this._isUsingDataStreams = this.options.dataStreamAdapter.isUsingDataStreams(); this.ruleInfoMessage = `for ${this.ruleType.id}:${this.options.rule.id} '${this.options.rule.name}'`; this.logTags = { tags: [this.ruleType.id, this.options.rule.id, 'alerts-client'] }; + this.isServerless = options.isServerless; } public async initializeExecution(opts: InitializeExecutionOpts) { @@ -555,7 +558,9 @@ export class AlertsClient< try { const response = await esClient.bulk({ - refresh: true, + // On serverless we can force a refresh to we don't wait for the longer refresh interval + // When too many refresh calls are done in a short period of time, they are throttled by stateless Elasticsearch + refresh: this.isServerless ? true : 'wait_for', index: this.indexTemplateAndPattern.alias, require_alias: !this.isUsingDataStreams(), body: bulkBody, diff --git a/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts b/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts index c97fb9f31f82..78339ed5906b 100644 --- a/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/alerts_client/lib/initialize_alerts_client.test.ts @@ -100,6 +100,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, @@ -159,6 +160,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, @@ -219,6 +221,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, @@ -288,6 +291,7 @@ describe('initializeAlertsClient', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, executionId: 'abc', logger, diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts index 4b4f632d4cb2..5b32cf507c81 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.test.ts @@ -275,6 +275,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -308,6 +309,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$: test$, + isServerless: false, }); await retryUntil( @@ -350,6 +352,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -372,6 +375,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('error log called', async () => logger.error.mock.calls.length > 0); @@ -453,6 +457,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -495,6 +500,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -1516,6 +1522,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: true, }); await retryUntil( @@ -1561,6 +1568,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: true, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1586,6 +1594,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -1629,6 +1638,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -1693,6 +1703,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1736,6 +1747,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -1824,6 +1836,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1870,6 +1883,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -1911,6 +1925,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -1960,6 +1975,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2013,6 +2029,7 @@ describe('Alerts Service', () => { maintenanceWindowsService, namespace: 'default', spaceId: 'default', + isServerless: false, rule: { consumer: 'bar', executionId: '5f6aa57d-3e22-484e-bae8-cbed868f4d28', @@ -2067,6 +2084,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2134,6 +2152,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2205,6 +2224,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2283,6 +2303,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); alertsService.register(TestRegistrationContext); @@ -2341,6 +2362,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2362,6 +2384,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2383,6 +2406,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2412,6 +2436,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2444,6 +2469,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2481,6 +2507,7 @@ describe('Alerts Service', () => { kibanaVersion: '8.8.0', dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil( @@ -2516,6 +2543,7 @@ describe('Alerts Service', () => { timeoutMs: 10, dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('error logger called', async () => logger.error.mock.calls.length > 0); @@ -2533,6 +2561,7 @@ describe('Alerts Service', () => { timeoutMs: 10, dataStreamAdapter, elasticsearchAndSOAvailability$, + isServerless: false, }); await retryUntil('debug logger called', async () => logger.debug.mock.calls.length > 0); diff --git a/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts b/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts index 4f0ead6c5420..6a6dbbdb58df 100644 --- a/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts +++ b/x-pack/plugins/alerting/server/alerts_service/alerts_service.ts @@ -59,6 +59,7 @@ interface AlertsServiceParams { timeoutMs?: number; dataStreamAdapter: DataStreamAdapter; elasticsearchAndSOAvailability$: Observable; + isServerless: boolean; } export interface CreateAlertsClientParams extends LegacyAlertsClientParams { @@ -120,6 +121,7 @@ export type PublicFrameworkAlertsService = PublicAlertsService & { export class AlertsService implements IAlertsService { private initialized: boolean; + private isServerless: boolean; private isInitializing: boolean = false; private resourceInitializationHelper: ResourceInstallationHelper; private registeredContexts: Map = new Map(); @@ -129,6 +131,7 @@ export class AlertsService implements IAlertsService { constructor(private readonly options: AlertsServiceParams) { this.initialized = false; + this.isServerless = options.isServerless; this.dataStreamAdapter = options.dataStreamAdapter; // Kick off initialization of common assets and save the promise @@ -245,6 +248,7 @@ export class AlertsService implements IAlertsService { spaceId: opts.spaceId, kibanaVersion: this.options.kibanaVersion, dataStreamAdapter: this.dataStreamAdapter, + isServerless: this.isServerless, }); } diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts index 54376012aa76..003673f9fdb9 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.test.ts @@ -15,10 +15,8 @@ import { setAlertsToUntracked } from './set_alerts_to_untracked'; let clusterClient: ElasticsearchClientMock; let logger: ReturnType<(typeof loggingSystemMock)['createLogger']>; -const getAuthorizedRuleTypesMock = jest.fn(); - +const getAllAuthorizedRuleTypesFindOperationMock = jest.fn(); const getAlertIndicesAliasMock = jest.fn(); - const ensureAuthorizedMock = jest.fn(); describe('setAlertsToUntracked()', () => { @@ -362,11 +360,16 @@ describe('setAlertsToUntracked()', () => { }); test('should untrack by query', async () => { - getAuthorizedRuleTypesMock.mockResolvedValue([ - { - id: 'test-rule-type', - }, - ]); + getAllAuthorizedRuleTypesFindOperationMock.mockResolvedValue( + new Map([ + [ + 'test-rule-type', + { + id: 'test-rule-type', + }, + ], + ]) + ); getAlertIndicesAliasMock.mockResolvedValue(['test-alert-index']); clusterClient.search.mockResponseOnce({ @@ -441,9 +444,9 @@ describe('setAlertsToUntracked()', () => { }, }, ], - featureIds: ['o11y'], + ruleTypeIds: ['my-rule-type-id'], spaceId: 'default', - getAuthorizedRuleTypes: getAuthorizedRuleTypesMock, + getAllAuthorizedRuleTypesFindOperation: getAllAuthorizedRuleTypesFindOperationMock, getAlertIndicesAlias: getAlertIndicesAliasMock, ensureAuthorized: ensureAuthorizedMock, logger, @@ -527,11 +530,16 @@ describe('setAlertsToUntracked()', () => { }); test('should return an empty array if the search returns zero results', async () => { - getAuthorizedRuleTypesMock.mockResolvedValue([ - { - id: 'test-rule-type', - }, - ]); + getAllAuthorizedRuleTypesFindOperationMock.mockResolvedValue( + new Map([ + [ + 'test-rule-type', + { + id: 'test-rule-type', + }, + ], + ]) + ); getAlertIndicesAliasMock.mockResolvedValue(['test-alert-index']); clusterClient.search.mockResponseOnce({ @@ -575,9 +583,9 @@ describe('setAlertsToUntracked()', () => { }, }, ], - featureIds: ['o11y'], + ruleTypeIds: ['my-rule-type-id'], spaceId: 'default', - getAuthorizedRuleTypes: getAuthorizedRuleTypesMock, + getAllAuthorizedRuleTypesFindOperation: getAllAuthorizedRuleTypesFindOperationMock, getAlertIndicesAlias: getAlertIndicesAliasMock, ensureAuthorized: ensureAuthorizedMock, logger, diff --git a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts index ed0c2cb21e06..89c8d671de6a 100644 --- a/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts +++ b/x-pack/plugins/alerting/server/alerts_service/lib/set_alerts_to_untracked.ts @@ -21,8 +21,8 @@ import { AlertStatus, } from '@kbn/rule-data-utils'; import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { AlertingAuthorizationEntity } from '../../authorization/alerting_authorization'; import type { RulesClientContext } from '../../rules_client'; +import { AlertingAuthorizationEntity } from '../../authorization/types'; type EnsureAuthorized = (opts: { ruleTypeId: string; consumer: string }) => Promise; @@ -32,9 +32,9 @@ export interface SetAlertsToUntrackedParams { alertUuids?: string[]; query?: QueryDslQueryContainer[]; spaceId?: RulesClientContext['spaceId']; - featureIds?: string[]; + ruleTypeIds?: string[]; isUsingQuery?: boolean; - getAuthorizedRuleTypes?: RulesClientContext['authorization']['getAuthorizedRuleTypes']; + getAllAuthorizedRuleTypesFindOperation?: RulesClientContext['authorization']['getAllAuthorizedRuleTypesFindOperation']; getAlertIndicesAlias?: RulesClientContext['getAlertIndicesAlias']; ensureAuthorized?: EnsureAuthorized; } @@ -155,21 +155,26 @@ const ensureAuthorizedToUntrack = async (params: SetAlertsToUntrackedParamsWithD }; const getAuthorizedAlertsIndices = async ({ - featureIds, - getAuthorizedRuleTypes, + ruleTypeIds, + getAllAuthorizedRuleTypesFindOperation, getAlertIndicesAlias, spaceId, logger, }: SetAlertsToUntrackedParamsWithDep) => { try { - const authorizedRuleTypes = - (await getAuthorizedRuleTypes?.(AlertingAuthorizationEntity.Alert, new Set(featureIds))) || - []; - const indices = getAlertIndicesAlias?.( - authorizedRuleTypes.map((art: { id: string }) => art.id), - spaceId - ); - return indices; + const authorizedRuleTypes = await getAllAuthorizedRuleTypesFindOperation?.({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + ruleTypeIds, + }); + + if (authorizedRuleTypes) { + return getAlertIndicesAlias?.( + Array.from(authorizedRuleTypes.keys()).map((id) => id), + spaceId + ); + } + + return []; } catch (error) { const errMessage = `Failed to get authorized rule types to untrack alerts by query: ${error}`; logger.error(errMessage); diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts index dab9d5f38f03..ade1a1f35b59 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.test.ts @@ -241,12 +241,15 @@ describe('findBackfill()', () => { test('should successfully find backfill with no filter', async () => { const result = await rulesClient.findBackfill({ page: 1, perPage: 10 }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -286,12 +289,15 @@ describe('findBackfill()', () => { test('should successfully find backfill with rule id', async () => { const result = await rulesClient.findBackfill({ page: 1, perPage: 10, ruleIds: 'abc' }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -336,12 +342,15 @@ describe('findBackfill()', () => { start: '2024-03-29T02:07:55Z', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -400,12 +409,15 @@ describe('findBackfill()', () => { end: '2024-03-29T02:07:55Z', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -465,12 +477,15 @@ describe('findBackfill()', () => { end: '2024-03-29T02:07:55Z', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -546,12 +561,15 @@ describe('findBackfill()', () => { ruleIds: 'abc', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ @@ -627,12 +645,15 @@ describe('findBackfill()', () => { sortOrder: 'asc', }); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'ad_hoc_run_params.attributes.rule.consumer', - ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'ad_hoc_run_params.attributes.rule.consumer', + ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts index 522128d0385f..3482d854bda1 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/find/find_backfill.ts @@ -40,16 +40,16 @@ export async function findBackfill( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'ad_hoc_run_params.attributes.rule.alertTypeId', consumer: 'ad_hoc_run_params.attributes.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( adHocRunAuditEvent({ diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts index b8f1e5af9c86..a0a79421c735 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.test.ts @@ -251,12 +251,15 @@ describe('scheduleBackfill()', () => { const mockData = [getMockData(), getMockData({ ruleId: '2', end: '2023-11-17T08:00:00.000Z' })]; const result = await rulesClient.scheduleBackfill(mockData); - expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith('rule', { - fieldNames: { - consumer: 'alert.attributes.consumer', - ruleTypeId: 'alert.attributes.alertTypeId', + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'alert.attributes.consumer', + ruleTypeId: 'alert.attributes.alertTypeId', + }, + type: 'kql', }, - type: 'kql', }); expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ diff --git a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts index 534262aa31c3..2dec1a78e317 100644 --- a/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts +++ b/x-pack/plugins/alerting/server/application/backfill/methods/schedule/schedule_backfill.ts @@ -46,10 +46,10 @@ export async function scheduleBackfill( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts index 57fb2bf8f48a..23ccbf97cb6c 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.test.ts @@ -23,7 +23,7 @@ import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; import { getBeforeSetup, setGlobalDate } from '../../../../rules_client/tests/lib'; import { RegistryRuleType } from '../../../../rule_type_registry'; -import { fromKueryExpression, nodeTypes } from '@kbn/es-query'; +import { fromKueryExpression, nodeTypes, toKqlExpression } from '@kbn/es-query'; import { RecoveredActionGroup } from '../../../../../common'; import { DefaultRuleAggregationResult } from '../../../../routes/rule/apis/aggregate/types'; import { defaultRuleAggregationFactory } from '.'; @@ -78,24 +78,28 @@ beforeEach(() => { setGlobalDate(); describe('aggregate()', () => { - const listedTypes = new Set([ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + const listedTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], ]); + beforeEach(() => { authorization.getFindAuthorizationFilter.mockResolvedValue({ ensureRuleTypeIsAuthorized() {}, @@ -161,26 +165,16 @@ describe('aggregate()', () => { }); ruleTypeRegistry.list.mockReturnValue(listedTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { - id: 'myType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - category: 'test', - producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + ], ]) ); }); @@ -394,6 +388,34 @@ describe('aggregate()', () => { ]); }); + test('combines the filters with the auth filter correctly', async () => { + const authFilter = fromKueryExpression( + 'alert.attributes.alertTypeId:myType and alert.attributes.consumer:myApp' + ); + + authorization.getFindAuthorizationFilter.mockResolvedValue({ + filter: authFilter, + ensureRuleTypeIsAuthorized() {}, + }); + + const rulesClient = new RulesClient(rulesClientParams); + await rulesClient.aggregate({ + options: { + ruleTypeIds: ['my-rule-type-id'], + consumers: ['bar'], + filter: `alert.attributes.tags: ['bar']`, + }, + aggs: defaultRuleAggregationFactory(), + }); + + const finalFilter = unsecuredSavedObjectsClient.find.mock.calls[0][0].filter; + + expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledTimes(1); + expect(toKqlExpression(finalFilter)).toMatchInlineSnapshot( + `"((alert.attributes.tags: ['bar'] AND alert.attributes.alertTypeId: my-rule-type-id AND alert.attributes.consumer: bar) AND (alert.attributes.alertTypeId: myType AND alert.attributes.consumer: myApp))"` + ); + }); + test('logs audit event when not authorized to aggregate rules', async () => { const rulesClient = new RulesClient({ ...rulesClientParams, auditLogger }); authorization.getFindAuthorizationFilter.mockRejectedValue(new Error('Unauthorized')); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts index 9011b971e629..307e27184ca7 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/aggregate_rules.ts @@ -5,8 +5,13 @@ * 2.0. */ -import { KueryNode, nodeBuilder } from '@kbn/es-query'; -import { isEmpty } from 'lodash'; +import type { KueryNode } from '@kbn/es-query'; +import { + buildConsumersFilter, + buildRuleTypeIdsFilter, + combineFilterWithAuthorizationFilter, + combineFilters, +} from '../../../../rules_client/common/filters'; import { findRulesSo } from '../../../../data/rule'; import { AlertingAuthorizationEntity } from '../../../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; @@ -22,15 +27,15 @@ export async function aggregateRules>( params: AggregateParams ): Promise { const { options = {}, aggs } = params; - const { filter, page = 1, perPage = 0, filterConsumers, ...restOptions } = options; + const { filter, page = 1, perPage = 0, ruleTypeIds, consumers, ...restOptions } = options; let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts, - isEmpty(filterConsumers) ? undefined : new Set(filterConsumers) - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); + validateRuleAggregationFields(aggs); aggregateOptionsSchema.validate(options); } catch (error) { @@ -45,15 +50,21 @@ export async function aggregateRules>( const { filter: authorizationFilter } = authorizationTuple; const filterKueryNode = buildKueryNodeFilter(filter); + const ruleTypeIdsFilter = buildRuleTypeIdsFilter(ruleTypeIds); + const consumersFilter = buildConsumersFilter(consumers); + const combinedFilters = combineFilters( + [filterKueryNode, ruleTypeIdsFilter, consumersFilter], + 'and' + ); const { aggregations } = await findRulesSo({ savedObjectsClient: context.unsecuredSavedObjectsClient, savedObjectsFindOptions: { ...restOptions, - filter: - authorizationFilter && filterKueryNode - ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) - : authorizationFilter, + filter: combineFilterWithAuthorizationFilter( + combinedFilters, + authorizationFilter as KueryNode + ), page, perPage, aggs, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts index 7250094160a0..d26f48e2462f 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/schemas/aggregate_options_schema.ts @@ -16,7 +16,8 @@ export const aggregateOptionsSchema = schema.object({ id: schema.string(), }) ), - filterConsumers: schema.maybe(schema.arrayOf(schema.string())), + ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), // filter type is `string | KueryNode`, but `KueryNode` has no schema to import yet filter: schema.maybe( schema.oneOf([schema.string(), schema.recordOf(schema.string(), schema.any())]) diff --git a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts index 2156fb91e877..e146928efcff 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/aggregate/types/index.ts @@ -9,17 +9,9 @@ import { TypeOf } from '@kbn/config-schema'; import { KueryNode } from '@kbn/es-query'; import { aggregateOptionsSchema } from '../schemas'; -type AggregateOptionsSchemaTypes = TypeOf; export type AggregateOptions = TypeOf & { - search?: AggregateOptionsSchemaTypes['search']; - defaultSearchOperator?: AggregateOptionsSchemaTypes['defaultSearchOperator']; - searchFields?: AggregateOptionsSchemaTypes['searchFields']; - hasReference?: AggregateOptionsSchemaTypes['hasReference']; // Adding filter as in schema it's defined as any instead of KueryNode filter?: string | KueryNode; - page?: AggregateOptionsSchemaTypes['page']; - perPage?: AggregateOptionsSchemaTypes['perPage']; - filterConsumers?: string[]; }; export interface AggregateParams { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts index 8868065fa43a..f7d83545ec19 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_edit/bulk_edit_rules.ts @@ -132,10 +132,10 @@ export async function bulkEditRules( const qNodeFilter = ids ? convertRuleIdsToKueryNode(ids) : qNodeQueryFilter; let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts index 304037782f6d..e93f82da28cb 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/bulk_untrack_alerts.ts @@ -41,12 +41,11 @@ async function bulkUntrackAlertsWithOCC(context: RulesClientContext, params: Bul if (!context.alertsService) throw new Error('unable to access alertsService'); const result = await context.alertsService.setAlertsToUntracked({ ...params, - featureIds: params.featureIds || [], + ruleTypeIds: params.ruleTypeIds || [], spaceId: context.spaceId, getAlertIndicesAlias: context.getAlertIndicesAlias, - getAuthorizedRuleTypes: context.authorization.getAuthorizedRuleTypes.bind( - context.authorization - ), + getAllAuthorizedRuleTypesFindOperation: + context.authorization.getAllAuthorizedRuleTypesFindOperation.bind(context.authorization), ensureAuthorized: async ({ ruleTypeId, consumer, diff --git a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts index f597d9f5b6fa..8a4affbc83c3 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/bulk_untrack/schemas/bulk_untrack_body_schema.ts @@ -11,5 +11,5 @@ export const bulkUntrackBodySchema = schema.object({ indices: schema.maybe(schema.arrayOf(schema.string())), alertUuids: schema.maybe(schema.arrayOf(schema.string())), query: schema.maybe(schema.arrayOf(schema.any())), - featureIds: schema.maybe(schema.arrayOf(schema.string())), + ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts index 34e13b65d76c..3514f8ce2237 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/create/create_rule.ts @@ -84,6 +84,12 @@ export async function createRule( throw Boom.badRequest(`Error validating create data - ${error.message}`); } + /** + * ruleTypeRegistry.get will throw a 400 (Bad request) + * error if the rule type is not registered. + */ + context.ruleTypeRegistry.get(data.alertTypeId); + let validationPayload: ValidateScheduleLimitResult = null; if (data.enabled) { validationPayload = await validateScheduleLimit({ diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts index e6bfd3408a53..369549d839c7 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.test.ts @@ -15,7 +15,7 @@ import { import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; import { ruleTypeRegistryMock } from '../../../../rule_type_registry.mock'; import { alertingAuthorizationMock } from '../../../../authorization/alerting_authorization.mock'; -import { nodeTypes, fromKueryExpression } from '@kbn/es-query'; +import { nodeTypes, fromKueryExpression, toKqlExpression } from '@kbn/es-query'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; import { AlertingAuthorization } from '../../../../authorization/alerting_authorization'; @@ -92,23 +92,26 @@ jest.mock('../../../../rules_client/common/map_sort_field', () => ({ })); describe('find()', () => { - const listedTypes = new Set([ - { - actionGroups: [], - recoveryActionGroup: RecoveredActionGroup, - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + const listedTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + recoveryActionGroup: RecoveredActionGroup, + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], ]); beforeEach(() => { @@ -163,26 +166,16 @@ describe('find()', () => { }); ruleTypeRegistry.list.mockReturnValue(listedTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { - id: 'myType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - recoveryActionGroup: RecoveredActionGroup, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - category: 'test', - producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + ], ]) ); }); @@ -235,7 +228,7 @@ describe('find()', () => { Array [ Object { "fields": undefined, - "filter": null, + "filter": undefined, "sortField": undefined, "type": "alert", }, @@ -349,7 +342,7 @@ describe('find()', () => { Array [ Object { "fields": undefined, - "filter": null, + "filter": undefined, "sortField": undefined, "type": "alert", }, @@ -461,7 +454,7 @@ describe('find()', () => { Array [ Object { "fields": undefined, - "filter": null, + "filter": undefined, "sortField": undefined, "type": "alert", }, @@ -513,13 +506,34 @@ describe('find()', () => { authorization.getFindAuthorizationFilter.mockResolvedValue({ ensureRuleTypeIsAuthorized() {}, }); + const injectReferencesFn = jest.fn().mockReturnValue({ bar: true, parameterThatIsSavedObjectId: '9', }); - ruleTypeRegistry.list.mockReturnValue( - new Set([ - ...listedTypes, + + const ruleTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + recoveryActionGroup: RecoveredActionGroup, + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], + [ + '123', { actionGroups: [], recoveryActionGroup: RecoveredActionGroup, @@ -536,8 +550,10 @@ describe('find()', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }, - ]) - ); + ], + ]); + + ruleTypeRegistry.list.mockReturnValue(ruleTypes); ruleTypeRegistry.get.mockImplementationOnce(() => ({ id: 'myType', name: 'myType', @@ -750,12 +766,33 @@ describe('find()', () => { authorization.getFindAuthorizationFilter.mockResolvedValue({ ensureRuleTypeIsAuthorized() {}, }); + const injectReferencesFn = jest.fn().mockImplementation(() => { throw new Error('something went wrong!'); }); - ruleTypeRegistry.list.mockReturnValue( - new Set([ - ...listedTypes, + + const ruleTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + recoveryActionGroup: RecoveredActionGroup, + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], + [ + '123', { actionGroups: [], recoveryActionGroup: RecoveredActionGroup, @@ -772,8 +809,10 @@ describe('find()', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }, - ]) - ); + ], + ]); + + ruleTypeRegistry.list.mockReturnValue(ruleTypes); ruleTypeRegistry.get.mockImplementationOnce(() => ({ id: 'myType', name: 'myType', @@ -792,6 +831,7 @@ describe('find()', () => { }, validLegacyConsumers: [], })); + ruleTypeRegistry.get.mockImplementationOnce(() => ({ id: '123', name: 'Test', @@ -987,12 +1027,58 @@ describe('find()', () => { expect(unsecuredSavedObjectsClient.find).toHaveBeenCalledWith({ fields: ['tags', 'alertTypeId', 'consumer'], - filter: null, + filter: undefined, sortField: undefined, type: RULE_SAVED_OBJECT_TYPE, }); expect(ensureRuleTypeIsAuthorized).toHaveBeenCalledWith('myType', 'myApp', 'rule'); }); + + test('calls getFindAuthorizationFilter correctly', async () => { + authorization.getFindAuthorizationFilter.mockResolvedValue({ + ensureRuleTypeIsAuthorized() {}, + }); + + const rulesClient = new RulesClient(rulesClientParams); + await rulesClient.find({ options: { ruleTypeIds: ['foo'], consumers: ['bar'] } }); + + expect(authorization.getFindAuthorizationFilter).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + filterOpts: { + fieldNames: { + consumer: 'alert.attributes.consumer', + ruleTypeId: 'alert.attributes.alertTypeId', + }, + type: 'kql', + }, + }); + }); + + test('combines the filters with the auth filter correctly', async () => { + const filter = fromKueryExpression( + 'alert.attributes.alertTypeId:myType and alert.attributes.consumer:myApp' + ); + + authorization.getFindAuthorizationFilter.mockResolvedValue({ + filter, + ensureRuleTypeIsAuthorized() {}, + }); + + const rulesClient = new RulesClient(rulesClientParams); + await rulesClient.find({ + options: { + ruleTypeIds: ['foo'], + consumers: ['bar'], + filter: `alert.attributes.tags: ['bar']`, + }, + }); + + const finalFilter = unsecuredSavedObjectsClient.find.mock.calls[0][0].filter; + + expect(toKqlExpression(finalFilter)).toMatchInlineSnapshot( + `"((alert.attributes.tags: ['bar'] AND alert.attributes.alertTypeId: foo AND alert.attributes.consumer: bar) AND (alert.attributes.alertTypeId: myType AND alert.attributes.consumer: myApp))"` + ); + }); }); describe('auditLogger', () => { diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts index 7e4efb2665f6..26441a447447 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/find_rules.ts @@ -6,11 +6,17 @@ */ import Boom from '@hapi/boom'; -import { isEmpty, pick } from 'lodash'; -import { KueryNode, nodeBuilder } from '@kbn/es-query'; +import { pick } from 'lodash'; +import { KueryNode } from '@kbn/es-query'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import { + buildConsumersFilter, + buildRuleTypeIdsFilter, + combineFilterWithAuthorizationFilter, + combineFilters, +} from '../../../../rules_client/common/filters'; +import { AlertingAuthorizationEntity } from '../../../../authorization/types'; import { SanitizedRule, Rule as DeprecatedRule, RawRule } from '../../../../types'; -import { AlertingAuthorizationEntity } from '../../../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../../../../rules_client/common/audit_events'; import { mapSortField, @@ -46,7 +52,7 @@ export async function findRules( ): Promise> { const { options, excludeFromPublicApi = false, includeSnoozeData = false } = params || {}; - const { fields, filterConsumers, ...restOptions } = options || {}; + const { fields, ruleTypeIds, consumers, ...restOptions } = options || {}; try { if (params) { @@ -58,11 +64,10 @@ export async function findRules( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts, - isEmpty(filterConsumers) ? undefined : new Set(filterConsumers) - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ @@ -76,6 +81,7 @@ export async function findRules( const { filter: authorizationFilter, ensureRuleTypeIsAuthorized } = authorizationTuple; const filterKueryNode = buildKueryNodeFilter(restOptions.filter as string | KueryNode); let sortField = mapSortField(restOptions.sortField); + if (excludeFromPublicApi) { try { validateOperationOnAttributes( @@ -111,6 +117,18 @@ export async function findRules( modifyFilterKueryNode({ astFilter: filterKueryNode }); } + const ruleTypeIdsFilter = buildRuleTypeIdsFilter(ruleTypeIds); + const consumersFilter = buildConsumersFilter(consumers); + const combinedFilters = combineFilters( + [filterKueryNode, ruleTypeIdsFilter, consumersFilter], + 'and' + ); + + const finalFilter = combineFilterWithAuthorizationFilter( + combinedFilters, + authorizationFilter as KueryNode + ); + const { page, per_page: perPage, @@ -121,10 +139,7 @@ export async function findRules( savedObjectsFindOptions: { ...modifiedOptions, sortField, - filter: - (authorizationFilter && filterKueryNode - ? nodeBuilder.and([filterKueryNode, authorizationFilter as KueryNode]) - : authorizationFilter) ?? filterKueryNode, + filter: finalFilter, fields: fields ? includeFieldsRequiredForAuthentication(fields) : fields, }, }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts index b766ffc283bb..aec95d7f2c06 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/schemas/find_rules_schemas.ts @@ -28,7 +28,8 @@ export const findRulesOptionsSchema = schema.object( filter: schema.maybe( schema.oneOf([schema.string(), schema.recordOf(schema.string(), schema.any())]) ), - filterConsumers: schema.maybe(schema.arrayOf(schema.string())), + ruleTypeIds: schema.maybe(schema.arrayOf(schema.string())), + consumers: schema.maybe(schema.arrayOf(schema.string())), }, { unknowns: 'allow' } ); @@ -37,5 +38,4 @@ export const findRulesParamsSchema = schema.object({ options: schema.maybe(findRulesOptionsSchema), excludeFromPublicApi: schema.maybe(schema.boolean()), includeSnoozeData: schema.maybe(schema.boolean()), - featureIds: schema.maybe(schema.arrayOf(schema.string())), }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts b/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts index 615a5b5db867..77694f150c5a 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/find/types/find_rules_types.ts @@ -9,5 +9,4 @@ import { TypeOf } from '@kbn/config-schema'; import { findRulesOptionsSchema, findRulesParamsSchema } from '../schemas'; export type FindRulesOptions = TypeOf; - export type FindRulesParams = TypeOf; diff --git a/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.test.ts new file mode 100644 index 000000000000..fd0a641df022 --- /dev/null +++ b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.test.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { rulesClientContextMock } from '../../../../rules_client/rules_client.mock'; +import { RulesClient } from '../../../../rules_client'; + +describe('listRuleTypes', () => { + const rulesClientContext = rulesClientContextMock.create(); + let rulesClient: RulesClient; + + beforeEach(async () => { + jest.clearAllMocks(); + rulesClient = new RulesClient(rulesClientContext); + + rulesClientContext.ruleTypeRegistry.list = jest.fn().mockReturnValue( + new Map([ + ['apm.anomaly', { name: 'Anomaly' }], + ['.es-query', { name: 'ES rule type' }], + ]) + ); + rulesClientContext.ruleTypeRegistry.has = jest + .fn() + .mockImplementation((ruleTypeId: string) => ruleTypeId === '.es-query'); + + rulesClientContext.authorization.getAuthorizedRuleTypes = jest.fn().mockResolvedValue( + new Map([ + ['.es-query', { authorizedConsumers: { all: true, read: true } }], + ['.not-exist', { authorizedConsumers: { all: true, read: true } }], + ]) + ); + }); + + it('authorizes correctly', async () => { + await rulesClient.listRuleTypes(); + + expect(rulesClientContext.authorization.getAuthorizedRuleTypes).toHaveBeenCalledWith({ + authorizationEntity: 'rule', + operations: ['get', 'create'], + ruleTypeIds: ['apm.anomaly', '.es-query'], + }); + }); + + it('returns the authorized rule types correctly and does not return non authorized or non existing rule types', async () => { + const res = await rulesClient.listRuleTypes(); + + expect(res).toEqual([{ name: 'ES rule type', authorizedConsumers: { all: true, read: true } }]); + }); +}); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts index 66256b4b7d7e..4bcb6fdece3e 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/rule_types/rule_types.ts @@ -6,16 +6,28 @@ */ import { - WriteOperations, - ReadOperations, AlertingAuthorizationEntity, + ReadOperations, + RegistryAlertTypeWithAuth, + WriteOperations, } from '../../../../authorization'; import { RulesClientContext } from '../../../../rules_client/types'; -export async function listRuleTypes(context: RulesClientContext) { - return await context.authorization.filterByRuleTypeAuthorization( - context.ruleTypeRegistry.list(), - [ReadOperations.Get, WriteOperations.Create], - AlertingAuthorizationEntity.Rule - ); +export async function listRuleTypes( + context: RulesClientContext +): Promise { + const registeredRuleTypes = context.ruleTypeRegistry.list(); + + const authorizedRuleTypes = await context.authorization.getAuthorizedRuleTypes({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + operations: [ReadOperations.Get, WriteOperations.Create], + ruleTypeIds: Array.from(registeredRuleTypes.keys()).map((id) => id), + }); + + return Array.from(authorizedRuleTypes.entries()) + .filter(([id, _]) => context.ruleTypeRegistry.has(id)) + .map(([id, { authorizedConsumers }]) => ({ + ...registeredRuleTypes.get(id)!, + authorizedConsumers, + })); } diff --git a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts index de356c3a2e2b..2a84becfd83d 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.test.ts @@ -66,23 +66,26 @@ const rulesClientParams: jest.Mocked = { isSystemAction: jest.fn(), }; -const listedTypes = new Set([ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, +const listedTypes = new Map([ + [ + 'myType', + { + actionGroups: [], + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, + id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], ]); beforeEach(() => { @@ -118,26 +121,16 @@ describe('getTags()', () => { unsecuredSavedObjectsClient.find.mockResolvedValue(getMockAggregationResult(['a', 'b', 'c'])); ruleTypeRegistry.list.mockReturnValue(listedTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { - id: 'myType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - category: 'test', - producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, + ], ]) ); }); diff --git a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts index c26fae42ce32..84a05ac67057 100644 --- a/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts +++ b/x-pack/plugins/alerting/server/application/rule/methods/tags/get_rule_tags.ts @@ -33,10 +33,10 @@ export async function getRuleTags( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts index e51a5c9b12c7..12e360c7cd64 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.mock.ts @@ -14,12 +14,20 @@ export type AlertingAuthorizationMock = jest.Mocked; const createAlertingAuthorizationMock = () => { const mocked: AlertingAuthorizationMock = { ensureAuthorized: jest.fn(), - filterByRuleTypeAuthorization: jest.fn(), - getAuthorizationFilter: jest.fn(), - getAuthorizedRuleTypes: jest.fn(), - getFindAuthorizationFilter: jest.fn(), - getAugmentedRuleTypesWithAuthorization: jest.fn(), + getAuthorizedRuleTypes: jest.fn().mockResolvedValue(new Map()), + getFindAuthorizationFilter: jest.fn().mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: () => {}, + }), getSpaceId: jest.fn(), + getAllAuthorizedRuleTypes: jest + .fn() + .mockResolvedValue({ hasAllRequested: true, authorizedRuleTypes: new Map() }), + getAllAuthorizedRuleTypesFindOperation: jest.fn().mockResolvedValue(new Map()), + getAuthorizationFilter: jest.fn().mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: () => {}, + }), }; return mocked; }; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts index f1cfb99a6daa..9c470823362d 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.test.ts @@ -5,75 +5,53 @@ * 2.0. */ -import { KueryNode, fromKueryExpression, toKqlExpression } from '@kbn/es-query'; +import Boom from '@hapi/boom'; +import { KueryNode, toKqlExpression } from '@kbn/es-query'; import { KibanaRequest } from '@kbn/core/server'; import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; import { securityMock } from '@kbn/security-plugin/server/mocks'; -import { - FeaturesPluginStart as FeaturesStartContract, - KibanaFeature, -} from '@kbn/features-plugin/server'; +import { KibanaFeature } from '@kbn/features-plugin/server'; import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; -import { - AlertingAuthorization, - WriteOperations, - ReadOperations, - AlertingAuthorizationEntity, -} from './alerting_authorization'; -import { v4 as uuidv4 } from 'uuid'; -import { RecoveredActionGroup } from '../../common'; -import { NormalizedRuleType, RegistryRuleType } from '../rule_type_registry'; +import { AlertingAuthorization } from './alerting_authorization'; import { AlertingAuthorizationFilterType } from './alerting_authorization_kuery'; -import { schema } from '@kbn/config-schema'; - -const ruleTypeRegistry = ruleTypeRegistryMock.create(); -const features: jest.Mocked = featuresPluginMock.createStart(); -const request = {} as KibanaRequest; - -const getSpace = jest.fn(); -const getSpaceId = () => 'space1'; +import { httpServerMock } from '@kbn/core-http-server-mocks'; +import { CheckPrivilegesResponse } from '@kbn/security-plugin-types-server'; +import type { FeaturesPluginStart } from '@kbn/features-plugin/server'; +import { WriteOperations, AlertingAuthorizationEntity, ReadOperations } from './types'; +import { AlertingKibanaPrivilege } from '@kbn/features-plugin/common/alerting_kibana_privilege'; const mockAuthorizationAction = ( - type: string, - app: string, - alertingType: string, + ruleType: string, + consumer: string, + entity: string, operation: string -) => `${type}/${app}/${alertingType}/${operation}`; -function mockSecurity() { - const security = securityMock.createSetup(); - const authorization = security.authz; - // typescript is having trouble inferring jest's automocking - ( - authorization.actions.alerting.get as jest.MockedFunction< - typeof authorization.actions.alerting.get - > - ).mockImplementation(mockAuthorizationAction); - authorization.mode.useRbacForRequest.mockReturnValue(true); - return { authorization }; -} +) => `${ruleType}/${consumer}/${entity}/${operation}`; -function mockFeature(appName: string, typeName?: string | string[]) { - const typeNameArray = typeName ? (Array.isArray(typeName) ? typeName : [typeName]) : undefined; +function mockFeatureWithConsumers( + appName: string, + alertingFeatures?: AlertingKibanaPrivilege, + subFeature?: boolean +) { return new KibanaFeature({ id: appName, name: appName, app: [], category: { id: 'foo', label: 'foo' }, - ...(typeNameArray + ...(alertingFeatures ? { - alerting: typeNameArray, + alerting: alertingFeatures, } : {}), privileges: { all: { - ...(typeNameArray + ...(alertingFeatures ? { alerting: { rule: { - all: typeNameArray, + all: alertingFeatures, }, alert: { - all: typeNameArray, + all: alertingFeatures, }, }, } @@ -85,14 +63,14 @@ function mockFeature(appName: string, typeName?: string | string[]) { ui: [], }, read: { - ...(typeNameArray + ...(alertingFeatures ? { alerting: { rule: { - read: typeNameArray, + read: alertingFeatures, }, alert: { - read: typeNameArray, + read: alertingFeatures, }, }, } @@ -104,2480 +82,2219 @@ function mockFeature(appName: string, typeName?: string | string[]) { ui: [], }, }, - }); -} - -function mockFeatureWithSubFeature(appName: string, typeName: string) { - return new KibanaFeature({ - id: appName, - name: appName, - app: [], - category: { id: 'foo', label: 'foo' }, - ...(typeName + ...(subFeature ? { - alerting: [typeName], + subFeatures: [ + { + name: appName, + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'doSomethingAlertRelated', + name: 'sub feature alert', + includeIn: 'all', + alerting: { + rule: { + all: alertingFeatures, + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: ['doSomethingAlertRelated'], + }, + { + id: 'doSomethingAlertRelated', + name: 'sub feature alert', + includeIn: 'read', + alerting: { + rule: { + read: alertingFeatures, + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: ['doSomethingAlertRelated'], + }, + ], + }, + ], + }, + ], } : {}), - privileges: { - all: { - savedObject: { - all: [], - read: [], - }, - ui: [], - }, - read: { - savedObject: { - all: [], - read: [], - }, - ui: [], - }, - }, - subFeatures: [ - { - name: appName, - privilegeGroups: [ - { - groupType: 'independent', - privileges: [ - { - id: 'doSomethingAlertRelated', - name: 'sub feature alert', - includeIn: 'all', - alerting: { - rule: { - all: [typeName], - }, - }, - savedObject: { - all: [], - read: [], - }, - ui: ['doSomethingAlertRelated'], - }, - { - id: 'doSomethingAlertRelated', - name: 'sub feature alert', - includeIn: 'read', - alerting: { - rule: { - read: [typeName], - }, - }, - savedObject: { - all: [], - read: [], - }, - ui: ['doSomethingAlertRelated'], - }, - ], - }, - ], - }, - ], }); } -const myAppFeature = mockFeature('myApp', 'myType'); -const myOtherAppFeature = mockFeature('myOtherApp', 'myType'); -const myAppWithSubFeature = mockFeatureWithSubFeature('myAppWithSubFeature', 'myType'); -const myFeatureWithoutAlerting = mockFeature('myOtherApp'); - -beforeEach(() => { - jest.resetAllMocks(); - ruleTypeRegistry.get.mockImplementation((id) => ({ - id, - name: 'My Alert Type', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - async executor() { - return { state: {} }; - }, - category: 'test', - producer: 'myApp', - validate: { - params: schema.any(), - }, - validLegacyConsumers: [], - })); - features.getKibanaFeatures.mockReturnValue([ - myAppFeature, - myOtherAppFeature, - myAppWithSubFeature, - myFeatureWithoutAlerting, - ]); - getSpace.mockResolvedValue(undefined); -}); +type CheckPrivilegesResponseWithoutES = Omit & { + privileges: Omit; +}; describe('AlertingAuthorization', () => { - describe('constructor', () => { - test(`fetches the user's current space`, async () => { - const space = { - id: uuidv4(), - name: uuidv4(), - disabledFeatures: [], - }; - getSpace.mockResolvedValue(space); + const getSpace = jest.fn(); + const getSpaceId = () => 'space1'; + const allRegisteredConsumers = new Set(); + const ruleTypesConsumersMap = new Map>(); + + const checkPrivileges = jest.fn, []>(async () => ({ + username: 'elastic', + hasAllRequested: true, + privileges: { kibana: [] }, + })); + + const ruleTypeIds = ['rule-type-id-1', 'rule-type-id-2', 'rule-type-id-3', 'rule-type-id-4']; + + let request: KibanaRequest; + let ruleTypeRegistry = ruleTypeRegistryMock.create(); + let securityStart: ReturnType; + let features: jest.Mocked; + + beforeEach(() => { + jest.clearAllMocks(); + allRegisteredConsumers.clear(); + allRegisteredConsumers.clear(); + ruleTypesConsumersMap.clear(); + + securityStart = securityMock.createStart(); + securityStart.authz.mode.useRbacForRequest.mockReturnValue(true); + securityStart.authz.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + request = httpServerMock.createKibanaRequest(); + getSpace.mockResolvedValue(undefined); + + features = featuresPluginMock.createStart(); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('feature-id-1', [ + { + ruleTypeId: 'rule-type-id-1', + consumers: ['alerts', 'consumer-a'], + }, + { ruleTypeId: 'rule-type-id-2', consumers: ['alerts', 'consumer-b'] }, + ]), + mockFeatureWithConsumers('feature-id-2', [ + { + ruleTypeId: 'rule-type-id-1', + consumers: ['alerts', 'consumer-b'], + }, + { + ruleTypeId: 'rule-type-id-3', + consumers: ['alerts', 'consumer-c'], + }, + ]), + mockFeatureWithConsumers('feature-id-3', [ + { + ruleTypeId: 'rule-type-id-4', + consumers: ['consumer-d'], + }, + ]), + ]); + + const alertingGet = securityStart.authz.actions.alerting.get as jest.Mock; + alertingGet.mockImplementation(mockAuthorizationAction); + + ruleTypeRegistry = ruleTypeRegistryMock.create(); + ruleTypeRegistry.getAllTypes.mockReturnValue(ruleTypeIds); + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => + ruleTypeIds.includes(ruleTypeId) + ); + + // @ts-expect-error: only the id is needed for the tests + ruleTypeRegistry.get.mockImplementation((ruleTypeId: string) => ({ id: ruleTypeId })); + }); + + describe('create', () => { + beforeEach(() => { + jest.clearAllMocks(); + securityStart = securityMock.createStart(); + features = featuresPluginMock.createStart(); + + getSpace.mockReturnValue({ id: 'default', name: 'Default', disabledFeatures: [] }); + features.getKibanaFeatures.mockReturnValue([mockFeatureWithConsumers('my-feature-1')]); + }); + + it('creates an AlertingAuthorization object', async () => { + expect.assertions(2); - new AlertingAuthorization({ + const authPromise = AlertingAuthorization.create({ request, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - expect(getSpace).toHaveBeenCalledWith(request); + await expect(authPromise).resolves.toBeDefined(); + await expect(authPromise).resolves.not.toThrow(); }); - }); - describe('ensureAuthorized', () => { - test('is a no-op when there is no authorization api', async () => { - const alertAuthorization = new AlertingAuthorization({ + it('creates an AlertingAuthorization object without spaces', async () => { + getSpace.mockReturnValue(undefined); + expect.assertions(2); + + const authPromise = AlertingAuthorization.create({ request, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, + await expect(authPromise).resolves.toBeDefined(); + await expect(authPromise).resolves.not.toThrow(); + }); + + it('filters out disabled spaces and features without alerting', async () => { + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: ['my-feature-1'], }); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['consumer-c', 'consumer-d'] }, + ]), + mockFeatureWithConsumers('my-feature-3'), + mockFeatureWithConsumers('my-feature-4', []), + ]); - test('is a no-op when the security license is disabled', async () => { - const { authorization } = mockSecurity(); - authorization.mode.useRbacForRequest.mockReturnValue(false); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, ruleTypeRegistry, - authorization, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.allRegisteredConsumers).toMatchInlineSnapshot(` + Set { + "consumer-c", + "consumer-d", + } + `); + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.ruleTypesConsumersMap).toMatchInlineSnapshot(` + Map { + "rule-type-2" => Set { + "consumer-c", + "consumer-d", + }, + } + `); + }); + + it('removes duplicated consumers', async () => { + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: [], }); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b', 'consumer-a'] }, + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-c'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-c'] }, + ]), + ]); - test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when producer and consumer are the same', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.allRegisteredConsumers).toMatchInlineSnapshot(` + Set { + "consumer-a", + "consumer-b", + "consumer-c", + } + `); + }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, + it('removes duplicated ruleTypes and consumers', async () => { + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: [], }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create')], - }); - }); + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b', 'consumer-a'] }, + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-c'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['consumer-a', 'consumer-b', 'consumer-e'] }, + { ruleTypeId: 'rule-type-1', consumers: ['consumer-a', 'consumer-b', 'consumer-d'] }, + ]), + ]); - test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when producer and consumer are the same', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, + authorization: securityStart.authz, }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, - }); + // @ts-expect-error: ruleTypesConsumersMap is a private method of the auth class + expect(auth.ruleTypesConsumersMap).toMatchInlineSnapshot(` + Map { + "rule-type-1" => Set { + "consumer-a", + "consumer-b", + "consumer-d", + }, + "rule-type-2" => Set { + "consumer-a", + "consumer-b", + "consumer-c", + "consumer-e", + }, + } + `); + }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + it('throws an error when a generic error occurs', async () => { + expect.assertions(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'alert', - 'update' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'alert', 'update')], - }); - }); + getSpace.mockRejectedValue(new Error('Error')); - test('ensures the user has privileges to execute rules for the specified rule type and operation without consumer when consumer is alerts', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const authPromise = AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + await expect(authPromise).rejects.toThrow(); + }); - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }); + it.each([403, 404])( + `construct the AlertingAuthorization with empty features if the error is boom and %s`, + async (errorStatusCode: number) => { + getSpace.mockRejectedValue( + new Boom.Boom('Server error', { + statusCode: errorStatusCode, + message: 'my error message', + }) + ); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.ruleTypesConsumersMap).toMatchInlineSnapshot(`Map {}`); + // @ts-expect-error: allRegisteredConsumers is a private method of the auth class + expect(auth.allRegisteredConsumers).toMatchInlineSnapshot(`Set {}`); + } + ); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + it('throws an error if the error is boom but not 403', async () => { + expect.assertions(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' + getSpace.mockRejectedValue( + new Boom.Boom('Server error', { statusCode: 400, message: 'my error message' }) ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create')], - }); - }); - test('ensures the user has privileges to execute alerts for the specified rule type and operation without consumer when consumer is alerts', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - const alertAuthorization = new AlertingAuthorization({ + const authPromise = AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); - - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'alerts', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, + authorization: securityStart.authz, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'alert', - 'update' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'alert', 'update')], - }); + await expect(authPromise).rejects.toThrow(); }); + }); - test('ensures the user has privileges to execute rules for the specified rule type, operation and producer when producer is different from consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + describe('ensureAuthorized', () => { + beforeEach(() => { + jest.clearAllMocks(); + allRegisteredConsumers.clear(); + allRegisteredConsumers.add('myApp'); + }); + it('is a no-op when there is no authorization api', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', + consumer: 'myApp', operation: WriteOperations.Create, entity: AlertingAuthorizationEntity.Rule, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myOtherApp', - 'rule', - 'create' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create')], - }); + expect(checkPrivileges).not.toHaveBeenCalled(); }); - test('ensures the user has privileges to execute alerts for the specified rule type, operation and producer when producer is different from consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + it('is a no-op when the security license is disabled', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, + consumer: 'myApp', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); - - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myOtherApp', - 'alert', - 'update' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update')], - }); + expect(checkPrivileges).not.toHaveBeenCalled(); }); - test('ensures the producer is used for authorization if the consumer is `alerts`', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); - + it('authorized correctly', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'alerts', + consumer: 'myApp', operation: WriteOperations.Create, entity: AlertingAuthorizationEntity.Rule, }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "myType/myApp/rule/create", + ], + }, + ] + `); + }); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' + it('throws if user lacks the required rule privileges for the consumer', async () => { + securityStart.authz.checkPrivilegesDynamicallyWithRequest.mockReturnValue( + jest.fn(async () => ({ hasAllRequested: false })) ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create')], - }); - }); - test('throws if user lacks the required rule privileges for the consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'rule', 'create'), - authorized: true, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', + consumer: 'myApp', operation: WriteOperations.Create, entity: AlertingAuthorizationEntity.Rule, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to create \\"myType\\" rule"` + `"Unauthorized by \\"myApp\\" to create \\"myType\\" rule"` ); }); - test('throws if user lacks the required alert privileges for the consumer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws if user lacks the required alert privileges for the consumer', async () => { + securityStart.authz.checkPrivilegesDynamicallyWithRequest.mockReturnValue( + jest.fn(async () => ({ hasAllRequested: false })) + ); + const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myType', 'myAppRulesOnly', 'alert', 'update'), - authorized: false, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myAppRulesOnly', + consumer: 'myApp', operation: WriteOperations.Update, entity: AlertingAuthorizationEntity.Alert, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myAppRulesOnly\\" to update \\"myType\\" alert"` + `"Unauthorized by \\"myApp\\" to update \\"myType\\" alert"` ); }); - test('throws if user lacks the required privileges for the producer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws if the user has access but the consumer is not registered', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'update'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'update'), - authorized: false, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', - operation: WriteOperations.Update, - entity: AlertingAuthorizationEntity.Alert, + consumer: 'not-exist', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to update \\"myType\\" alert"` + `"Unauthorized by \\"not-exist\\" to create \\"myType\\" rule"` ); }); - test('throws if user lacks the required privileges for both consumer and producer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws when there is no authorization api but the consumer is not registered', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, getSpaceId, - }); - - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'alert', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'alert', 'create'), - authorized: false, - }, - ], - }, + allRegisteredConsumers, + ruleTypesConsumersMap, }); await expect( alertAuthorization.ensureAuthorized({ ruleTypeId: 'myType', - consumer: 'myOtherApp', + consumer: 'not-exist', operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Alert, + entity: AlertingAuthorizationEntity.Rule, }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to create \\"myType\\" alert"` + `"Unauthorized by \\"not-exist\\" to create \\"myType\\" rule"` ); }); - test('checks additional privileges correctly', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('throws when the security license is disabled but the consumer is not registered', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); - - await alertAuthorization.ensureAuthorized({ - ruleTypeId: 'myType', - consumer: 'myApp', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - additionalPrivileges: ['test/create'], - }); + await expect( + alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'not-exist', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"not-exist\\" to create \\"myType\\" rule"` + ); + }); - expect(ruleTypeRegistry.get).toHaveBeenCalledWith('myType'); + it('throws an error when the consumer does not exist because it was from a disabled plugin', async () => { + features.getKibanaFeatures.mockReturnValue([ + mockFeatureWithConsumers('my-feature-1', [ + { ruleTypeId: 'rule-type-1', consumers: ['disabled-feature-consumer'] }, + ]), + mockFeatureWithConsumers('my-feature-2', [ + { ruleTypeId: 'rule-type-2', consumers: ['enabled-feature-consumer'] }, + ]), + ]); - expect(authorization.actions.alerting.get).toHaveBeenCalledTimes(1); - expect(authorization.actions.alerting.get).toHaveBeenCalledWith( - 'myType', - 'myApp', - 'rule', - 'create' - ); - expect(checkPrivileges).toHaveBeenCalledWith({ - kibana: [mockAuthorizationAction('myType', 'myApp', 'rule', 'create'), 'test/create'], + getSpace.mockReturnValue({ + id: 'default', + name: 'Default', + disabledFeatures: ['my-feature-1'], }); - }); - }); - describe('getFindAuthorizationFilter', () => { - const myOtherAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const myAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const mySecondAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType, mySecondAppAlertType]); - test('omits filter when there is no authorization api', async () => { - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, ruleTypeRegistry, - features, - getSpace, getSpaceId, - }); - const { filter, ensureRuleTypeIsAuthorized } = - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - }, - }); - expect(() => ensureRuleTypeIsAuthorized('someMadeUpType', 'myApp', 'rule')).not.toThrow(); - expect(filter).toEqual(undefined); - }); - test('ensureRuleTypeIsAuthorized is no-op when there is no authorization api', async () => { - const alertAuthorization = new AlertingAuthorization({ - request, - ruleTypeRegistry, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - }, - } + + await expect( + auth.ensureAuthorized({ + ruleTypeId: 'rule-type-1', + consumer: 'disabled-feature-consumer', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"disabled-feature-consumer\\" to create \\"rule-type-1\\" rule"` ); - ensureRuleTypeIsAuthorized('someMadeUpType', 'myApp', 'rule'); }); - test('creates a filter based on the privileged types', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myAppAlertType', 'mySecondAppAlertType']), - mockFeature('alerts', 'myOtherAppAlertType'), - myOtherAppFeature, - myAppWithSubFeature, - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: true, - privileges: { kibana: [] }, - }); + + it('checks additional privileges correctly', async () => { const alertAuthorization = new AlertingAuthorization({ request, - authorization, ruleTypeRegistry, - features, - getSpace, + authorization: securityStart.authz, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const filter = ( - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).filter; + await alertAuthorization.ensureAuthorized({ + ruleTypeId: 'myType', + consumer: 'myApp', + operation: WriteOperations.Create, + entity: AlertingAuthorizationEntity.Rule, + additionalPrivileges: ['test/create'], + }); - expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( - `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: mySecondAppAlertType AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)))"` - ); + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "myType/myApp/rule/create", + "test/create", + ], + }, + ] + `); }); - test('throws if user has no privileges to any rule type', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ - { - privilege: mockAuthorizationAction('myType', 'myOtherApp', 'rule', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myType', 'myApp', 'rule', 'create'), - authorized: false, - }, - ], - }, - }); - const alertAuthorization = new AlertingAuthorization({ + }); + + describe('getFindAuthorizationFilter', () => { + it('creates a filter based on the privileged types', async () => { + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized to find rules for any rule types"` - ); - }); - test('creates an `ensureRuleTypeIsAuthorized` function which throws if type is unauthorized', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType']), - mockFeature('myOtherApp', ['myOtherAppAlertType', 'myAppAlertType']), - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'alerts', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'find' - ), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'find'), + authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-b', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'find'), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-2', 'alerts', 'rule', 'find'), + authorized: true, }, - ], - }, - }); - const alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - }, - } - ); - expect(() => { - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'alert'); - }).toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"myOtherApp\\" to find \\"myAppAlertType\\" alert"` - ); - }); - test('creates an `ensureRuleTypeIsAuthorized` function which is no-op if type is authorized', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType']), - mockFeature('myOtherApp', 'myAppAlertType'), - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - checkPrivileges.mockResolvedValueOnce({ - username: 'some-user', - hasAllRequested: false, - privileges: { - kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'find'), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'rule', - 'find' - ), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'find'), + authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'find'), + privilege: mockAuthorizationAction('rule-type-id-3', 'alerts', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'find'), - authorized: true, + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-d', 'rule', 'find'), + authorized: false, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', + + const filter = ( + await auth.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + }, }, - } + }) + ).filter; + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/find", + "rule-type-id-1/consumer-a/rule/find", + "rule-type-id-1/consumer-b/rule/find", + "rule-type-id-2/alerts/rule/find", + "rule-type-id-2/consumer-b/rule/find", + "rule-type-id-3/alerts/rule/find", + "rule-type-id-3/consumer-c/rule/find", + "rule-type-id-4/consumer-d/rule/find", + ], + }, + ] + `); + + expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( + `"((path.to.rule_type_id: rule-type-id-1 AND (consumer-field: alerts OR consumer-field: consumer-a OR consumer-field: consumer-b)) OR (path.to.rule_type_id: rule-type-id-2 AND (consumer-field: alerts OR consumer-field: consumer-b)) OR (path.to.rule_type_id: rule-type-id-3 AND (consumer-field: consumer-c OR consumer-field: alerts)))"` ); - expect(() => { - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); - }).not.toThrow(); }); - test('creates an `logSuccessfulAuthorization` function which logs every authorized type', async () => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType', 'mySecondAppAlertType']), - mockFeature('myOtherApp', ['mySecondAppAlertType', 'myAppAlertType']), - ]); - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + + it('does not throw if the rule type is authorized', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'rule', - 'find' - ), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'find'), authorized: true, }, { - privilege: mockAuthorizationAction('mySecondAppAlertType', 'myApp', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - 'mySecondAppAlertType', - 'myOtherApp', - 'rule', - 'find' - ), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'find'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - const { ensureRuleTypeIsAuthorized } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { + + const { ensureRuleTypeIsAuthorized } = await auth.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - } - ); - expect(() => { - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); - ensureRuleTypeIsAuthorized('mySecondAppAlertType', 'myOtherApp', 'rule'); - ensureRuleTypeIsAuthorized('myAppAlertType', 'myOtherApp', 'rule'); - }).not.toThrow(); + }, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-a', 'rule') + ).not.toThrow(); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-2', 'consumer-b', 'rule') + ).not.toThrow(); }); + }); - // This is a specific use case currently for alerts as data - // Space ids are stored in the alerts documents and even if security is disabled - // still need to consider the users space privileges - test('creates a spaceId only filter if security is disabled, but require space awareness', async () => { - const alertAuthorization = new AlertingAuthorization({ - request, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, + describe('getAuthorizationFilter', () => { + describe('filter', () => { + it('gets the filter correctly with no security and no spaceIds in the fields names', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(filter).toEqual(undefined); }); - const { filter } = await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { - type: AlertingAuthorizationFilterType.ESDSL, - fieldNames: { - ruleTypeId: 'ruleId', - consumer: 'consumer', - spaceIds: 'path.to.space.id', + + // This is a specific use case currently for alerts as data + // Space ids are stored in the alerts documents and even if security is disabled + // still need to consider the users space privileges + it('gets the filter correctly with no security and spaceIds in the fields names', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + spaceIds: 'path.to.space.id', + }, }, - } - ); + operation: ReadOperations.Get, + }); - expect(filter).toEqual({ - bool: { minimum_should_match: 1, should: [{ match: { 'path.to.space.id': 'space1' } }] }, + expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( + `"path.to.space.id: space1"` + ); }); - }); - }); - describe('filterByRuleTypeAuthorization', () => { - const myOtherAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'myOtherApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const myAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType]); - beforeEach(() => { - features.getKibanaFeatures.mockReturnValue([ - mockFeature('myApp', ['myOtherAppAlertType', 'myAppAlertType']), - mockFeature('myOtherApp', ['myAppAlertType', 'myOtherAppAlertType']), - ]); - }); - test('augments a list of types with all features when there is no authorization api', async () => { - features.getKibanaFeatures.mockReturnValue([ - myAppFeature, - myOtherAppFeature, - myAppWithSubFeature, - myFeatureWithoutAlerting, - ]); - const alertAuthorization = new AlertingAuthorization({ - request, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, + it('gets the filter correctly with security disabled', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(filter).toEqual(undefined); }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Rule - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "alerts": Object { - "all": true, - "read": true, + it('gets the filter correctly for all rule types and consumers', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, - "discover": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-b', 'rule', 'get'), + authorized: true, }, - "myApp": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), + authorized: true, }, - "myAppWithSubFeature": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'get'), + authorized: true, }, - "myOtherApp": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-4', 'consumer-d', 'rule', 'get'), + authorized: true, }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { filter } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "alerts": Object { - "all": true, - "read": true, + operation: ReadOperations.Get, + }); + + expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( + `"((ruleId: rule-type-id-1 AND (consumer: consumer-a OR consumer: consumer-b)) OR (ruleId: rule-type-id-2 AND consumer: consumer-b) OR (ruleId: rule-type-id-3 AND consumer: consumer-c) OR (ruleId: rule-type-id-4 AND consumer: consumer-d))"` + ); + }); + + it('throws when the user is not authorized for any rule type', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + await expect( + auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', }, - "discover": Object { - "all": true, - "read": true, + }, + operation: ReadOperations.Get, + }) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unauthorized to get rules for any rule types"` + ); + }); + }); + + describe('ensureRuleTypeIsAuthorized', () => { + it('does not throw if the rule type is authorized', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, - "myApp": Object { - "all": true, - "read": true, + { + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), + authorized: true, }, - "myAppWithSubFeature": Object { - "all": true, - "read": true, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-a', 'rule') + ).not.toThrow(); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-2', 'consumer-b', 'rule') + ).not.toThrow(); + }); + + it('throws if the rule type is not authorized', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, - "myOtherApp": Object { - "all": true, - "read": true, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-2', 'consumer-a', 'rule') + ).toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"consumer-a\\" to get \\"rule-type-id-2\\" rule"` + ); + }); + + it('throws if the rule type is not authorized for the entity', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', + }, + }, + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-a', 'alert') + ).toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"consumer-a\\" to get \\"rule-type-id-1\\" alert"` + ); + }); + + it('throws if the rule type is not authorized for the consumer', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + const { ensureRuleTypeIsAuthorized } = await auth.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'ruleId', + consumer: 'consumer', }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, - } + operation: ReadOperations.Get, + }); + + expect(() => + ensureRuleTypeIsAuthorized('rule-type-id-1', 'consumer-b', 'rule') + ).toThrowErrorMatchingInlineSnapshot( + `"Unauthorized by \\"consumer-b\\" to get \\"rule-type-id-1\\" rule"` + ); + }); + }); + }); + + describe('getAuthorizedRuleTypes', () => { + it('calls checkPrivileges correctly', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + await auth.getAuthorizedRuleTypes({ + ruleTypeIds: ['rule-type-id-1'], + operations: [WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }); + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/create", + "rule-type-id-1/consumer-a/rule/create", + "rule-type-id-1/consumer-b/rule/create", + ], + }, + ] `); }); - test('augments a list of types with consumers under which the operation is authorized', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('returns the authorized rules correctly', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'rule', 'create'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'rule', - 'create' - ), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'rule', 'create'), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'rule', 'create'), + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'create'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Rule - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, + expect( + await auth.getAuthorizedRuleTypes({ + ruleTypeIds: ['rule-type-id-1'], + operations: [WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Map { + "rule-type-id-1" => Object { "authorizedConsumers": Object { - "myApp": Object { + "consumer-a": Object { "all": true, "read": true, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - "myOtherApp": Object { - "all": true, - "read": true, + } + `); + }); + }); + + describe('getAllAuthorizedRuleTypes', () => { + it('get authorized rule types with authorized consumers', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'create'), + authorized: false, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + await auth.getAllAuthorizedRuleTypes({ + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "consumer-b": Object { + "all": false, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + "username": "some-user", + } + `); + }); + + it('calls checkPrivileges with the correct actions', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + await auth.getAllAuthorizedRuleTypes({ + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }); + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/get", + "rule-type-id-1/alerts/rule/create", + "rule-type-id-1/consumer-a/rule/get", + "rule-type-id-1/consumer-a/rule/create", + "rule-type-id-1/consumer-b/rule/get", + "rule-type-id-1/consumer-b/rule/create", + "rule-type-id-2/alerts/rule/get", + "rule-type-id-2/alerts/rule/create", + "rule-type-id-2/consumer-b/rule/get", + "rule-type-id-2/consumer-b/rule/create", + "rule-type-id-3/alerts/rule/get", + "rule-type-id-3/alerts/rule/create", + "rule-type-id-3/consumer-c/rule/get", + "rule-type-id-3/consumer-c/rule/create", + "rule-type-id-4/consumer-d/rule/get", + "rule-type-id-4/consumer-d/rule/create", + ], + }, + ] + `); + }); + }); + + describe('_getAuthorizedRuleTypesWithAuthorizedConsumers', () => { + it('returns all rule types with all consumers as authorized with no authorization', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-3" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-4" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('filters out rule types with no authorization', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [ruleTypeIds[0], ruleTypeIds[1]], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('returns all rule types with all consumers as authorized with disabled authorization', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-3" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-4" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('filters out rule types with disabled authorization', async () => { + securityStart.authz.mode.useRbacForRequest.mockReturnValue(false); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [ruleTypeIds[0], ruleTypeIds[1]], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + "rule-type-id-2" => Object { + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "consumer-a": Object { + "all": true, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, + "consumer-c": Object { + "all": true, + "read": true, + }, + "consumer-d": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + } + `); + }); + + it('get authorized rule types with authorized consumers with read access only', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": false, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + "username": "some-user", + } + `); + }); + + it('get authorized rule types with authorized consumers with full access', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, + }, + }, + }, + "hasAllRequested": true, + "username": "some-user", + } + `); + }); + + it('filters out not requested rule types', async () => { + checkPrivileges.mockResolvedValueOnce({ + username: 'some-user', + hasAllRequested: true, + privileges: { + kibana: [ + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-b', 'rule', 'create'), + authorized: true, + }, + { + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'create'), + authorized: true, + }, + ], + }, + }); + + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); + + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [ruleTypeIds[0], ruleTypeIds[1]], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": false, + "read": true, + }, + "consumer-b": Object { + "all": true, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, + "hasAllRequested": true, + "username": "some-user", } `); }); - test('authorizes user under the `alerts` consumer when they are authorized by the producer', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('returns an empty map with no requested rule types', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'create'), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), + authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map {}, + "hasAllRequested": true, + "username": "some-user", } `); }); - test('augments a list of types with consumers under which multiple operations are authorized', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('get authorized rule types with authorized consumers when some rule types are not authorized', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'create' - ), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'create'), - authorized: false, - }, - { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'get'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'get' - ), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'get'), - authorized: true, + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'create'), + authorized: false, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'get'), + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-c', 'rule', 'get'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create, ReadOperations.Get], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - "myOtherApp": Object { - "all": false, - "read": true, + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": false, - "read": true, - }, - "myOtherApp": Object { - "all": false, - "read": true, + "rule-type-id-3" => Object { + "authorizedConsumers": Object { + "consumer-c": Object { + "all": false, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myAppAlertType", - "producer": "myApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, + "hasAllRequested": true, + "username": "some-user", } `); }); - test('omits types which have no consumers under which the operation is authorized', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('get authorized rule types with authorized consumers when consumers are not valid for a rule type', async () => { checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, { - privilege: mockAuthorizationAction( - 'myOtherAppAlertType', - 'myOtherApp', - 'alert', - 'create' - ), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'create'), authorized: true, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myApp', 'alert', 'create'), + privilege: mockAuthorizationAction('rule-type-id-2', 'consumer-b', 'rule', 'create'), authorized: false, }, { - privilege: mockAuthorizationAction('myAppAlertType', 'myOtherApp', 'alert', 'create'), - authorized: false, + privilege: mockAuthorizationAction('rule-type-id-3', 'consumer-d', 'rule', 'get'), + authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.filterByRuleTypeAuthorization( - new Set([myAppAlertType, myOtherAppAlertType]), - [WriteOperations.Create], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` - Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - "myOtherApp": Object { - "all": true, - "read": true, + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds, + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` + Object { + "authorizedRuleTypes": Map { + "rule-type-id-1" => Object { + "authorizedConsumers": Object { + "consumer-a": Object { + "all": true, + "read": true, + }, }, }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "myOtherApp", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], }, + "hasAllRequested": true, + "username": "some-user", } `); }); - }); - describe('getAugmentedRuleTypesWithAuthorization', () => { - const myOtherAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - enabledInLicense: true, - isExportable: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const myAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - isExportable: true, - hasAlertsMappings: true, - hasFieldsForAAD: true, - validLegacyConsumers: [], - }; - const mySecondAppAlertType: RegistryRuleType = { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - isExportable: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }; - const setOfAlertTypes = new Set([myAppAlertType, myOtherAppAlertType, mySecondAppAlertType]); - beforeEach(() => { - features.getKibanaFeatures.mockReturnValue([mockFeature('myApp', ['myOtherAppAlertType'])]); - }); - test('it returns authorized rule types given a set of feature ids', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('filters out rule types that are not in the rule type registry but registered in the feature', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => false); + checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'find'), + privilege: mockAuthorizationAction('rule-type-id-1', 'consumer-a', 'rule', 'get'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.getAugmentedRuleTypesWithAuthorization( - ['myApp'], - [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['rule-type-id-1'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` Object { - "authorizedRuleTypes": Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": false, - "read": true, - }, - }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "alerts", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, - }, - "hasAllRequested": false, + "authorizedRuleTypes": Map {}, + "hasAllRequested": true, "username": "some-user", } `); }); - test('it returns all authorized if user has read, get and update alert privileges', async () => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); + it('filters out rule types that are registered in the rule type registry but not in the feature', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => true); + checkPrivileges.mockResolvedValueOnce({ username: 'some-user', - hasAllRequested: false, + hasAllRequested: true, privileges: { kibana: [ { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'get'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('myOtherAppAlertType', 'myApp', 'alert', 'update'), + privilege: mockAuthorizationAction('not-exist', 'consumer-a', 'rule', 'get'), authorized: true, }, ], }, }); - const alertAuthorization = new AlertingAuthorization({ + + const auth = await AlertingAuthorization.create({ request, - authorization, ruleTypeRegistry, + getSpaceId, features, getSpace, - getSpaceId, + authorization: securityStart.authz, }); - ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - await expect( - alertAuthorization.getAugmentedRuleTypesWithAuthorization( - ['myApp'], - [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], - AlertingAuthorizationEntity.Alert - ) - ).resolves.toMatchInlineSnapshot(` + expect( + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['not-exist'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, + }) + ).toMatchInlineSnapshot(` Object { - "authorizedRuleTypes": Set { - Object { - "actionGroups": Array [], - "actionVariables": undefined, - "authorizedConsumers": Object { - "myApp": Object { - "all": true, - "read": true, - }, - }, - "category": "test", - "defaultActionGroupId": "default", - "enabledInLicense": true, - "hasAlertsMappings": false, - "hasFieldsForAAD": false, - "id": "myOtherAppAlertType", - "isExportable": true, - "minimumLicenseRequired": "basic", - "name": "myOtherAppAlertType", - "producer": "alerts", - "recoveryActionGroup": Object { - "id": "recovered", - "name": "Recovered", - }, - "validLegacyConsumers": Array [], - }, - }, - "hasAllRequested": false, + "authorizedRuleTypes": Map {}, + "hasAllRequested": true, "username": "some-user", } `); }); - }); - describe('8.11+', () => { - let alertAuthorization: AlertingAuthorization; - - const setOfRuleTypes: RegistryRuleType[] = [ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.esQuery', - name: 'ES Query', - category: 'management', - producer: 'stackAlerts', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: ['discover', 'alerts'], - }, - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.threshold-rule-o11y', - name: 'New threshold 011y', - category: 'observability', - producer: 'observability', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.infrastructure-threshold-o11y', - name: 'Metrics o11y', - category: 'observability', - producer: 'infrastructure', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: ['alerts'], - }, - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: '.logs-threshold-o11y', - name: 'Logs o11y', - category: 'observability', - producer: 'logs', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: ['alerts'], - }, - ]; + it('call checkPrivileges with the correct actions', async () => { + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, + }); - const onlyStackAlertsKibanaPrivileges = [ - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'find'), - authorized: true, - }, - ]; - const only011yKibanaPrivileges = [ - { - privilege: mockAuthorizationAction( - '.infrastructure-threshold-o11y', - 'infrastructure', - 'rule', - 'create' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - '.infrastructure-threshold-o11y', - 'infrastructure', - 'rule', - 'find' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - '.threshold-rule-o11y', - 'infrastructure', - 'rule', - 'create' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction( - '.threshold-rule-o11y', - 'infrastructure', - 'rule', - 'find' - ), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - ]; - const onlyLogsAndStackAlertsKibanaPrivileges = [ - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.esQuery', 'stackAlerts', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.logs-threshold-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'create'), - authorized: true, - }, - { - privilege: mockAuthorizationAction('.threshold-rule-o11y', 'logs', 'rule', 'find'), - authorized: true, - }, - ]; - - beforeEach(async () => { - ruleTypeRegistry.list.mockReturnValue(new Set(setOfRuleTypes)); - ruleTypeRegistry.get.mockImplementation((id: string) => { - if (setOfRuleTypes.some((rt) => rt.id === id)) { - const ruleType = setOfRuleTypes.find((rt) => rt.id === id); - return (ruleType ?? {}) as NormalizedRuleType<{}, {}, {}, {}, {}, '', '', {}>; - } - return {} as NormalizedRuleType<{}, {}, {}, {}, {}, '', '', {}>; + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: [...ruleTypeIds, 'rule-type-not-exist'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, }); - }); - describe('user only access to stack alerts + discover', () => { - beforeEach(() => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.mode.useRbacForRequest.mockReturnValue(true); - - features.getKibanaFeatures.mockReset(); - features.getKibanaFeatures.mockReturnValue([ - mockFeature('stackAlerts', ['.esQuery']), - mockFeature('discover', []), - ]); - checkPrivileges.mockReset(); - checkPrivileges.mockResolvedValue({ - username: 'onlyStack', - hasAllRequested: true, - privileges: { - kibana: onlyStackAlertsKibanaPrivileges, + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [ + "rule-type-id-1/alerts/rule/get", + "rule-type-id-1/alerts/rule/create", + "rule-type-id-1/consumer-a/rule/get", + "rule-type-id-1/consumer-a/rule/create", + "rule-type-id-1/consumer-b/rule/get", + "rule-type-id-1/consumer-b/rule/create", + "rule-type-id-2/alerts/rule/get", + "rule-type-id-2/alerts/rule/create", + "rule-type-id-2/consumer-b/rule/get", + "rule-type-id-2/consumer-b/rule/create", + "rule-type-id-3/alerts/rule/get", + "rule-type-id-3/alerts/rule/create", + "rule-type-id-3/consumer-c/rule/get", + "rule-type-id-3/consumer-c/rule/create", + "rule-type-id-4/consumer-d/rule/get", + "rule-type-id-4/consumer-d/rule/create", + ], }, - }); - authorization.checkPrivilegesDynamicallyWithRequest.mockReset(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - }); + ] + `); + }); - describe('ensureAuthorized', () => { - test('should allow to create .esquery rule type with stackAlerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'stackAlerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); + it('call checkPrivileges with the correct actions when the rule type does not exist in the registry', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => false); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with discover consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'discover', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"logs\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with infrastructure consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"infrastructure\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".threshold-rule-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .logs-threshold-o11y rule type with alerts infrastructure', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.logs-threshold-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".logs-threshold-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, }); - test('creates a filter based on the privileged types', async () => { - const filter = ( - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).filter; - expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( - `"(path.to.rule_type_id: .esQuery AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts))"` - ); + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['rule-type-id-1'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, }); - }); - describe('user only access to o11y', () => { - beforeEach(() => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.mode.useRbacForRequest.mockReturnValue(true); - - features.getKibanaFeatures.mockReset(); - features.getKibanaFeatures.mockReturnValue([ - mockFeature('infrastructure', [ - '.infrastructure-threshold-o11y', - '.threshold-rule-o11y', - '.esQuery', - ]), - mockFeature('logs', ['.threshold-rule-o11y', '.esQuery', '.logs-threshold-o11y']), - ]); - checkPrivileges.mockReset(); - checkPrivileges.mockResolvedValue({ - username: 'onlyO11y', - hasAllRequested: true, - privileges: { - kibana: only011yKibanaPrivileges, + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [], }, - }); - authorization.checkPrivilegesDynamicallyWithRequest.mockReset(); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - }); - - describe('ensureAuthorized', () => { - test('should throw an error to create .esquery rule type with stackAlerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'stackAlerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"stackAlerts\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with discover consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'discover', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"discover\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".threshold-rule-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with logs infrastructure', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .logs-threshold-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.logs-threshold-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - }); - test('creates a filter based on the privileged types', async () => { - expect( - ( - await alertAuthorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }, - new Set(['infrastructure', 'logs']) - ) - ).filter - ).toEqual( - fromKueryExpression( - `(path.to.rule_type_id:.infrastructure-threshold-o11y and consumer-field:(infrastructure or alerts)) or (path.to.rule_type_id:.threshold-rule-o11y and consumer-field:(infrastructure or logs)) or (path.to.rule_type_id:.logs-threshold-o11y and consumer-field:(logs or alerts))` - ) - ); - }); + ] + `); }); - describe('user only access to logs and stackAlerts', () => { - beforeEach(() => { - const { authorization } = mockSecurity(); - const checkPrivileges: jest.MockedFunction< - ReturnType - > = jest.fn(); - authorization.mode.useRbacForRequest.mockReturnValue(true); - - features.getKibanaFeatures.mockClear(); - features.getKibanaFeatures.mockReturnValue([ - mockFeature('stackAlerts', ['.esQuery']), - mockFeature('logs', ['.logs-threshold-o11y', '.threshold-rule-o11y', '.esQuery']), - ]); - checkPrivileges.mockClear(); - checkPrivileges.mockResolvedValue({ - username: 'stackAndLogs', - hasAllRequested: true, - privileges: { - kibana: onlyLogsAndStackAlertsKibanaPrivileges, - }, - }); - authorization.checkPrivilegesDynamicallyWithRequest.mockReturnValue(checkPrivileges); - alertAuthorization = new AlertingAuthorization({ - request, - authorization, - ruleTypeRegistry, - features, - getSpace, - getSpaceId, - }); - }); - - describe('ensureAuthorized', () => { - test('should allow to create .esquery rule type with stackAlerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'stackAlerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); + it('call checkPrivileges with the correct actions when the rule type does not exist in the feature', async () => { + ruleTypeRegistry.has.mockImplementation((ruleTypeId: string) => true); - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with discover consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'discover', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .esquery rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should allow to create .logs-threshold-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.logs-threshold-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with logs consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'logs', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).resolves.toEqual(undefined); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with logs infrastructure', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"infrastructure\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .threshold-rule-o11y rule type with alerts consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.threshold-rule-o11y', - consumer: 'alerts', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"alerts\\" to create \\".threshold-rule-o11y\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); - test('should throw an error to create .esquery rule type with infrastructure consumer', async () => { - await expect( - alertAuthorization.ensureAuthorized({ - ruleTypeId: '.esQuery', - consumer: 'infrastructure', - operation: WriteOperations.Create, - entity: AlertingAuthorizationEntity.Rule, - }) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Unauthorized by \\"infrastructure\\" to create \\".esQuery\\" rule"` - ); - - expect(ruleTypeRegistry.get).toHaveBeenCalledTimes(1); - }); + const auth = await AlertingAuthorization.create({ + request, + ruleTypeRegistry, + getSpaceId, + features, + getSpace, + authorization: securityStart.authz, }); - test('creates a filter based on the privileged types', async () => { - const filter = ( - await alertAuthorization.getFindAuthorizationFilter(AlertingAuthorizationEntity.Rule, { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }) - ).filter; - - expect(toKqlExpression(filter as KueryNode)).toMatchInlineSnapshot( - `"((path.to.rule_type_id: .esQuery AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts OR consumer-field: logs)) OR (path.to.rule_type_id: .logs-threshold-o11y AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts OR consumer-field: logs)) OR (path.to.rule_type_id: .threshold-rule-o11y AND (consumer-field: alerts OR consumer-field: discover OR consumer-field: stackAlerts OR consumer-field: logs)))"` - ); + // @ts-expect-error: need to test the private method + await auth._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: ['not-exist'], + operations: [ReadOperations.Get, WriteOperations.Create], + authorizationEntity: AlertingAuthorizationEntity.Rule, }); + + expect(checkPrivileges).toBeCalledTimes(1); + expect(checkPrivileges.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "kibana": Array [], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts index 6b24f2f5de9a..a7e36590d221 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization.ts @@ -6,61 +6,20 @@ */ import Boom from '@hapi/boom'; -import { has, isEmpty } from 'lodash'; import { KibanaRequest } from '@kbn/core/server'; import { JsonObject } from '@kbn/utility-types'; import { KueryNode } from '@kbn/es-query'; -import { SecurityPluginSetup } from '@kbn/security-plugin/server'; +import { SecurityPluginStart } from '@kbn/security-plugin/server'; import { FeaturesPluginStart } from '@kbn/features-plugin/server'; import { Space } from '@kbn/spaces-plugin/server'; -import { STACK_ALERTS_FEATURE_ID } from '@kbn/rule-data-utils'; import { RegistryRuleType } from '../rule_type_registry'; -import { ALERTING_FEATURE_ID, RuleTypeRegistry } from '../types'; +import { RuleTypeRegistry } from '../types'; import { asFiltersByRuleTypeAndConsumer, asFiltersBySpaceId, AlertingAuthorizationFilterOpts, } from './alerting_authorization_kuery'; - -export enum AlertingAuthorizationEntity { - Rule = 'rule', - Alert = 'alert', -} - -export enum ReadOperations { - Get = 'get', - GetRuleState = 'getRuleState', - GetAlertSummary = 'getAlertSummary', - GetExecutionLog = 'getExecutionLog', - GetActionErrorLog = 'getActionErrorLog', - Find = 'find', - GetAuthorizedAlertsIndices = 'getAuthorizedAlertsIndices', - GetRuleExecutionKPI = 'getRuleExecutionKPI', - GetBackfill = 'getBackfill', - FindBackfill = 'findBackfill', -} - -export enum WriteOperations { - Create = 'create', - Delete = 'delete', - Update = 'update', - UpdateApiKey = 'updateApiKey', - Enable = 'enable', - Disable = 'disable', - MuteAll = 'muteAll', - UnmuteAll = 'unmuteAll', - MuteAlert = 'muteAlert', - UnmuteAlert = 'unmuteAlert', - Snooze = 'snooze', - BulkEdit = 'bulkEdit', - BulkDelete = 'bulkDelete', - BulkEnable = 'bulkEnable', - BulkDisable = 'bulkDisable', - Unsnooze = 'unsnooze', - RunSoon = 'runSoon', - ScheduleBackfill = 'scheduleBackfill', - DeleteBackfill = 'deleteBackfill', -} +import { ReadOperations, WriteOperations, AlertingAuthorizationEntity } from './types'; export interface EnsureAuthorizedOpts { ruleTypeId: string; @@ -74,75 +33,178 @@ interface HasPrivileges { read: boolean; all: boolean; } + type AuthorizedConsumers = Record; export interface RegistryAlertTypeWithAuth extends RegistryRuleType { authorizedConsumers: AuthorizedConsumers; } -type IsAuthorizedAtProducerLevel = boolean; -export interface ConstructorOptions { +export type AuthorizedRuleTypes = Map; + +export interface CreateOptions { ruleTypeRegistry: RuleTypeRegistry; request: KibanaRequest; features: FeaturesPluginStart; getSpace: (request: KibanaRequest) => Promise; getSpaceId: (request: KibanaRequest) => string | undefined; - authorization?: SecurityPluginSetup['authz']; + authorization?: SecurityPluginStart['authz']; +} + +type ConstructorOptions = Pick< + CreateOptions, + 'ruleTypeRegistry' | 'request' | 'authorization' | 'getSpaceId' +> & { + allRegisteredConsumers: Set; + ruleTypesConsumersMap: Map>; +}; + +interface GetAuthorizationFilterParams { + authorizationEntity: AlertingAuthorizationEntity; + filterOpts: AlertingAuthorizationFilterOpts; + operation: WriteOperations | ReadOperations; } -const DISCOVER_FEATURE_ID = 'discover'; +interface GetAuthorizedRuleTypesWithAuthorizedConsumersParams { + ruleTypeIds?: string[]; + operations: Array; + authorizationEntity: AlertingAuthorizationEntity; +} + +interface GetAllAuthorizedRuleTypesFindOperationParams { + authorizationEntity: AlertingAuthorizationEntity; + ruleTypeIds?: string[]; +} + +interface GetFindAuthorizationFilterParams { + authorizationEntity: AlertingAuthorizationEntity; + filterOpts: AlertingAuthorizationFilterOpts; +} + +interface GetAuthorizedRuleTypesParams { + ruleTypeIds?: string[]; + operations: Array; + authorizationEntity: AlertingAuthorizationEntity; +} + +interface GetAllAuthorizedRuleTypes { + operations: Array; + authorizationEntity: AlertingAuthorizationEntity; +} export class AlertingAuthorization { private readonly ruleTypeRegistry: RuleTypeRegistry; private readonly request: KibanaRequest; - private readonly authorization?: SecurityPluginSetup['authz']; - private readonly featuresIds: Promise>; - private readonly allPossibleConsumers: Promise; + private readonly authorization?: SecurityPluginStart['authz']; + private readonly allRegisteredConsumers: Set; + private readonly ruleTypesConsumersMap: Map>; private readonly spaceId: string | undefined; - private readonly features: FeaturesPluginStart; + constructor({ ruleTypeRegistry, request, authorization, - features, - getSpace, getSpaceId, + allRegisteredConsumers, + ruleTypesConsumersMap, }: ConstructorOptions) { this.request = request; this.authorization = authorization; this.ruleTypeRegistry = ruleTypeRegistry; - this.features = features; + this.allRegisteredConsumers = allRegisteredConsumers; + this.ruleTypesConsumersMap = ruleTypesConsumersMap; this.spaceId = getSpaceId(request); + } - this.featuresIds = getSpace(request) - .then((maybeSpace) => new Set(maybeSpace?.disabledFeatures ?? [])) - .then( - (disabledFeatures) => - new Set( - features - .getKibanaFeatures() - .filter( - ({ id, alerting }) => - // ignore features which are disabled in the user's space - !disabledFeatures.has(id) && - // ignore features which don't grant privileges to alerting - (alerting?.length ?? 0 > 0) - ) - .map((feature) => feature.id) - ) - ) - .catch(() => { - // failing to fetch the space means the user is likely not privileged in the - // active space at all, which means that their list of features should be empty - return new Set(); - }); + /** + * Creates an AlertingAuthorization object. + */ + static async create({ + request, + features, + getSpace, + getSpaceId, + authorization, + ruleTypeRegistry, + }: CreateOptions): Promise { + const allRegisteredConsumers = new Set(); + const ruleTypesConsumersMap = new Map>(); + let maybeSpace; + + try { + maybeSpace = await getSpace(request); + } catch (error) { + /** + * Failing to fetch the space with 403 or 404 means the user is likely not privileged in the active space at all + * which means that `allRegisteredConsumers` and `ruleTypesConsumersMap` should be empty. By initializing the alerting authorization + * with empty data structures we ensure that the user will not have access to any rule types in the active space. + * All other errors are treated as server errors and they are surfaced to the upper level. + */ + if (Boom.isBoom(error) && [403, 404].includes(error.output.statusCode)) { + return new AlertingAuthorization({ + request, + authorization, + getSpaceId, + ruleTypeRegistry, + allRegisteredConsumers, + ruleTypesConsumersMap, + }); + } + + if (Boom.isBoom(error)) { + throw error; + } - this.allPossibleConsumers = this.featuresIds.then((featuresIds) => { - return featuresIds.size - ? asAuthorizedConsumers([ALERTING_FEATURE_ID, DISCOVER_FEATURE_ID, ...featuresIds], { - read: true, - all: true, - }) - : {}; + throw new Error(`Failed to create AlertingAuthorization class: ${error}`); + } + + const disabledFeatures = new Set(maybeSpace?.disabledFeatures ?? []); + const featuresWithAlertingConfigured = features.getKibanaFeatures().filter( + ({ id, alerting }) => + // ignore features which are disabled in the user's space + !disabledFeatures.has(id) && + // ignore features which don't grant privileges to alerting + Boolean(alerting?.length) + ); + + /** + * Each feature configures a set of rule types. Each + * rule type configures its valid consumers. For example, + * + * { id: 'my-feature-id-1', alerting: [{ ruleTypeId: 'my-rule-type', consumers: ['consumer-a', 'consumer-b'] }] } + * { id: 'my-feature-id-2', alerting: [{ ruleTypeId: 'my-rule-type-2', consumers: ['consumer-a', 'consumer-d'] }] } + * + * In this loop we iterate over all features and we construct: + * a) a set that contains all registered consumers and + * b) a map that contains all valid consumers per rule type. + * We remove duplicates in the process. For example, + * + * allRegisteredConsumers: Set(1) { 'consumer-a', 'consumer-b', 'consumer-d' } + * ruleTypesConsumersMap: Map(1) { + * 'my-rule-type' => Set(1) { 'consumer-a', 'consumer-b' } + * 'my-rule-type-2' => Set(1) { 'consumer-a', 'consumer-d' } + * } + */ + for (const feature of featuresWithAlertingConfigured) { + if (feature.alerting) { + for (const entry of feature.alerting) { + const consumers = ruleTypesConsumersMap.get(entry.ruleTypeId) ?? new Set(); + + entry.consumers.forEach((consumer) => { + consumers.add(consumer); + allRegisteredConsumers.add(consumer); + }); + ruleTypesConsumersMap.set(entry.ruleTypeId, consumers); + } + } + } + + return new AlertingAuthorization({ + request, + authorization, + getSpaceId, + ruleTypeRegistry, + allRegisteredConsumers, + ruleTypesConsumersMap, }); } @@ -155,42 +217,30 @@ export class AlertingAuthorization { } /* - * This method exposes the private 'augmentRuleTypesWithAuthorization' to be + * This method exposes the private '_getAuthorizedRuleTypesWithAuthorizedConsumers' to be * used by the RAC/Alerts client */ - public async getAugmentedRuleTypesWithAuthorization( - featureIds: readonly string[], - operations: Array, - authorizationEntity: AlertingAuthorizationEntity - ): Promise<{ + public async getAllAuthorizedRuleTypes(params: GetAllAuthorizedRuleTypes): Promise<{ username?: string; hasAllRequested: boolean; - authorizedRuleTypes: Set; + authorizedRuleTypes: AuthorizedRuleTypes; }> { - return this.augmentRuleTypesWithAuthorization( - this.ruleTypeRegistry.list(), - operations, - authorizationEntity, - new Set(featureIds) - ); + return this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + operations: params.operations, + authorizationEntity: params.authorizationEntity, + }); } public async ensureAuthorized({ ruleTypeId, - consumer: legacyConsumer, + consumer, operation, entity, additionalPrivileges = [], }: EnsureAuthorizedOpts) { const { authorization } = this; - const ruleType = this.ruleTypeRegistry.get(ruleTypeId); - const consumer = getValidConsumer({ - validLegacyConsumers: ruleType.validLegacyConsumers, - legacyConsumer, - producer: ruleType.producer, - }); - const isAvailableConsumer = has(await this.allPossibleConsumers, consumer); + const isAvailableConsumer = this.allRegisteredConsumers.has(consumer); if (authorization && this.shouldCheckAuthorization()) { const checkPrivileges = authorization.checkPrivilegesDynamicallyWithRequest(this.request); @@ -209,7 +259,7 @@ export class AlertingAuthorization { * as Privileged. * This check will ensure we don't accidentally let these through */ - throw Boom.forbidden(getUnauthorizedMessage(ruleTypeId, legacyConsumer, operation, entity)); + throw Boom.forbidden(getUnauthorizedMessage(ruleTypeId, consumer, operation, entity)); } if (!hasAllRequested) { @@ -220,274 +270,204 @@ export class AlertingAuthorization { } } - public async getFindAuthorizationFilter( - authorizationEntity: AlertingAuthorizationEntity, - filterOpts: AlertingAuthorizationFilterOpts, - featuresIds?: Set - ): Promise<{ + public async getFindAuthorizationFilter(params: GetFindAuthorizationFilterParams): Promise<{ filter?: KueryNode | JsonObject; ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void; }> { - return this.getAuthorizationFilter( - authorizationEntity, - filterOpts, - ReadOperations.Find, - featuresIds - ); + return this.getAuthorizationFilter({ + operation: ReadOperations.Find, + authorizationEntity: params.authorizationEntity, + filterOpts: params.filterOpts, + }); } - public async getAuthorizedRuleTypes( - authorizationEntity: AlertingAuthorizationEntity, - featuresIds?: Set - ): Promise { - const { authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization( - this.ruleTypeRegistry.list(), - [ReadOperations.Find], - authorizationEntity, - featuresIds - ); - return Array.from(authorizedRuleTypes); + public async getAllAuthorizedRuleTypesFindOperation( + params: GetAllAuthorizedRuleTypesFindOperationParams + ): Promise { + const { authorizedRuleTypes } = await this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: params.ruleTypeIds, + operations: [ReadOperations.Find], + authorizationEntity: params.authorizationEntity, + }); + + return authorizedRuleTypes; } - public async getAuthorizationFilter( - authorizationEntity: AlertingAuthorizationEntity, - filterOpts: AlertingAuthorizationFilterOpts, - operation: WriteOperations | ReadOperations, - featuresIds?: Set - ): Promise<{ + public async getAuthorizationFilter(params: GetAuthorizationFilterParams): Promise<{ filter?: KueryNode | JsonObject; ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void; }> { if (this.authorization && this.shouldCheckAuthorization()) { - const { authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization( - this.ruleTypeRegistry.list(), - [operation], - authorizationEntity, - featuresIds - ); + const { authorizedRuleTypes } = await this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + operations: [params.operation], + authorizationEntity: params.authorizationEntity, + }); if (!authorizedRuleTypes.size) { - throw Boom.forbidden(`Unauthorized to find ${authorizationEntity}s for any rule types`); + throw Boom.forbidden( + `Unauthorized to ${params.operation} ${params.authorizationEntity}s for any rule types` + ); } - const authorizedRuleTypeIdsToConsumers = new Set( - [...authorizedRuleTypes].reduce((ruleTypeIdConsumerPairs, ruleType) => { - for (const consumer of Object.keys(ruleType.authorizedConsumers)) { - ruleTypeIdConsumerPairs.push(`${ruleType.id}/${consumer}/${authorizationEntity}`); - } - return ruleTypeIdConsumerPairs; - }, []) - ); - - const authorizedEntries: Map> = new Map(); return { filter: asFiltersByRuleTypeAndConsumer( authorizedRuleTypes, - filterOpts, + params.filterOpts, this.spaceId ) as JsonObject, ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, authType: string) => { - if (!authorizedRuleTypeIdsToConsumers.has(`${ruleTypeId}/${consumer}/${authType}`)) { + if (!authorizedRuleTypes.has(ruleTypeId) || authType !== params.authorizationEntity) { + throw Boom.forbidden( + getUnauthorizedMessage(ruleTypeId, consumer, params.operation, authType) + ); + } + + const authorizedRuleType = authorizedRuleTypes.get(ruleTypeId)!; + const authorizedConsumers = authorizedRuleType.authorizedConsumers; + + if (!authorizedConsumers[consumer]) { throw Boom.forbidden( - getUnauthorizedMessage(ruleTypeId, consumer, 'find', authorizationEntity) + getUnauthorizedMessage( + ruleTypeId, + consumer, + params.operation, + params.authorizationEntity + ) ); - } else { - if (authorizedEntries.has(ruleTypeId)) { - authorizedEntries.get(ruleTypeId)!.add(consumer); - } else { - authorizedEntries.set(ruleTypeId, new Set([consumer])); - } } }, }; } return { - filter: asFiltersBySpaceId(filterOpts, this.spaceId) as JsonObject, + filter: asFiltersBySpaceId(params.filterOpts, this.spaceId) as JsonObject, ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, authType: string) => {}, }; } - public async filterByRuleTypeAuthorization( - ruleTypes: Set, - operations: Array, - authorizationEntity: AlertingAuthorizationEntity - ): Promise> { - const { authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization( - ruleTypes, - operations, - authorizationEntity - ); + public async getAuthorizedRuleTypes( + params: GetAuthorizedRuleTypesParams + ): Promise { + const { authorizedRuleTypes } = await this._getAuthorizedRuleTypesWithAuthorizedConsumers({ + ruleTypeIds: params.ruleTypeIds, + operations: params.operations, + authorizationEntity: params.authorizationEntity, + }); + return authorizedRuleTypes; } - private async augmentRuleTypesWithAuthorization( - ruleTypes: Set, - operations: Array, - authorizationEntity: AlertingAuthorizationEntity, - featuresIds?: Set + private async _getAuthorizedRuleTypesWithAuthorizedConsumers( + params: GetAuthorizedRuleTypesWithAuthorizedConsumersParams ): Promise<{ username?: string; hasAllRequested: boolean; - authorizedRuleTypes: Set; + authorizedRuleTypes: Map; }> { - const fIds = new Set(featuresIds ?? (await this.featuresIds)); + const { operations, authorizationEntity } = params; + const ruleTypeIds = params.ruleTypeIds + ? new Set(params.ruleTypeIds) + : new Set(this.ruleTypeRegistry.getAllTypes()); - /** - * Temporary hack to fix issues with the discover consumer. - * Issue: https://github.com/elastic/kibana/issues/184595. - * PR https://github.com/elastic/kibana/pull/183756 will - * remove the hack and fix it in a generic way. - * - * The discover consumer should be authorized - * as the stackAlerts consumer. - */ - if (fIds.has(DISCOVER_FEATURE_ID)) { - fIds.delete(DISCOVER_FEATURE_ID); - fIds.add(STACK_ALERTS_FEATURE_ID); - } + const requiredPrivileges = new Map< + string, + { ruleTypeId: string; consumer: string; operation: ReadOperations | WriteOperations } + >(); if (this.authorization && this.shouldCheckAuthorization()) { + const authorizedRuleTypes = new Map(); + const checkPrivileges = this.authorization.checkPrivilegesDynamicallyWithRequest( this.request ); - // add an empty `authorizedConsumers` array on each ruleType - const ruleTypesWithAuthorization = Array.from( - this.augmentWithAuthorizedConsumers(ruleTypes, {}) - ); - const ruleTypesAuthorized: Map = new Map(); - // map from privilege to ruleType which we can refer back to when analyzing the result - // of checkPrivileges - const privilegeToRuleType = new Map< - string, - [RegistryAlertTypeWithAuth, string, HasPrivileges, IsAuthorizedAtProducerLevel] - >(); - const allPossibleConsumers = await this.allPossibleConsumers; - const addLegacyConsumerPrivileges = (legacyConsumer: string) => - legacyConsumer === ALERTING_FEATURE_ID || - legacyConsumer === DISCOVER_FEATURE_ID || - isEmpty(featuresIds); - - for (const feature of fIds) { - const featureDef = this.features - .getKibanaFeatures() - .find((kFeature) => kFeature.id === feature); - - for (const ruleTypeId of featureDef?.alerting ?? []) { - const ruleTypeAuth = ruleTypesWithAuthorization.find((rtwa) => rtwa.id === ruleTypeId); - if (ruleTypeAuth) { - if (!ruleTypesAuthorized.has(ruleTypeId)) { - ruleTypesAuthorized.set(ruleTypeId, ruleTypeAuth); - } - for (const operation of operations) { - privilegeToRuleType.set( - this.authorization!.actions.alerting.get( - ruleTypeId, - feature, - authorizationEntity, - operation - ), - [ - ruleTypeAuth, - feature, - hasPrivilegeByOperation(operation), - ruleTypeAuth.producer === feature, - ] - ); - // FUTURE ENGINEER - // We are just trying to add back the legacy consumers associated - // to the rule type to get back the privileges that was given at one point - if (!isEmpty(ruleTypeAuth.validLegacyConsumers)) { - ruleTypeAuth.validLegacyConsumers.forEach((legacyConsumer) => { - if (addLegacyConsumerPrivileges(legacyConsumer)) { - if (!allPossibleConsumers[legacyConsumer]) { - allPossibleConsumers[legacyConsumer] = { - read: true, - all: true, - }; - } - - privilegeToRuleType.set( - this.authorization!.actions.alerting.get( - ruleTypeId, - legacyConsumer, - authorizationEntity, - operation - ), - [ruleTypeAuth, legacyConsumer, hasPrivilegeByOperation(operation), false] - ); - } - }); + for (const ruleTypeId of ruleTypeIds) { + /** + * Skip if the ruleTypeId is not configured in any feature + * or it is not set in the rule type registry. + */ + if (!this.ruleTypesConsumersMap.has(ruleTypeId) || !this.ruleTypeRegistry.has(ruleTypeId)) { + continue; + } + + const ruleType = this.ruleTypeRegistry.get(ruleTypeId)!; + const ruleTypeConsumers = this.ruleTypesConsumersMap.get(ruleTypeId) ?? new Set(); + + for (const consumerToAuthorize of ruleTypeConsumers) { + for (const operation of operations) { + requiredPrivileges.set( + this.authorization.actions.alerting.get( + ruleTypeId, + consumerToAuthorize, + authorizationEntity, + operation + ), + { + ruleTypeId: ruleType.id, + consumer: consumerToAuthorize, + operation, } - } + ); } } } const { username, hasAllRequested, privileges } = await checkPrivileges({ - kibana: [...privilegeToRuleType.keys()], + kibana: [...requiredPrivileges.keys()], }); + for (const { authorized, privilege } of privileges.kibana) { + if (authorized && requiredPrivileges.has(privilege)) { + const { ruleTypeId, consumer, operation } = requiredPrivileges.get(privilege)!; + + const authorizedRuleType = authorizedRuleTypes.get(ruleTypeId) ?? { + authorizedConsumers: {}, + }; + + const authorizedConsumers = authorizedRuleType.authorizedConsumers; + const mergedOperations = mergeHasPrivileges( + getPrivilegesFromOperation(operation), + authorizedConsumers[consumer] + ); + + authorizedRuleTypes.set(ruleTypeId, { + authorizedConsumers: { + ...authorizedConsumers, + [consumer]: mergedOperations, + }, + }); + } + } + return { username, hasAllRequested, - authorizedRuleTypes: - hasAllRequested && featuresIds === undefined - ? // has access to all features - this.augmentWithAuthorizedConsumers( - new Set(ruleTypesAuthorized.values()), - allPossibleConsumers - ) - : // only has some of the required privileges - privileges.kibana.reduce((authorizedRuleTypes, { authorized, privilege }) => { - if (authorized && privilegeToRuleType.has(privilege)) { - const [ruleType, feature, hasPrivileges, isAuthorizedAtProducerLevel] = - privilegeToRuleType.get(privilege)!; - if (fIds.has(feature)) { - ruleType.authorizedConsumers[feature] = mergeHasPrivileges( - hasPrivileges, - ruleType.authorizedConsumers[feature] - ); - - if (isAuthorizedAtProducerLevel) { - // granting privileges under the producer automatically authorized the Rules Management UI as well - ruleType.validLegacyConsumers.forEach((legacyConsumer) => { - if (addLegacyConsumerPrivileges(legacyConsumer)) { - ruleType.authorizedConsumers[legacyConsumer] = mergeHasPrivileges( - hasPrivileges, - ruleType.authorizedConsumers[legacyConsumer] - ); - } - }); - } - authorizedRuleTypes.add(ruleType); - } - } - return authorizedRuleTypes; - }, new Set()), + authorizedRuleTypes, }; } else { return { hasAllRequested: true, - authorizedRuleTypes: this.augmentWithAuthorizedConsumers( - new Set([...ruleTypes].filter((ruleType) => fIds.has(ruleType.producer))), - await this.allPossibleConsumers - ), + authorizedRuleTypes: this.getRegisteredRuleTypesWithAllRegisteredConsumers(ruleTypeIds), }; } } - private augmentWithAuthorizedConsumers( - ruleTypes: Set, - authorizedConsumers: AuthorizedConsumers - ): Set { - return new Set( - Array.from(ruleTypes).map((ruleType) => ({ - ...ruleType, - authorizedConsumers: { ...authorizedConsumers }, - })) - ); + private getRegisteredRuleTypesWithAllRegisteredConsumers(ruleTypeIds: Set) { + const authorizedRuleTypes = new Map(); + const authorizedConsumers = getConsumersWithPrivileges(this.allRegisteredConsumers, { + all: true, + read: true, + }); + + Array.from(this.ruleTypesConsumersMap.keys()) + .filter((ruleTypeId) => ruleTypeIds.has(ruleTypeId)) + .forEach((ruleTypeId) => { + authorizedRuleTypes.set(ruleTypeId, { + authorizedConsumers, + }); + }); + + return authorizedRuleTypes; } } @@ -498,7 +478,7 @@ function mergeHasPrivileges(left: HasPrivileges, right?: HasPrivileges): HasPriv }; } -function hasPrivilegeByOperation(operation: ReadOperations | WriteOperations): HasPrivileges { +function getPrivilegesFromOperation(operation: ReadOperations | WriteOperations): HasPrivileges { const read = Object.values(ReadOperations).includes(operation as unknown as ReadOperations); const all = Object.values(WriteOperations).includes(operation as unknown as WriteOperations); return { @@ -507,34 +487,21 @@ function hasPrivilegeByOperation(operation: ReadOperations | WriteOperations): H }; } -function asAuthorizedConsumers( - consumers: string[], +function getConsumersWithPrivileges( + consumers: Set, hasPrivileges: HasPrivileges ): AuthorizedConsumers { - return consumers.reduce((acc, feature) => { + return Array.from(consumers).reduce((acc, feature) => { acc[feature] = hasPrivileges; return acc; }, {}); } function getUnauthorizedMessage( - alertTypeId: string, + ruleTypeId: string, scope: string, operation: string, entity: string ): string { - return `Unauthorized by "${scope}" to ${operation} "${alertTypeId}" ${entity}`; + return `Unauthorized by "${scope}" to ${operation} "${ruleTypeId}" ${entity}`; } - -export const getValidConsumer = ({ - validLegacyConsumers, - legacyConsumer, - producer, -}: { - validLegacyConsumers: string[]; - legacyConsumer: string; - producer: string; -}): string => - legacyConsumer === ALERTING_FEATURE_ID || validLegacyConsumers.includes(legacyConsumer) - ? producer - : legacyConsumer; diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts index b433a95a7773..bcc2b37dca7d 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.test.ts @@ -5,364 +5,258 @@ * 2.0. */ -import { RecoveredActionGroup } from '../../common'; import { AlertingAuthorizationFilterType, asFiltersByRuleTypeAndConsumer, ensureFieldIsSafeForQuery, asFiltersBySpaceId, } from './alerting_authorization_kuery'; -import { fromKueryExpression } from '@kbn/es-query'; +import { KueryNode, toKqlExpression } from '@kbn/es-query'; describe('asKqlFiltersByRuleTypeAndConsumer', () => { test('constructs KQL filter for single rule type with single authorized consumer', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( - asFiltersByRuleTypeAndConsumer( - new Set([ + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, - authorizedConsumers: { - myApp: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', }, - }, - 'space1' + 'space1' + ) as KueryNode ) - ).toEqual( - fromKueryExpression(`((path.to.rule_type_id:myAppAlertType and consumer-field:(myApp)))`) - ); + ).toMatchInlineSnapshot(`"(path.to.rule_type_id: myAppAlertType AND consumer-field: myApp)"`); }); test('constructs KQL filter for single rule type with multiple authorized consumers', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( - asFiltersByRuleTypeAndConsumer( - new Set([ + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }, - 'space1' - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp)))` + 'space1' + ) as KueryNode ) + ).toMatchInlineSnapshot( + `"(path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp))"` ); }); test('constructs KQL filter for multiple rule types across authorized consumer', async () => { - expect( - asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + }, + ], + [ + 'myOtherAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, + }, + ], + ]); + + expect( + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - }, - }, - 'space1' - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:mySecondAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)))` + 'space1' + ) as KueryNode ) + ).toMatchInlineSnapshot( + `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)))"` ); }); test('constructs KQL filter with spaceId filter when spaceIds field path exists', async () => { - expect( - asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - ]), + }, + ], + [ + 'myOtherAppAlertType', { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - spaceIds: 'path.to.spaceIds', + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, }, - 'space1' - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature) and path.to.spaceIds:space1) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature) and path.to.spaceIds:space1))` - ) - ); - }); + ], + ]); - test('constructs KQL filter without spaceId filter when spaceIds path is specified, but spaceId is undefined', async () => { expect( - asFiltersByRuleTypeAndConsumer( - new Set([ + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + spaceIds: 'path.to.spaceIds', }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + 'space1' + ) as KueryNode + ) + ).toMatchInlineSnapshot( + `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature) AND path.to.spaceIds: space1) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature) AND path.to.spaceIds: space1))"` + ); + }); + + test('constructs KQL filter without spaceId filter when spaceIds path is specified, but spaceId is undefined', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - ]), + }, + ], + [ + 'myOtherAppAlertType', { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - spaceIds: 'path.to.spaceIds', + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, }, - undefined - ) - ).toEqual( - fromKueryExpression( - `((path.to.rule_type_id:myAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)) or (path.to.rule_type_id:myOtherAppAlertType and consumer-field:(alerts or myApp or myOtherApp or myAppWithSubFeature)))` + ], + ]); + + expect( + toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + spaceIds: 'path.to.spaceIds', + }, + }, + undefined + ) as KueryNode ) + ).toMatchInlineSnapshot( + `"((path.to.rule_type_id: myAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)) OR (path.to.rule_type_id: myOtherAppAlertType AND (consumer-field: alerts OR consumer-field: myApp OR consumer-field: myOtherApp OR consumer-field: myAppWithSubFeature)))"` ); }); test('constructs KQL filter for single rule type with no authorized consumer', async () => { - const result = asFiltersByRuleTypeAndConsumer( - new Set([ + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, authorizedConsumers: {}, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', + ], + ]); + + const result = toKqlExpression( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + }, }, - }, - 'space1' + 'space1' + ) as KueryNode ); - expect(result).toEqual(fromKueryExpression(`path.to.rule_type_id:myAppAlertType`)); + expect(result).toMatchInlineSnapshot(`"path.to.rule_type_id: myAppAlertType"`); }); }); describe('asEsDslFiltersByRuleTypeAndConsumer', () => { test('constructs ES DSL filter for single rule type with single authorized consumer', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, - authorizedConsumers: { - myApp: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]), + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -405,30 +299,22 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { }); test('constructs ES DSL filter for single rule type with multiple authorized consumers', async () => { + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + }, + }, + ], + ]); + expect( asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]), + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -478,73 +364,34 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { }); test('constructs ES DSL filter for multiple rule types across authorized consumer', async () => { - expect( - asFiltersByRuleTypeAndConsumer( - new Set([ - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myOtherAppAlertType', - name: 'myOtherAppAlertType', - category: 'test', - producer: 'alerts', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - { - actionGroups: [], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'mySecondAppAlertType', - name: 'mySecondAppAlertType', - category: 'test', - producer: 'myApp', - authorizedConsumers: { - alerts: { read: true, all: true }, - myApp: { read: true, all: true }, - myOtherApp: { read: true, all: true }, - myAppWithSubFeature: { read: true, all: true }, - }, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], + }, + ], + [ + 'myOtherAppAlertType', + { + authorizedConsumers: { + alerts: { read: true, all: true }, + myApp: { read: true, all: true }, + myOtherApp: { read: true, all: true }, + myAppWithSubFeature: { read: true, all: true }, }, - ]), + }, + ], + ]); + + expect( + asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -554,164 +401,175 @@ describe('asEsDslFiltersByRuleTypeAndConsumer', () => { }, 'space1' ) - ).toEqual({ - bool: { - should: [ - { - bool: { - filter: [ - { - bool: { - should: [{ match: { 'path.to.rule_type_id': 'myAppAlertType' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [ - { - bool: { - should: [{ match: { 'consumer-field': 'alerts' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myApp' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myOtherApp' } }], - minimum_should_match: 1, - }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myAppWithSubFeature' } }], - minimum_should_match: 1, + ).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": Object { + "path.to.rule_type_id": "myAppAlertType", + }, }, - }, - ], - minimum_should_match: 1, - }, - }, - ], - }, - }, - { - bool: { - filter: [ - { - bool: { - should: [{ match: { 'path.to.rule_type_id': 'myOtherAppAlertType' } }], - minimum_should_match: 1, + ], + }, }, - }, - { - bool: { - should: [ - { - bool: { - should: [{ match: { 'consumer-field': 'alerts' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "alerts", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myOtherApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myOtherApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myAppWithSubFeature' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myAppWithSubFeature", + }, + }, + ], + }, }, - }, - ], - minimum_should_match: 1, + ], + }, }, - }, - ], + ], + }, }, - }, - { - bool: { - filter: [ - { - bool: { - should: [{ match: { 'path.to.rule_type_id': 'mySecondAppAlertType' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "path.to.rule_type_id": "myOtherAppAlertType", + }, + }, + ], + }, }, - }, - { - bool: { - should: [ - { - bool: { - should: [{ match: { 'consumer-field': 'alerts' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "alerts", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myOtherApp' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myOtherApp", + }, + }, + ], + }, }, - }, - { - bool: { - should: [{ match: { 'consumer-field': 'myAppWithSubFeature' } }], - minimum_should_match: 1, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "consumer-field": "myAppWithSubFeature", + }, + }, + ], + }, }, - }, - ], - minimum_should_match: 1, + ], + }, }, - }, - ], + ], + }, }, - }, - ], - minimum_should_match: 1, - }, - }); + ], + }, + } + `); }); test('constructs KQL filter for single rule type with no authorized consumer', async () => { - const result = asFiltersByRuleTypeAndConsumer( - new Set([ + const authorizedRuleTypes = new Map([ + [ + 'myAppAlertType', { - actionGroups: [], - defaultActionGroupId: 'default', - recoveryActionGroup: RecoveredActionGroup, - id: 'myAppAlertType', - name: 'myAppAlertType', - category: 'test', - producer: 'myApp', - minimumLicenseRequired: 'basic', - isExportable: true, authorizedConsumers: {}, - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], }, - ]), + ], + ]); + + const result = asFiltersByRuleTypeAndConsumer( + authorizedRuleTypes, { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { @@ -760,18 +618,20 @@ describe('asFiltersBySpaceId', () => { test('returns KQL filter of spaceId', () => { expect( - asFiltersBySpaceId( - { - type: AlertingAuthorizationFilterType.KQL, - fieldNames: { - ruleTypeId: 'path.to.rule_type_id', - consumer: 'consumer-field', - spaceIds: 'path.to.space.id', + toKqlExpression( + asFiltersBySpaceId( + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'path.to.rule_type_id', + consumer: 'consumer-field', + spaceIds: 'path.to.space.id', + }, }, - }, - 'space1' + 'space1' + ) as KueryNode ) - ).toEqual(fromKueryExpression('(path.to.space.id: space1)')); + ).toMatchInlineSnapshot(`"path.to.space.id: space1"`); }); test('returns undefined if no path to spaceIds is provided', () => { diff --git a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts index 01e30dfb3832..666059c7a7b4 100644 --- a/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts +++ b/x-pack/plugins/alerting/server/authorization/alerting_authorization_kuery.ts @@ -9,7 +9,7 @@ import { remove } from 'lodash'; import { EsQueryConfig, nodeBuilder, toElasticsearchQuery, KueryNode } from '@kbn/es-query'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { RegistryAlertTypeWithAuth } from './alerting_authorization'; +import { AuthorizedRuleTypes } from './alerting_authorization'; export enum AlertingAuthorizationFilterType { KQL = 'kql', @@ -35,36 +35,39 @@ const esQueryConfig: EsQueryConfig = { }; export function asFiltersByRuleTypeAndConsumer( - ruleTypes: Set, + ruleTypes: AuthorizedRuleTypes, opts: AlertingAuthorizationFilterOpts, spaceId: string | undefined ): KueryNode | estypes.QueryDslQueryContainer { const kueryNode = nodeBuilder.or( - Array.from(ruleTypes).reduce((filters, { id, authorizedConsumers }) => { - ensureFieldIsSafeForQuery('ruleTypeId', id); - - const andNodes: KueryNode[] = [nodeBuilder.is(opts.fieldNames.ruleTypeId, id)]; - - const authorizedConsumersKeys = Object.keys(authorizedConsumers); - if (authorizedConsumersKeys.length) { - andNodes.push( - nodeBuilder.or( - authorizedConsumersKeys.map((consumer) => { - ensureFieldIsSafeForQuery('consumer', consumer); - return nodeBuilder.is(opts.fieldNames.consumer, consumer); - }) - ) - ); - } - - if (opts.fieldNames.spaceIds != null && spaceId != null) { - andNodes.push(nodeBuilder.is(opts.fieldNames.spaceIds, spaceId)); - } - - filters.push(nodeBuilder.and(andNodes)); - - return filters; - }, []) + Array.from(ruleTypes.entries()).reduce( + (filters, [id, { authorizedConsumers }]) => { + ensureFieldIsSafeForQuery('ruleTypeId', id); + + const andNodes: KueryNode[] = [nodeBuilder.is(opts.fieldNames.ruleTypeId, id)]; + + const authorizedConsumersKeys = Object.keys(authorizedConsumers); + if (authorizedConsumersKeys.length) { + andNodes.push( + nodeBuilder.or( + authorizedConsumersKeys.map((consumer) => { + ensureFieldIsSafeForQuery('consumer', consumer); + return nodeBuilder.is(opts.fieldNames.consumer, consumer); + }) + ) + ); + } + + if (opts.fieldNames.spaceIds != null && spaceId != null) { + andNodes.push(nodeBuilder.is(opts.fieldNames.spaceIds, spaceId)); + } + + filters.push(nodeBuilder.and(andNodes)); + + return filters; + }, + [] + ) ); if (opts.type === AlertingAuthorizationFilterType.ESDSL) { diff --git a/x-pack/plugins/alerting/server/authorization/index.ts b/x-pack/plugins/alerting/server/authorization/index.ts index 17f0f9f22bbe..e31dac301cbc 100644 --- a/x-pack/plugins/alerting/server/authorization/index.ts +++ b/x-pack/plugins/alerting/server/authorization/index.ts @@ -7,3 +7,4 @@ export * from './alerting_authorization'; export * from './alerting_authorization_kuery'; +export * from './types'; diff --git a/x-pack/plugins/alerting/server/authorization/types.ts b/x-pack/plugins/alerting/server/authorization/types.ts new file mode 100644 index 000000000000..77357456c74b --- /dev/null +++ b/x-pack/plugins/alerting/server/authorization/types.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export enum AlertingAuthorizationEntity { + Rule = 'rule', + Alert = 'alert', +} + +export enum ReadOperations { + Get = 'get', + GetRuleState = 'getRuleState', + GetAlertSummary = 'getAlertSummary', + GetExecutionLog = 'getExecutionLog', + GetActionErrorLog = 'getActionErrorLog', + Find = 'find', + GetAuthorizedAlertsIndices = 'getAuthorizedAlertsIndices', + GetRuleExecutionKPI = 'getRuleExecutionKPI', + GetBackfill = 'getBackfill', + FindBackfill = 'findBackfill', +} + +export enum WriteOperations { + Create = 'create', + Delete = 'delete', + Update = 'update', + UpdateApiKey = 'updateApiKey', + Enable = 'enable', + Disable = 'disable', + MuteAll = 'muteAll', + UnmuteAll = 'unmuteAll', + MuteAlert = 'muteAlert', + UnmuteAlert = 'unmuteAlert', + Snooze = 'snooze', + BulkEdit = 'bulkEdit', + BulkDelete = 'bulkDelete', + BulkEnable = 'bulkEnable', + BulkDisable = 'bulkDisable', + Unsnooze = 'unsnooze', + RunSoon = 'runSoon', + ScheduleBackfill = 'scheduleBackfill', + DeleteBackfill = 'deleteBackfill', +} diff --git a/x-pack/plugins/alerting/server/config.test.ts b/x-pack/plugins/alerting/server/config.test.ts index 4b84905a12a6..0cb75cb6162c 100644 --- a/x-pack/plugins/alerting/server/config.test.ts +++ b/x-pack/plugins/alerting/server/config.test.ts @@ -21,7 +21,6 @@ describe('config validation', () => { "interval": "5m", "removalDelay": "1h", }, - "maxEphemeralActionsPerAlert": 10, "rules": Object { "maxScheduledPerMinute": 32000, "minimumScheduleInterval": Object { diff --git a/x-pack/plugins/alerting/server/config.ts b/x-pack/plugins/alerting/server/config.ts index be7790cd8188..776576cce299 100644 --- a/x-pack/plugins/alerting/server/config.ts +++ b/x-pack/plugins/alerting/server/config.ts @@ -60,7 +60,6 @@ const rulesSchema = schema.object({ }), }); -export const DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT = 10; export const configSchema = schema.object({ healthCheck: schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '60m' }), @@ -69,9 +68,7 @@ export const configSchema = schema.object({ interval: schema.string({ validate: validateDurationSchema, defaultValue: '5m' }), removalDelay: schema.string({ validate: validateDurationSchema, defaultValue: '1h' }), }), - maxEphemeralActionsPerAlert: schema.number({ - defaultValue: DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT, - }), + maxEphemeralActionsPerAlert: schema.maybe(schema.number()), enableFrameworkAlerts: schema.boolean({ defaultValue: true }), cancelAlertsOnRuleTimeout: schema.boolean({ defaultValue: true }), rules: rulesSchema, diff --git a/x-pack/plugins/alerting/server/index.ts b/x-pack/plugins/alerting/server/index.ts index 2cb2c212a91b..fc00d37e6ebc 100644 --- a/x-pack/plugins/alerting/server/index.ts +++ b/x-pack/plugins/alerting/server/index.ts @@ -36,8 +36,7 @@ export type { export { DEFAULT_AAD_CONFIG } from './types'; export { RULE_SAVED_OBJECT_TYPE, API_KEY_PENDING_INVALIDATION_TYPE } from './saved_objects'; export { RuleNotifyWhen } from '../common'; -export { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from './config'; -export type { PluginSetupContract, PluginStartContract } from './plugin'; +export type { AlertingServerSetup, AlertingServerStart } from './plugin'; export type { FindResult, BulkEditOperation, BulkOperationError } from './rules_client'; export type { Rule } from './application/rule/types'; export type { PublicAlert as Alert } from './alert'; @@ -45,12 +44,13 @@ export { parseDuration, isRuleSnoozed } from './lib'; export { getEsErrorMessage } from './lib/errors'; export type { AlertingRulesConfig } from './config'; export { - ReadOperations, AlertingAuthorizationFilterType, AlertingAuthorization, + ReadOperations, WriteOperations, AlertingAuthorizationEntity, } from './authorization'; + export { DEFAULT_ALERTS_ILM_POLICY, DEFAULT_ALERTS_ILM_POLICY_NAME, @@ -84,9 +84,9 @@ export const config: PluginConfigDescriptor = { rules: { run: { alerts: { max: true } } }, }, deprecations: ({ renameFromRoot, deprecate }) => [ - deprecate('maxEphemeralActionsPerAlert', 'a future version', { + deprecate('maxEphemeralActionsPerAlert', '9.0.0', { level: 'warning', - message: `Configuring "xpack.alerting.maxEphemeralActionsPerAlert" is deprecated and will be removed in a future version. Remove this setting to increase action execution resiliency.`, + message: `The setting "xpack.alerting.maxEphemeralActionsPerAlert" is deprecated and currently ignored by the system. Please remove this setting.`, }), ], }; diff --git a/x-pack/plugins/alerting/server/mocks.ts b/x-pack/plugins/alerting/server/mocks.ts index 33cbccbaf8c0..d885cf0721b4 100644 --- a/x-pack/plugins/alerting/server/mocks.ts +++ b/x-pack/plugins/alerting/server/mocks.ts @@ -14,7 +14,7 @@ import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; import { searchSourceCommonMock } from '@kbn/data-plugin/common/search/search_source/mocks'; import { SharePluginStart } from '@kbn/share-plugin/server'; import { rulesClientMock } from './rules_client.mock'; -import { PluginSetupContract, PluginStartContract } from './plugin'; +import { AlertingServerSetup, AlertingServerStart } from './plugin'; import { Alert, AlertFactoryDoneUtils } from './alert'; import { AlertInstanceContext, @@ -27,7 +27,7 @@ import { publicAlertsClientMock } from './alerts_client/alerts_client.mock'; export { rulesClientMock }; const createSetupMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = { registerType: jest.fn(), getSecurityHealth: jest.fn(), getConfig: jest.fn(), @@ -57,7 +57,7 @@ const createShareStartMock = () => { }; const createStartMock = () => { - const mock: jest.Mocked = { + const mock: jest.Mocked = { listTypes: jest.fn(), getType: jest.fn(), getAllTypes: jest.fn(), diff --git a/x-pack/plugins/alerting/server/plugin.test.ts b/x-pack/plugins/alerting/server/plugin.test.ts index 37175ac96041..2938daf8b1ec 100644 --- a/x-pack/plugins/alerting/server/plugin.test.ts +++ b/x-pack/plugins/alerting/server/plugin.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { AlertingPlugin, PluginSetupContract } from './plugin'; +import { AlertingPlugin, AlertingServerSetup } from './plugin'; import { createUsageCollectionSetupMock } from '@kbn/usage-collection-plugin/server/mocks'; import { coreMock, statusServiceMock } from '@kbn/core/server/mocks'; import { licensingMock } from '@kbn/licensing-plugin/server/mocks'; @@ -170,7 +170,7 @@ describe('Alerting Plugin', () => { }); describe('registerType()', () => { - let setup: PluginSetupContract; + let setup: AlertingServerSetup; beforeEach(async () => { const context = coreMock.createPluginInitializerContext( generateAlertingConfig() @@ -209,7 +209,8 @@ describe('Alerting Plugin', () => { ...sampleRuleType, minimumLicenseRequired: 'basic', } as RuleType; - await setup.registerType(ruleType); + + setup.registerType(ruleType); expect(ruleType.ruleTaskTimeout).toBe('5m'); }); @@ -219,7 +220,7 @@ describe('Alerting Plugin', () => { minimumLicenseRequired: 'basic', ruleTaskTimeout: '20h', } as RuleType; - await setup.registerType(ruleType); + setup.registerType(ruleType); expect(ruleType.ruleTaskTimeout).toBe('20h'); }); @@ -228,7 +229,7 @@ describe('Alerting Plugin', () => { ...sampleRuleType, minimumLicenseRequired: 'basic', } as RuleType; - await setup.registerType(ruleType); + setup.registerType(ruleType); expect(ruleType.cancelAlertsOnRuleTimeout).toBe(true); }); @@ -238,13 +239,13 @@ describe('Alerting Plugin', () => { minimumLicenseRequired: 'basic', cancelAlertsOnRuleTimeout: false, } as RuleType; - await setup.registerType(ruleType); + setup.registerType(ruleType); expect(ruleType.cancelAlertsOnRuleTimeout).toBe(false); }); }); describe('registerConnectorAdapter()', () => { - let setup: PluginSetupContract; + let setup: AlertingServerSetup; beforeEach(async () => { const context = coreMock.createPluginInitializerContext( @@ -314,9 +315,9 @@ describe('Alerting Plugin', () => { }); expect(encryptedSavedObjectsSetup.canEncrypt).toEqual(false); - expect(() => + await expect(() => startContract.getRulesClientWithRequest({} as KibanaRequest) - ).toThrowErrorMatchingInlineSnapshot( + ).rejects.toThrowErrorMatchingInlineSnapshot( `"Unable to create alerts client because the Encrypted Saved Objects plugin is missing encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in the kibana.yml or use the bin/kibana-encryption-keys command."` ); }); @@ -380,7 +381,8 @@ describe('Alerting Plugin', () => { }, getSavedObjectsClient: jest.fn(), } as unknown as KibanaRequest; - startContract.getRulesClientWithRequest(fakeRequest); + + await startContract.getRulesClientWithRequest(fakeRequest); }); }); @@ -443,7 +445,8 @@ describe('Alerting Plugin', () => { }, getSavedObjectsClient: jest.fn(), } as unknown as KibanaRequest; - startContract.getAlertingAuthorizationWithRequest(fakeRequest); + + await startContract.getAlertingAuthorizationWithRequest(fakeRequest); }); }); }); diff --git a/x-pack/plugins/alerting/server/plugin.ts b/x-pack/plugins/alerting/server/plugin.ts index bf1f02d3a491..9d1a15305f7e 100644 --- a/x-pack/plugins/alerting/server/plugin.ts +++ b/x-pack/plugins/alerting/server/plugin.ts @@ -61,7 +61,6 @@ import type { PluginSetup as UnifiedSearchServerPluginSetup } from '@kbn/unified import { PluginStart as DataPluginStart } from '@kbn/data-plugin/server'; import { MonitoringCollectionSetup } from '@kbn/monitoring-collection-plugin/server'; import { SharePluginStart } from '@kbn/share-plugin/server'; -import { ServerlessPluginSetup } from '@kbn/serverless/server'; import { RuleTypeRegistry } from './rule_type_registry'; import { TaskRunnerFactory } from './task_runner'; @@ -134,7 +133,7 @@ export const LEGACY_EVENT_LOG_ACTIONS = { resolvedInstance: 'resolved-instance', }; -export interface PluginSetupContract { +export interface AlertingServerSetup { registerConnectorAdapter< RuleActionParams extends ConnectorAdapterParams = ConnectorAdapterParams, ConnectorParams extends ConnectorAdapterParams = ConnectorAdapterParams @@ -169,19 +168,15 @@ export interface PluginSetupContract { getDataStreamAdapter: () => DataStreamAdapter; } -export interface PluginStartContract { +export interface AlertingServerStart { listTypes: RuleTypeRegistry['list']; - getAllTypes: RuleTypeRegistry['getAllTypes']; getType: RuleTypeRegistry['get']; getAlertIndicesAlias: GetAlertIndicesAlias; - - getRulesClientWithRequest(request: KibanaRequest): RulesClientApi; - + getRulesClientWithRequest(request: KibanaRequest): Promise; getAlertingAuthorizationWithRequest( request: KibanaRequest - ): PublicMethodsOf; - + ): Promise>; getFrameworkHealth: () => Promise; } @@ -198,7 +193,6 @@ export interface AlertingPluginsSetup { data: DataPluginSetup; features: FeaturesPluginSetup; unifiedSearch: UnifiedSearchServerPluginSetup; - serverless?: ServerlessPluginSetup; } export interface AlertingPluginsStart { @@ -213,7 +207,6 @@ export interface AlertingPluginsStart { data: DataPluginStart; dataViews: DataViewsPluginStart; share: SharePluginStart; - serverless?: ServerlessPluginSetup; } export class AlertingPlugin { @@ -239,6 +232,7 @@ export class AlertingPlugin { private pluginStop$: Subject; private dataStreamAdapter?: DataStreamAdapter; private backfillClient?: BackfillClient; + private readonly isServerless: boolean; private nodeRoles: PluginInitializerContext['node']['roles']; private readonly connectorAdapterRegistry = new ConnectorAdapterRegistry(); @@ -256,19 +250,20 @@ export class AlertingPlugin { this.kibanaVersion = initializerContext.env.packageInfo.version; this.inMemoryMetrics = new InMemoryMetrics(initializerContext.logger.get('in_memory_metrics')); this.pluginStop$ = new ReplaySubject(1); + this.isServerless = initializerContext.env.packageInfo.buildFlavor === 'serverless'; } public setup( core: CoreSetup, plugins: AlertingPluginsSetup - ): PluginSetupContract { + ): AlertingServerSetup { this.kibanaBaseUrl = core.http.basePath.publicBaseUrl; this.licenseState = new LicenseState(plugins.licensing.license$); this.security = plugins.security; const elasticsearchAndSOAvailability$ = getElasticsearchAndSOAvailability(core.status.core$); - const useDataStreamForAlerts = !!plugins.serverless; + const useDataStreamForAlerts = this.isServerless; this.dataStreamAdapter = getDataStreamAdapter({ useDataStreamForAlerts }); core.capabilities.registerProvider(() => { @@ -282,7 +277,7 @@ export class AlertingPlugin { }; }); - plugins.features.registerKibanaFeature(getRulesSettingsFeature(!!plugins.serverless)); + plugins.features.registerKibanaFeature(getRulesSettingsFeature(this.isServerless)); plugins.features.registerKibanaFeature(maintenanceWindowFeature); @@ -330,6 +325,7 @@ export class AlertingPlugin { .getStartServices() .then(([{ elasticsearch }]) => elasticsearch.client.asInternalUser), elasticsearchAndSOAvailability$, + isServerless: this.isServerless, }); } } @@ -410,7 +406,8 @@ export class AlertingPlugin { getAlertIndicesAlias: createGetAlertIndicesAliasFn(this.ruleTypeRegistry!), encryptedSavedObjects: plugins.encryptedSavedObjects, config$: plugins.unifiedSearch.autocomplete.getInitializerContextConfig().create(), - isServerless: !!plugins.serverless, + isServerless: this.isServerless, + docLinks: core.docLinks, }); return { @@ -490,7 +487,7 @@ export class AlertingPlugin { }; } - public start(core: CoreStart, plugins: AlertingPluginsStart): PluginStartContract { + public start(core: CoreStart, plugins: AlertingPluginsStart): AlertingServerStart { const { isESOCanEncrypt, logger, @@ -517,7 +514,6 @@ export class AlertingPlugin { alertingAuthorizationClientFactory.initialize({ ruleTypeRegistry: ruleTypeRegistry!, - securityPluginSetup: security, securityPluginStart: plugins.security, async getSpace(request: KibanaRequest) { return plugins.spaces?.spacesService.getActiveSpace(request); @@ -561,7 +557,7 @@ export class AlertingPlugin { logger: this.logger, savedObjectsService: core.savedObjects, securityService: core.security, - isServerless: !!plugins.serverless, + isServerless: this.isServerless, }); maintenanceWindowClientFactory.initialize({ @@ -571,7 +567,7 @@ export class AlertingPlugin { uiSettings: core.uiSettings, }); - const getRulesClientWithRequest = (request: KibanaRequest) => { + const getRulesClientWithRequest = async (request: KibanaRequest) => { if (isESOCanEncrypt !== true) { throw new Error( `Unable to create alerts client because the Encrypted Saved Objects plugin is missing encryption key. Please set xpack.encryptedSavedObjects.encryptionKey in the kibana.yml or use the bin/kibana-encryption-keys command.` @@ -580,7 +576,7 @@ export class AlertingPlugin { return rulesClientFactory!.create(request, core.savedObjects); }; - const getAlertingAuthorizationWithRequest = (request: KibanaRequest) => { + const getAlertingAuthorizationWithRequest = async (request: KibanaRequest) => { return alertingAuthorizationClientFactory!.create(request); }; @@ -614,28 +610,29 @@ export class AlertingPlugin { logger, }), maxAlerts: this.config.rules.run.alerts.max, - maxEphemeralActionsPerRule: this.config.maxEphemeralActionsPerAlert, ruleTypeRegistry: this.ruleTypeRegistry!, rulesSettingsService: new RulesSettingsService({ cacheInterval: this.config.rulesSettings.cacheInterval, getRulesSettingsClientWithRequest, - isServerless: !!plugins.serverless, + isServerless: this.isServerless, logger, }), savedObjects: core.savedObjects, share: plugins.share, spaceIdToNamespace, - supportsEphemeralTasks: plugins.taskManager.supportsEphemeralTasks(), uiSettings: core.uiSettings, usageCounter: this.usageCounter, + isServerless: this.isServerless, }); this.eventLogService!.registerSavedObjectProvider(RULE_SAVED_OBJECT_TYPE, (request) => { - const client = getRulesClientWithRequest(request); - return (objects?: SavedObjectsBulkGetObject[]) => - objects + return async (objects?: SavedObjectsBulkGetObject[]) => { + const client = await getRulesClientWithRequest(request); + + return objects ? Promise.all(objects.map(async (objectItem) => await client.get({ id: objectItem.id }))) : Promise.resolve([]); + }; }); this.eventLogService!.isEsContextReady() diff --git a/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts b/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts index b2f25d349ec7..a24ea147d411 100644 --- a/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts +++ b/x-pack/plugins/alerting/server/routes/_mock_handler_arguments.ts @@ -59,7 +59,7 @@ export function mockHandlerArguments( alerting: { listTypes, getRulesClient() { - return rulesClient || rulesClientMock.create(); + return Promise.resolve(rulesClient || rulesClientMock.create()); }, getRulesSettingsClient() { return rulesSettingsClient || rulesSettingsClientMock.create(); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts index 6c343ac12518..66d90671ac1b 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/delete/delete_backfill_route.ts @@ -29,7 +29,8 @@ export const deleteBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: DeleteBackfillRequestParamsV1 = req.params; await rulesClient.deleteBackfill(params.id); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts index fea2925c0983..be1ff25ef593 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/find/find_backfill_route.ts @@ -34,7 +34,8 @@ export const findBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const query: FindBackfillRequestQueryV1 = req.query; const result = await rulesClient.findBackfill(transformRequestV1(query)); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts index bfb178d875c8..5758bb6ba805 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/get/get_backfill_route.ts @@ -31,7 +31,8 @@ export const getBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: GetBackfillRequestParamsV1 = req.params; const result = await rulesClient.getBackfill(params.id); diff --git a/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts b/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts index 466c69b2b6aa..77eb5c9355cf 100644 --- a/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts +++ b/x-pack/plugins/alerting/server/routes/backfill/apis/schedule/schedule_backfill_route.ts @@ -29,7 +29,8 @@ export const scheduleBackfillRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: ScheduleBackfillRequestBodyV1 = req.body; const result = await rulesClient.scheduleBackfill(transformRequestV1(body)); diff --git a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts index f726073ed084..83773ab8531b 100644 --- a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts +++ b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.test.ts @@ -25,7 +25,7 @@ jest.mock('../../../../lib/license_api_access', () => ({ const alerting = alertsMock.createStart(); const currentDate = new Date().toISOString(); -const ruleTypes = [ +const ruleTypes: RegistryAlertTypeWithAuth[] = [ { id: '1', name: 'name', @@ -48,12 +48,11 @@ const ruleTypes = [ category: 'test', producer: 'test', enabledInLicense: true, - minimumScheduleInterval: '1m', defaultScheduleInterval: '10m', hasAlertsMappings: false, hasFieldsForAAD: false, validLegacyConsumers: [], - } as RegistryAlertTypeWithAuth, + }, ]; beforeEach(() => { @@ -76,7 +75,7 @@ beforeEach(() => { describe('healthRoute', () => { it('registers the route', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -89,7 +88,7 @@ describe('healthRoute', () => { }); it('queries the usage api', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -113,7 +112,7 @@ describe('healthRoute', () => { }); it('throws error when user does not have any access to any rule types', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set()); + rulesClient.listRuleTypes.mockResolvedValueOnce([]); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -139,7 +138,7 @@ describe('healthRoute', () => { }); it('evaluates whether Encrypted Saved Objects is missing encryption key', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); @@ -180,7 +179,7 @@ describe('healthRoute', () => { }); test('when ES security status cannot be determined from license state, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); @@ -222,7 +221,7 @@ describe('healthRoute', () => { }); test('when ES security is disabled, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); @@ -264,7 +263,7 @@ describe('healthRoute', () => { }); test('when ES security is enabled but user cannot generate api keys, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); @@ -306,7 +305,7 @@ describe('healthRoute', () => { }); test('when ES security is enabled and user can generate api keys, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); diff --git a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts index 34ef56a51daa..4daf510b6a64 100644 --- a/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts +++ b/x-pack/plugins/alerting/server/routes/framework/apis/health/health.ts @@ -48,8 +48,9 @@ export const healthRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { try { const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); // Verify that user has access to at least one rule type - const ruleTypes = Array.from(await alertingContext.getRulesClient().listRuleTypes()); + const ruleTypes = Array.from(await rulesClient.listRuleTypes()); if (ruleTypes.length > 0) { const alertingFrameworkHealth = await alertingContext.getFrameworkHealth(); diff --git a/x-pack/plugins/alerting/server/routes/get_action_error_log.ts b/x-pack/plugins/alerting/server/routes/get_action_error_log.ts index 5da2189c1d43..7406d07c3fa2 100644 --- a/x-pack/plugins/alerting/server/routes/get_action_error_log.ts +++ b/x-pack/plugins/alerting/server/routes/get_action_error_log.ts @@ -69,7 +69,8 @@ export const getActionErrorLogRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const withAuth = req.query.with_auth; const rewrittenReq = rewriteReq({ id, ...req.query }); diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts index 795b473dc8c6..48ea073369d2 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts @@ -46,7 +46,8 @@ export const getGlobalExecutionKPIRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); return res.ok({ body: await rulesClient.getGlobalExecutionKpiWithAuth(rewriteReq(req.query)), }); diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts index 9c9e09e81bd4..13ea133e21a8 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts @@ -71,7 +71,8 @@ export const getGlobalExecutionLogRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); return res.ok({ body: await rulesClient.getGlobalExecutionLogWithAuth(rewriteReq(req.query)), }); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts index 7eaf5d4645ec..937db706199e 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_alert_summary.ts @@ -75,7 +75,8 @@ export const getRuleAlertSummaryRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const summary = await rulesClient.getAlertSummary(rewriteReq({ id, ...req.query })); return res.ok({ body: rewriteBodyRes(summary) }); diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts index af15520d3c32..302ac0293a44 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_kpi.ts @@ -48,7 +48,8 @@ export const getRuleExecutionKPIRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; return res.ok({ body: await rulesClient.getRuleExecutionKPI(rewriteReq({ id, ...req.query })), diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts index 619bc82bd637..4eccefd171f0 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.ts @@ -73,7 +73,8 @@ export const getRuleExecutionLogRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; return res.ok({ body: await rulesClient.getExecutionLogForRule(rewriteReq({ id, ...req.query })), diff --git a/x-pack/plugins/alerting/server/routes/get_rule_state.ts b/x-pack/plugins/alerting/server/routes/get_rule_state.ts index 7530f1d4964c..1a2b17b8f674 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_state.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_state.ts @@ -47,7 +47,8 @@ export const getRuleStateRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const state = await rulesClient.getAlertState({ id }); return state ? res.ok({ body: rewriteBodyRes(state) }) : res.noContent(); diff --git a/x-pack/plugins/alerting/server/routes/index.ts b/x-pack/plugins/alerting/server/routes/index.ts index 1a274692cefe..d1fc9989be5e 100644 --- a/x-pack/plugins/alerting/server/routes/index.ts +++ b/x-pack/plugins/alerting/server/routes/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { IRouter } from '@kbn/core/server'; +import { DocLinksServiceSetup, IRouter } from '@kbn/core/server'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import type { ConfigSchema } from '@kbn/unified-search-plugin/server/config'; @@ -81,6 +81,7 @@ export interface RouteOptions { usageCounter?: UsageCounter; config$?: Observable; isServerless?: boolean; + docLinks: DocLinksServiceSetup; } export function defineRoutes(opts: RouteOptions) { diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts index 52917ad5f302..f3df843899f2 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.test.ts @@ -16,6 +16,7 @@ import { Rule, RuleSystemAction } from '../../../common/rule'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -32,6 +33,7 @@ beforeEach(() => { }); describe('createAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const createdAt = new Date(); const updatedAt = new Date(); @@ -104,6 +106,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -179,6 +182,7 @@ describe('createAlertRoute', () => { encryptedSavedObjects, usageCounter: mockUsageCounter, isServerless: true, + docLinks, }); const [config] = router.post.mock.calls[0]; @@ -204,6 +208,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -281,6 +286,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -359,6 +365,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -426,7 +433,7 @@ describe('createAlertRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createAlertRoute({ router, licenseState, encryptedSavedObjects }); + createAlertRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -448,7 +455,7 @@ describe('createAlertRoute', () => { throw new Error('OMG'); }); - createAlertRoute({ router, licenseState, encryptedSavedObjects }); + createAlertRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -466,7 +473,7 @@ describe('createAlertRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createAlertRoute({ router, licenseState, encryptedSavedObjects }); + createAlertRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -491,6 +498,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [, handler] = router.post.mock.calls[0]; rulesClient.create.mockResolvedValueOnce(createResult); @@ -511,6 +519,7 @@ describe('createAlertRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -570,4 +579,39 @@ describe('createAlertRoute', () => { body: createResult, }); }); + + it('should be deprecated', () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); + const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); + + createAlertRoute({ + router, + licenseState, + encryptedSavedObjects, + usageCounter: mockUsageCounter, + docLinks, + }); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id?}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/create.ts b/x-pack/plugins/alerting/server/routes/legacy/create.ts index 333877b7df49..8346ec37edf9 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/create.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/create.ts @@ -49,6 +49,7 @@ export const createAlertRoute = ({ licenseState, usageCounter, isServerless, + docLinks, }: RouteOptions) => { router.post( { @@ -65,8 +66,15 @@ export const createAlertRoute = ({ access: isServerless ? 'internal' : 'public', summary: 'Create an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id?}', + }, + }, }, }, handleDisabledApiKeysError( @@ -76,7 +84,9 @@ export const createAlertRoute = ({ if (!context.alerting) { return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } - const rulesClient = (await context.alerting).getRulesClient(); + + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const alert = req.body; const params = req.params; const notifyWhen = alert?.notifyWhen ? (alert.notifyWhen as RuleNotifyWhenType) : null; diff --git a/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts b/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts index 95a28904f479..d8fd0effc50e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/delete.test.ts @@ -13,6 +13,7 @@ import { verifyApiAccess } from '../../lib/license_api_access'; import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -29,11 +30,13 @@ beforeEach(() => { }); describe('deleteAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('deletes an alert with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - deleteAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState, docLinks); const [config, handler] = router.delete.mock.calls[0]; @@ -70,7 +73,7 @@ describe('deleteAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - deleteAlertRoute(router, licenseState, undefined, true); + deleteAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.delete.mock.calls[0]; @@ -82,7 +85,7 @@ describe('deleteAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - deleteAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState, docLinks); const [, handler] = router.delete.mock.calls[0]; @@ -108,7 +111,7 @@ describe('deleteAlertRoute', () => { throw new Error('OMG'); }); - deleteAlertRoute(router, licenseState); + deleteAlertRoute(router, licenseState, docLinks); const [, handler] = router.delete.mock.calls[0]; @@ -132,7 +135,7 @@ describe('deleteAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - deleteAlertRoute(router, licenseState, mockUsageCounter); + deleteAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.delete.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -140,4 +143,30 @@ describe('deleteAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('delete', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + deleteAlertRoute(router, licenseState, docLinks); + + const [config] = router.delete.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "DELETE", + "newApiPath": "/api/alerting/rule/{id}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/delete.ts b/x-pack/plugins/alerting/server/routes/legacy/delete.ts index 2b63de9e4ee7..738633c61f74 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/delete.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/delete.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -20,6 +21,7 @@ const paramSchema = schema.object({ export const deleteAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -33,8 +35,15 @@ export const deleteAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Delete an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'DELETE', + newApiPath: '/api/alerting/rule/{id}', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -43,7 +52,8 @@ export const deleteAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('delete', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; await rulesClient.delete({ id }); return res.noContent(); diff --git a/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts index 1c8ee110aca9..13fec185429e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.test.ts @@ -12,6 +12,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('disableAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('disables an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - disableAlertRoute(router, licenseState); + disableAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('disableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - disableAlertRoute(router, licenseState, undefined, true); + disableAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('disableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - disableAlertRoute(router, licenseState); + disableAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('disableAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - disableAlertRoute(router, licenseState, mockUsageCounter); + disableAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -111,4 +114,30 @@ describe('disableAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('disable', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + disableAlertRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_disable", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/disable.ts b/x-pack/plugins/alerting/server/routes/legacy/disable.ts index 0c6f3cf062a0..e69a176776e0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/disable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/disable.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -21,6 +22,7 @@ const paramSchema = schema.object({ export const disableAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -34,8 +36,15 @@ export const disableAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Disable an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_disable', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -44,7 +53,8 @@ export const disableAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('disable', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.disableRule({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts index d2ed24cc3fa1..88df304ea07c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.test.ts @@ -12,6 +12,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('enableAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('enables an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - enableAlertRoute(router, licenseState); + enableAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('enableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - enableAlertRoute(router, licenseState, undefined, true); + enableAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('enableAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - enableAlertRoute(router, licenseState); + enableAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('enableAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - enableAlertRoute(router, licenseState, mockUsageCounter); + enableAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -111,4 +114,30 @@ describe('enableAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('enable', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + enableAlertRoute(router, licenseState, docLinks, undefined, true); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_enable", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/enable.ts b/x-pack/plugins/alerting/server/routes/legacy/enable.ts index d52eaa784f67..289b4050e059 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/enable.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/enable.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -22,6 +23,7 @@ const paramSchema = schema.object({ export const enableAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -35,8 +37,15 @@ export const enableAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Enable an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_enable', + }, + }, }, }, handleDisabledApiKeysError( @@ -46,7 +55,8 @@ export const enableAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('enable', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.enableRule({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.test.ts b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts index 0b8584be43da..646f18fa072e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.test.ts @@ -15,6 +15,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { trackLegacyTerminology } from '../lib/track_legacy_terminology'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -35,11 +36,13 @@ beforeEach(() => { }); describe('findAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('finds alerts with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -100,7 +103,7 @@ describe('findAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState, undefined, true); + findAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -112,7 +115,7 @@ describe('findAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -147,7 +150,7 @@ describe('findAlertRoute', () => { throw new Error('OMG'); }); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -173,7 +176,7 @@ describe('findAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - findAlertRoute(router, licenseState, mockUsageCounter); + findAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const findResult = { page: 1, @@ -195,7 +198,7 @@ describe('findAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - findAlertRoute(router, licenseState, mockUsageCounter); + findAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const findResult = { @@ -232,7 +235,7 @@ describe('findAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - findAlertRoute(router, licenseState, mockUsageCounter); + findAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const findResult = { page: 1, @@ -263,7 +266,7 @@ describe('findAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - findAlertRoute(router, licenseState); + findAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -407,4 +410,30 @@ describe('findAlertRoute', () => { body: omit(findResult, 'data[0].systemActions'), }); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findAlertRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rules/_find", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/find.ts b/x-pack/plugins/alerting/server/routes/legacy/find.ts index fa309ae51f2e..de1e5f8c226a 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/find.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/find.ts @@ -9,6 +9,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { estypes } from '@elastic/elasticsearch'; import { KueryNode } from '@kbn/es-query'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; @@ -64,6 +65,7 @@ const querySchema = schema.object({ export const findAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -79,8 +81,15 @@ export const findAlertRoute = ( tags: ['oas-tag:alerting'], description: 'Gets a paginated set of alerts. Alert `params` are stored as a flattened field type and analyzed as keywords. As alerts change in Kibana, the results on each page of the response also change. Use the find API for traditional paginated results, but avoid using it to export large amounts of data.', - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rules/_find', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -95,7 +104,8 @@ export const findAlertRoute = ( ) as string[], usageCounter ); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const query = req.query; const renameMap = { diff --git a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts index f27210c77387..ca8154fc7ada 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.test.ts @@ -14,6 +14,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { Rule, RuleSystemAction } from '../../../common'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -29,6 +30,7 @@ beforeEach(() => { }); describe('getAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const mockedAlert: Rule<{ bar: true; }> = { @@ -82,7 +84,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}"`); @@ -111,7 +113,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState, undefined, true); + getAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}"`); @@ -122,7 +124,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -149,7 +151,7 @@ describe('getAlertRoute', () => { throw new Error('OMG'); }); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -174,7 +176,7 @@ describe('getAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - getAlertRoute(router, licenseState, mockUsageCounter); + getAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; rulesClient.get.mockResolvedValueOnce(mockedAlert); @@ -190,7 +192,7 @@ describe('getAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertRoute(router, licenseState); + getAlertRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/alert/{id}"`); @@ -213,4 +215,29 @@ describe('getAlertRoute', () => { body: mockedAlert, }); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getAlertRoute(router, licenseState, docLinks); + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rule/{id}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get.ts b/x-pack/plugins/alerting/server/routes/legacy/get.ts index e5eff52bf02d..19fc0f7ff49e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; import { LEGACY_BASE_ALERT_API_PATH } from '../../../common'; @@ -20,6 +21,7 @@ const paramSchema = schema.object({ export const getAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -33,8 +35,15 @@ export const getAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rule/{id}', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -43,7 +52,8 @@ export const getAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('get', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const { systemActions, ...rule } = await rulesClient.get({ id, excludeFromPublicApi: true }); return res.ok({ diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts index 4ecc085c3bb4..cc3deaad9af9 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.test.ts @@ -14,6 +14,7 @@ import { rulesClientMock } from '../../rules_client.mock'; import { AlertSummary } from '../../types'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -29,6 +30,7 @@ beforeEach(() => { }); describe('getAlertInstanceSummaryRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const dateString = new Date().toISOString(); const mockedAlertInstanceSummary: AlertSummary = { id: '', @@ -55,7 +57,7 @@ describe('getAlertInstanceSummaryRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertInstanceSummaryRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -94,7 +96,7 @@ describe('getAlertInstanceSummaryRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertInstanceSummaryRoute(router, licenseState, undefined, true); + getAlertInstanceSummaryRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -106,7 +108,7 @@ describe('getAlertInstanceSummaryRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertInstanceSummaryRoute(router, licenseState); + getAlertInstanceSummaryRoute(router, licenseState, docLinks); const [, handler] = router.get.mock.calls[0]; @@ -136,7 +138,7 @@ describe('getAlertInstanceSummaryRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - getAlertInstanceSummaryRoute(router, licenseState, mockUsageCounter); + getAlertInstanceSummaryRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; rulesClient.getAlertSummary.mockResolvedValueOnce(mockedAlertInstanceSummary); @@ -148,4 +150,28 @@ describe('getAlertInstanceSummaryRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('instanceSummary', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getAlertInstanceSummaryRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "type": "remove", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts index 58a75dd68dce..0e50601a1fd4 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_instance_summary.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -30,6 +31,7 @@ const rewriteBodyRes = ({ ruleTypeId, alerts, ...rest }: AlertSummary) => ({ export const getAlertInstanceSummaryRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -44,8 +46,13 @@ export const getAlertInstanceSummaryRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get an alert summary', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'remove', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -54,7 +61,8 @@ export const getAlertInstanceSummaryRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('instanceSummary', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const { dateStart } = req.query; const summary = await rulesClient.getAlertSummary({ id, dateStart }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts index f8f1d4caeed9..ca79291b23db 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.test.ts @@ -13,6 +13,7 @@ import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { rulesClientMock } from '../../rules_client.mock'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { RULE_SAVED_OBJECT_TYPE } from '../../saved_objects'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,6 +29,7 @@ beforeEach(() => { }); describe('getAlertStateRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const mockedAlertState = { alertTypeState: { some: 'value', @@ -50,7 +52,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState); + getAlertStateRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -87,7 +89,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState, undefined, true); + getAlertStateRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -99,7 +101,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState); + getAlertStateRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -135,7 +137,7 @@ describe('getAlertStateRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - getAlertStateRoute(router, licenseState); + getAlertStateRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -175,7 +177,7 @@ describe('getAlertStateRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - getAlertStateRoute(router, licenseState, mockUsageCounter); + getAlertStateRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -183,4 +185,28 @@ describe('getAlertStateRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('state', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + getAlertStateRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "type": "remove", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts index e952ef871966..f9db44c1e9a0 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/get_alert_state.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -20,6 +21,7 @@ const paramSchema = schema.object({ export const getAlertStateRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -33,8 +35,13 @@ export const getAlertStateRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get the state of an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'remove', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -43,7 +50,8 @@ export const getAlertStateRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('state', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const state = await rulesClient.getAlertState({ id }); return state ? res.ok({ body: state }) : res.noContent(); diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.test.ts b/x-pack/plugins/alerting/server/routes/legacy/health.test.ts index 6c0b3ae6f67a..fea24b831e97 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/health.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/health.test.ts @@ -16,6 +16,7 @@ import { RecoveredActionGroup } from '../../types'; import { alertsMock } from '../../mocks'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; import { RegistryAlertTypeWithAuth } from '../../authorization'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -80,13 +81,15 @@ beforeEach(() => { }); describe('healthRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('registers the route', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [config] = router.get.mock.calls[0]; @@ -95,12 +98,12 @@ describe('healthRoute', () => { }); it('should have internal access for serverless', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - healthRoute(router, licenseState, encryptedSavedObjects, undefined, true); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -109,12 +112,12 @@ describe('healthRoute', () => { }); it('throws error when user does not have any access to any rule types', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set()); + rulesClient.listRuleTypes.mockResolvedValueOnce([]); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: false }); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -135,12 +138,12 @@ describe('healthRoute', () => { }); it('evaluates whether Encrypted Saved Objects is missing encryption key', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: false }); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -192,13 +195,13 @@ describe('healthRoute', () => { }); test('when ES security status cannot be determined from license state, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(null); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -250,13 +253,13 @@ describe('healthRoute', () => { }); test('when ES security is disabled, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(false); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -308,13 +311,13 @@ describe('healthRoute', () => { }); test('when ES security is enabled but user cannot generate api keys, isSufficientlySecure should return false', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(true); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -366,13 +369,13 @@ describe('healthRoute', () => { }); test('when ES security is enabled and user can generate api keys, isSufficientlySecure should return true', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const router = httpServiceMock.createRouter(); const licenseState = licenseStateMock.create(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); licenseState.getIsSecurityEnabled.mockReturnValueOnce(true); - healthRoute(router, licenseState, encryptedSavedObjects); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( @@ -424,14 +427,14 @@ describe('healthRoute', () => { }); it('should track every call', async () => { - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - healthRoute(router, licenseState, encryptedSavedObjects, mockUsageCounter); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: { id: '1' } }, [ 'ok', @@ -439,4 +442,32 @@ describe('healthRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('health', mockUsageCounter); }); + + it('should be deprecated', async () => { + rulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); + const router = httpServiceMock.createRouter(); + + const licenseState = licenseStateMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rule/_health", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/health.ts b/x-pack/plugins/alerting/server/routes/legacy/health.ts index 8f67767941fd..b463298837f4 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/health.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/health.ts @@ -7,6 +7,7 @@ import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -18,6 +19,7 @@ export function healthRoute( router: AlertingRouter, licenseState: ILicenseState, encryptedSavedObjects: EncryptedSavedObjectsPluginSetup, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) { @@ -29,8 +31,15 @@ export function healthRoute( access: isServerless ? 'internal' : 'public', summary: 'Get the alerting framework health', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rule/_health', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -41,8 +50,9 @@ export function healthRoute( trackLegacyRouteUsage('health', usageCounter); try { const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); // Verify that user has access to at least one rule type - const ruleTypes = Array.from(await alertingContext.getRulesClient().listRuleTypes()); + const ruleTypes = Array.from(await rulesClient.listRuleTypes()); if (ruleTypes.length > 0) { const alertingFrameworkHealth = await alertingContext.getFrameworkHealth(); diff --git a/x-pack/plugins/alerting/server/routes/legacy/index.ts b/x-pack/plugins/alerting/server/routes/legacy/index.ts index 99220106d5ac..e9551d938e6c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/index.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/index.ts @@ -24,22 +24,23 @@ import { healthRoute } from './health'; import { RouteOptions } from '..'; export function defineLegacyRoutes(opts: RouteOptions) { - const { router, licenseState, encryptedSavedObjects, usageCounter, isServerless } = opts; + const { router, licenseState, encryptedSavedObjects, usageCounter, isServerless, docLinks } = + opts; createAlertRoute(opts); - deleteAlertRoute(router, licenseState, usageCounter, isServerless); - findAlertRoute(router, licenseState, usageCounter, isServerless); - getAlertRoute(router, licenseState, usageCounter, isServerless); - getAlertStateRoute(router, licenseState, usageCounter, isServerless); - getAlertInstanceSummaryRoute(router, licenseState, usageCounter, isServerless); - listAlertTypesRoute(router, licenseState, usageCounter, isServerless); - updateAlertRoute(router, licenseState, usageCounter, isServerless); - enableAlertRoute(router, licenseState, usageCounter, isServerless); - disableAlertRoute(router, licenseState, usageCounter, isServerless); - updateApiKeyRoute(router, licenseState, usageCounter, isServerless); - muteAllAlertRoute(router, licenseState, usageCounter, isServerless); - unmuteAllAlertRoute(router, licenseState, usageCounter, isServerless); - muteAlertInstanceRoute(router, licenseState, usageCounter, isServerless); - unmuteAlertInstanceRoute(router, licenseState, usageCounter, isServerless); - healthRoute(router, licenseState, encryptedSavedObjects, usageCounter, isServerless); + deleteAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + findAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + getAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + getAlertStateRoute(router, licenseState, docLinks, usageCounter, isServerless); + getAlertInstanceSummaryRoute(router, licenseState, docLinks, usageCounter, isServerless); + listAlertTypesRoute(router, licenseState, docLinks, usageCounter, isServerless); + updateAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + enableAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + disableAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + updateApiKeyRoute(router, licenseState, docLinks, usageCounter, isServerless); + muteAllAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + unmuteAllAlertRoute(router, licenseState, docLinks, usageCounter, isServerless); + muteAlertInstanceRoute(router, licenseState, docLinks, usageCounter, isServerless); + unmuteAlertInstanceRoute(router, licenseState, docLinks, usageCounter, isServerless); + healthRoute(router, licenseState, encryptedSavedObjects, docLinks, usageCounter, isServerless); } diff --git a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts index 80298f7fd288..27e9d7ce4486 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.test.ts @@ -15,6 +15,7 @@ import { rulesClientMock } from '../../rules_client.mock'; import { RecoveredActionGroup } from '../../../common'; import { RegistryAlertTypeWithAuth } from '../../authorization'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -31,18 +32,19 @@ beforeEach(() => { }); describe('listAlertTypesRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); it('lists alert types with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - listAlertTypesRoute(router, licenseState); + listAlertTypesRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; expect(config.path).toMatchInlineSnapshot(`"/api/alerts/list_alert_types"`); expect(config.options?.access).toBe('public'); - const listTypes = [ + const listTypes: RegistryAlertTypeWithAuth[] = [ { id: '1', name: 'name', @@ -67,9 +69,10 @@ describe('listAlertTypesRoute', () => { hasAlertsMappings: false, hasFieldsForAAD: false, validLegacyConsumers: [], - } as RegistryAlertTypeWithAuth, + }, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok']); @@ -119,7 +122,7 @@ describe('listAlertTypesRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - listAlertTypesRoute(router, licenseState, undefined, true); + listAlertTypesRoute(router, licenseState, docLinks, undefined, true); const [config] = router.get.mock.calls[0]; @@ -131,7 +134,7 @@ describe('listAlertTypesRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - listAlertTypesRoute(router, licenseState); + listAlertTypesRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -165,7 +168,7 @@ describe('listAlertTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -188,7 +191,7 @@ describe('listAlertTypesRoute', () => { throw new Error('OMG'); }); - listAlertTypesRoute(router, licenseState); + listAlertTypesRoute(router, licenseState, docLinks); const [config, handler] = router.get.mock.calls[0]; @@ -222,7 +225,7 @@ describe('listAlertTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -243,9 +246,9 @@ describe('listAlertTypesRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set([])); + rulesClient.listRuleTypes.mockResolvedValueOnce([]); - listAlertTypesRoute(router, licenseState, mockUsageCounter); + listAlertTypesRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.get.mock.calls[0]; const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -255,4 +258,30 @@ describe('listAlertTypesRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('listAlertTypes', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + listAlertTypesRoute(router, licenseState, docLinks); + + const [config] = router.get.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/alerting/rule_types", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts index 35d6a7efeeee..f4f2bc7936b3 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/list_alert_types.ts @@ -5,6 +5,7 @@ * 2.0. */ import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -14,6 +15,7 @@ import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; export const listAlertTypesRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -25,8 +27,15 @@ export const listAlertTypesRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Get the alert types', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/alerting/rule_types', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -36,8 +45,10 @@ export const listAlertTypesRoute = ( } trackLegacyRouteUsage('listAlertTypes', usageCounter); const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); + return res.ok({ - body: Array.from(await alertingContext.getRulesClient().listRuleTypes()), + body: Array.from(await rulesClient.listRuleTypes()), }); }) ); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts index 9a9ea27ba675..d80cf415283d 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('muteAllAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('mute an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAllAlertRoute(router, licenseState); + muteAllAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('muteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAllAlertRoute(router, licenseState, undefined, true); + muteAllAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('muteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAllAlertRoute(router, licenseState); + muteAllAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('muteAllAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - muteAllAlertRoute(router, licenseState, mockUsageCounter); + muteAllAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -111,4 +114,30 @@ describe('muteAllAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('muteAll', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAllAlertRoute(router, licenseState, docLinks, undefined, true); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_mute_all", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts index 5c4fc1542ef5..75c860167f21 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_all.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -21,6 +22,7 @@ const paramSchema = schema.object({ export const muteAllAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -34,8 +36,15 @@ export const muteAllAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Mute all alert instances', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_mute_all', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -44,7 +53,8 @@ export const muteAllAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('muteAll', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.muteAll({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts index 7a142e4e9485..08e03a6d053e 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('muteAlertInstanceRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('mutes an alert instance', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAlertInstanceRoute(router, licenseState); + muteAlertInstanceRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -73,7 +76,7 @@ describe('muteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAlertInstanceRoute(router, licenseState, undefined, true); + muteAlertInstanceRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -87,7 +90,7 @@ describe('muteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - muteAlertInstanceRoute(router, licenseState); + muteAlertInstanceRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -111,7 +114,7 @@ describe('muteAlertInstanceRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - muteAlertInstanceRoute(router, licenseState, mockUsageCounter); + muteAlertInstanceRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -119,4 +122,30 @@ describe('muteAlertInstanceRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('muteInstance', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + muteAlertInstanceRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts index ab0b52d41de2..23225c387cca 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/mute_instance.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -24,6 +25,7 @@ const paramSchema = schema.object({ export const muteAlertInstanceRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -37,8 +39,15 @@ export const muteAlertInstanceRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Mute an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{rule_id}/alert/{alert_id}/_mute', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -49,7 +58,8 @@ export const muteAlertInstanceRoute = ( trackLegacyRouteUsage('muteInstance', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const renameMap = { alert_id: 'alertId', diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts index 6a88335ec98a..5ae337e6a3f5 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('unmuteAllAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('unmutes an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAllAlertRoute(router, licenseState); + unmuteAllAlertRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('unmuteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAllAlertRoute(router, licenseState, undefined, true); + unmuteAllAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('unmuteAllAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAllAlertRoute(router, licenseState); + unmuteAllAlertRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -103,7 +106,7 @@ describe('unmuteAllAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - unmuteAllAlertRoute(router, licenseState, mockUsageCounter); + unmuteAllAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -111,4 +114,30 @@ describe('unmuteAllAlertRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('unmuteAll', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAllAlertRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_unmute_all", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts index 0681e7d2cf01..2684ea60d733 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_all.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -21,6 +22,7 @@ const paramSchema = schema.object({ export const unmuteAllAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -34,8 +36,15 @@ export const unmuteAllAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Unmute all alert instances', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_unmute_all', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -44,7 +53,8 @@ export const unmuteAllAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('unmuteAll', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.unmuteAll({ id }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts index b04f376c38ca..b6fba61aaff8 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('unmuteAlertInstanceRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('unmutes an alert instance', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAlertInstanceRoute(router, licenseState); + unmuteAlertInstanceRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -73,7 +76,7 @@ describe('unmuteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAlertInstanceRoute(router, licenseState, undefined, true); + unmuteAlertInstanceRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -87,7 +90,7 @@ describe('unmuteAlertInstanceRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - unmuteAlertInstanceRoute(router, licenseState); + unmuteAlertInstanceRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -111,7 +114,7 @@ describe('unmuteAlertInstanceRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - unmuteAlertInstanceRoute(router, licenseState, mockUsageCounter); + unmuteAlertInstanceRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -119,4 +122,30 @@ describe('unmuteAlertInstanceRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('unmuteInstance', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + unmuteAlertInstanceRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts index 1101a2b5092e..e6122a92509b 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/unmute_instance.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -22,6 +23,7 @@ const paramSchema = schema.object({ export const unmuteAlertInstanceRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -35,8 +37,15 @@ export const unmuteAlertInstanceRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Unmute an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{rule_id}/alert/{alert_id}/_unmute', + }, + }, }, }, router.handleLegacyErrors(async function (context, req, res) { @@ -45,7 +54,8 @@ export const unmuteAlertInstanceRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('unmuteInstance', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { alertId, alertInstanceId } = req.params; try { await rulesClient.unmuteInstance({ alertId, alertInstanceId }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/update.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts index fc4a814c26a2..7aaee90b805c 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.test.ts @@ -15,6 +15,7 @@ import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { RuleNotifyWhen, SanitizedRule, RuleSystemAction } from '../../../common'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -30,6 +31,7 @@ beforeEach(() => { }); describe('updateAlertRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const mockedResponse = { id: '1', alertTypeId: '1', @@ -66,7 +68,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [config, handler] = router.put.mock.calls[0]; @@ -145,7 +147,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState, undefined, true); + updateAlertRoute(router, licenseState, docLinks, undefined, true); const [config] = router.put.mock.calls[0]; @@ -157,7 +159,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [, handler] = router.put.mock.calls[0]; @@ -204,7 +206,7 @@ describe('updateAlertRoute', () => { throw new Error('OMG'); }); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [, handler] = router.put.mock.calls[0]; @@ -247,7 +249,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [, handler] = router.put.mock.calls[0]; @@ -269,7 +271,7 @@ describe('updateAlertRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - updateAlertRoute(router, licenseState, mockUsageCounter); + updateAlertRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.put.mock.calls[0]; rulesClient.update.mockResolvedValueOnce(mockedResponse as unknown as SanitizedRule); const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ @@ -283,7 +285,7 @@ describe('updateAlertRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateAlertRoute(router, licenseState); + updateAlertRoute(router, licenseState, docLinks); const [config, handler] = router.put.mock.calls[0]; @@ -359,4 +361,30 @@ describe('updateAlertRoute', () => { expect(res.ok).toHaveBeenCalled(); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateAlertRoute(router, licenseState, docLinks); + + const [config] = router.put.mock.calls[0]; + + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "PUT", + "newApiPath": "/api/alerting/rule/rule/{id}", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/update.ts b/x-pack/plugins/alerting/server/routes/legacy/update.ts index 01adeb5c634d..3e3d3b5a480f 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -47,6 +48,7 @@ const bodySchema = schema.object({ export const updateAlertRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -61,8 +63,15 @@ export const updateAlertRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Update an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'PUT', + newApiPath: '/api/alerting/rule/rule/{id}', + }, + }, }, }, handleDisabledApiKeysError( @@ -72,7 +81,8 @@ export const updateAlertRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('update', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; const { name, actions, params, schedule, tags, throttle, notifyWhen } = req.body; try { diff --git a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts index cd5b6639ad00..cb2817af2ed5 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.test.ts @@ -13,6 +13,7 @@ import { mockHandlerArguments } from '../_mock_handler_arguments'; import { rulesClientMock } from '../../rules_client.mock'; import { RuleTypeDisabledError } from '../../lib/errors/rule_type_disabled'; import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); jest.mock('../../lib/license_api_access', () => ({ @@ -28,11 +29,13 @@ beforeEach(() => { }); describe('updateApiKeyRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('updates api key for an alert', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateApiKeyRoute(router, licenseState); + updateApiKeyRoute(router, licenseState, docLinks); const [config, handler] = router.post.mock.calls[0]; @@ -69,7 +72,7 @@ describe('updateApiKeyRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateApiKeyRoute(router, licenseState, undefined, true); + updateApiKeyRoute(router, licenseState, docLinks, undefined, true); const [config] = router.post.mock.calls[0]; @@ -81,7 +84,7 @@ describe('updateApiKeyRoute', () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); - updateApiKeyRoute(router, licenseState); + updateApiKeyRoute(router, licenseState, docLinks); const [, handler] = router.post.mock.calls[0]; @@ -105,7 +108,7 @@ describe('updateApiKeyRoute', () => { const mockUsageCountersSetup = usageCountersServiceMock.createSetupContract(); const mockUsageCounter = mockUsageCountersSetup.createUsageCounter('test'); - updateApiKeyRoute(router, licenseState, mockUsageCounter); + updateApiKeyRoute(router, licenseState, docLinks, mockUsageCounter); const [, handler] = router.post.mock.calls[0]; const [context, req, res] = mockHandlerArguments({ rulesClient }, { params: {}, body: {} }, [ 'ok', @@ -113,4 +116,29 @@ describe('updateApiKeyRoute', () => { await handler(context, req, res); expect(trackLegacyRouteUsage).toHaveBeenCalledWith('updateApiKey', mockUsageCounter); }); + + it('should be deprecated', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + updateApiKeyRoute(router, licenseState, docLinks); + + const [config] = router.post.mock.calls[0]; + expect(config.options?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201550$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201550\\$/, + "reason": Object { + "newApiMethod": "POST", + "newApiPath": "/api/alerting/rule/{id}/_update_api_key", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts index 30c51d3cdcf5..603a32176857 100644 --- a/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts +++ b/x-pack/plugins/alerting/server/routes/legacy/update_api_key.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; +import { DocLinksServiceSetup } from '@kbn/core/server'; import type { AlertingRouter } from '../../types'; import { ILicenseState } from '../../lib/license_state'; import { verifyApiAccess } from '../../lib/license_api_access'; @@ -22,6 +23,7 @@ const paramSchema = schema.object({ export const updateApiKeyRoute = ( router: AlertingRouter, licenseState: ILicenseState, + docLinks: DocLinksServiceSetup, usageCounter?: UsageCounter, isServerless?: boolean ) => { @@ -35,8 +37,15 @@ export const updateApiKeyRoute = ( access: isServerless ? 'internal' : 'public', summary: 'Update the API key for an alert', tags: ['oas-tag:alerting'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.alerting.legacyRuleApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'POST', + newApiPath: '/api/alerting/rule/{id}/_update_api_key', + }, + }, }, }, handleDisabledApiKeysError( @@ -46,7 +55,8 @@ export const updateApiKeyRoute = ( return res.badRequest({ body: 'RouteHandlerContext is not registered for alerting' }); } trackLegacyRouteUsage('updateApiKey', usageCounter); - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const { id } = req.params; try { await rulesClient.updateRuleApiKey({ id }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts index 77221de2d714..74a94cbba80a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.test.ts @@ -145,6 +145,7 @@ describe('aggregateRulesRoute', () => { { body: { default_search_operator: 'AND', + rule_type_ids: ['foo'], }, }, ['ok'] @@ -237,6 +238,9 @@ describe('aggregateRulesRoute', () => { }, "options": Object { "defaultSearchOperator": "AND", + "ruleTypeIds": Array [ + "foo", + ], }, }, ] diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts index 9b595858793f..05c5fc2167e1 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/aggregate_rules_route.ts @@ -37,7 +37,8 @@ export const aggregateRulesRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: AggregateRulesRequestBodyV1 = req.body; const options = transformAggregateQueryRequestV1({ ...body, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts index baa6b9bb46f9..ae13f08d0afa 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/aggregate/transforms/transform_aggregate_query_request/v1.ts @@ -13,13 +13,15 @@ export const transformAggregateQueryRequest: RewriteRequestCase ({ defaultSearchOperator, ...(hasReference ? { hasReference } : {}), ...(searchFields ? { searchFields } : {}), ...(search ? { search } : {}), - ...(filterConsumers ? { filterConsumers } : {}), + ...(ruleTypeIds ? { ruleTypeIds } : {}), + ...(consumers ? { consumers } : {}), ...(filter ? { filter } : {}), }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts index 8bd6f7fc1991..8548464d4481 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_delete/bulk_delete_rules_route.ts @@ -36,7 +36,8 @@ export const bulkDeleteRulesRoute = ({ handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkDeleteRulesRequestBodyV1 = req.body; const { filter, ids } = body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts index 724eda3ae7b8..315904efa40a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_disable/bulk_disable_rules_route.ts @@ -37,7 +37,8 @@ export const bulkDisableRulesRoute = ({ handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkDisableRulesRequestBodyV1 = req.body; const { filter, ids, untrack } = body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts index 4c853beeec25..f516b63031aa 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_edit/bulk_edit_rules_route.ts @@ -41,7 +41,8 @@ const buildBulkEditRulesRoute = ({ licenseState, path, router }: BuildBulkEditRu handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); const bulkEditData: BulkEditRulesRequestBodyV1 = req.body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts index da97949fd0fe..71932cb6d78b 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_enable/bulk_enable_rules_route.ts @@ -35,7 +35,8 @@ export const bulkEnableRulesRoute = ({ handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkEnableRulesRequestBodyV1 = req.body; try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts index 622218705b51..a43cc48d9563 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack/bulk_untrack_alerts_route.ts @@ -28,7 +28,8 @@ export const bulkUntrackAlertsRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkUntrackRequestBodyV1 = req.body; try { await rulesClient.bulkUntrackAlerts({ diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts index 3486005d3b58..ebaab0cb9840 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.test.ts @@ -45,7 +45,7 @@ describe('bulkUntrackAlertsByQueryRoute', () => { }, }, ], - feature_ids: ['o11y'], + rule_type_ids: ['o11y'], }; const [context, req, res] = mockHandlerArguments( @@ -62,7 +62,7 @@ describe('bulkUntrackAlertsByQueryRoute', () => { expect(rulesClient.bulkUntrackAlerts.mock.calls[0]).toEqual([ { query: requestBody.query, - featureIds: requestBody.feature_ids, + ruleTypeIds: requestBody.rule_type_ids, isUsingQuery: true, }, ]); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts index 5cebdb8c6e7f..735cd75b7f4a 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/bulk_untrack_alerts_by_query_route.ts @@ -29,7 +29,8 @@ export const bulkUntrackAlertsByQueryRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const body: BulkUntrackByQueryRequestBodyV1 = req.body; try { await rulesClient.bulkUntrackAlerts({ diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts index 87c58c48c4c6..dd346f8cc818 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/bulk_untrack_by_query/transforms/transform_bulk_untrack_alerts_by_query_body/v1.ts @@ -9,8 +9,8 @@ import type { BulkUntrackByQueryRequestBodyV1 } from '../../../../../../../commo export const transformBulkUntrackAlertsByQueryBody = ({ query, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, }: BulkUntrackByQueryRequestBodyV1) => ({ query, - featureIds, + ruleTypeIds, }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts index ea6460dfb946..0aa23886a9b4 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/clone/clone_rule_route.ts @@ -33,7 +33,8 @@ export const cloneRuleRoute = ( handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: CloneRuleRequestParamsV1 = req.params; try { // TODO (http-versioning): Remove this cast, this enables us to move forward diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts index cab395616161..f778b09854ab 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.test.ts @@ -18,6 +18,7 @@ import { RuleAction, RuleSystemAction, SanitizedRule } from '../../../../types'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { usageCountersServiceMock } from '@kbn/usage-collection-plugin/server/usage_counters/usage_counters_service.mock'; import { actionsClientMock } from '@kbn/actions-plugin/server/mocks'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; const rulesClient = rulesClientMock.create(); @@ -30,6 +31,7 @@ beforeEach(() => { }); describe('createRuleRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); const createdAt = new Date(); const updatedAt = new Date(); const action: RuleAction = { @@ -151,6 +153,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -264,6 +267,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -381,6 +385,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -499,6 +504,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [config, handler] = router.post.mock.calls[0]; @@ -606,7 +612,7 @@ describe('createRuleRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createRuleRoute({ router, licenseState, encryptedSavedObjects }); + createRuleRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -628,7 +634,7 @@ describe('createRuleRoute', () => { throw new Error('OMG'); }); - createRuleRoute({ router, licenseState, encryptedSavedObjects }); + createRuleRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -646,7 +652,7 @@ describe('createRuleRoute', () => { const router = httpServiceMock.createRouter(); const encryptedSavedObjects = encryptedSavedObjectsMock.createSetup({ canEncrypt: true }); - createRuleRoute({ router, licenseState, encryptedSavedObjects }); + createRuleRoute({ router, licenseState, encryptedSavedObjects, docLinks }); const [, handler] = router.post.mock.calls[0]; @@ -677,6 +683,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [_, handler] = router.post.mock.calls[0]; @@ -759,6 +766,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [_, handler] = router.post.mock.calls[0]; @@ -815,6 +823,7 @@ describe('createRuleRoute', () => { licenseState, encryptedSavedObjects, usageCounter: mockUsageCounter, + docLinks, }); const [_, handler] = router.post.mock.calls[0]; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts index 45341fb48e9b..26775ad0f98d 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/create/create_rule_route.ts @@ -62,7 +62,8 @@ export const createRuleRoute = ({ router, licenseState, usageCounter }: RouteOpt handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); const rulesSettingsClient = (await context.alerting).getRulesSettingsClient(true); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts index 0452de7f7bec..e1e09403b309 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/delete/delete_rule_route.ts @@ -48,7 +48,8 @@ export const deleteRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: DeleteRuleRequestParamsV1 = req.params; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts index cae82e80be86..e364bc130121 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/disable/disable_rule_route.ts @@ -51,7 +51,7 @@ export const disableRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const { id }: DisableRuleRequestParamsV1 = req.params; const body: DisableRuleRequestBodyV1 = req.body || {}; const { untrack = false } = body; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts index 4843ed932374..e5f0983bf844 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/enable/enable_rule_route.ts @@ -48,7 +48,7 @@ export const enableRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const params: EnableRuleRequestParamsV1 = req.params; try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts index 46ff2e8e96e1..53b330a8a204 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.test.ts @@ -7,6 +7,8 @@ import { httpServiceMock } from '@kbn/core/server/mocks'; import { licenseStateMock } from '../../../../lib/license_state.mock'; import { findInternalRulesRoute } from './find_internal_rules_route'; +import { mockHandlerArguments } from '../../../_mock_handler_arguments'; +import { rulesClientMock } from '../../../../rules_client.mock'; jest.mock('../../../../lib/license_api_access', () => ({ verifyApiAccess: jest.fn(), @@ -20,6 +22,8 @@ beforeEach(() => { jest.resetAllMocks(); }); +const rulesClient = rulesClientMock.create(); + describe('findInternalRulesRoute', () => { it('registers the route without public access', async () => { const licenseState = licenseStateMock.create(); @@ -33,4 +37,78 @@ describe('findInternalRulesRoute', () => { expect.any(Function) ); }); + + it('finds rules with proper parameters', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findInternalRulesRoute(router, licenseState); + + const [config, handler] = router.post.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/internal/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + body: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + rule_type_ids: ['foo'], + consumers: ['bar'], + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(rulesClient.find).toHaveBeenCalledTimes(1); + expect(rulesClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "excludeFromPublicApi": false, + "includeSnoozeData": true, + "options": Object { + "consumers": Array [ + "bar", + ], + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + "ruleTypeIds": Array [ + "foo", + ], + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts index 8ff8ce59192c..0117d86468f2 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_internal_rules_route.ts @@ -8,10 +8,10 @@ import { IRouter } from '@kbn/core/server'; import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import type { - FindRulesRequestQueryV1, + FindRulesInternalRequestBodyV1, FindRulesResponseV1, } from '../../../../../common/routes/rule/apis/find'; -import { findRulesRequestQuerySchemaV1 } from '../../../../../common/routes/rule/apis/find'; +import { findRulesInternalRequestBodySchemaV1 } from '../../../../../common/routes/rule/apis/find'; import { RuleParamsV1 } from '../../../../../common/routes/rule/response'; import { ILicenseState } from '../../../../lib'; import { @@ -20,7 +20,7 @@ import { } from '../../../../types'; import { verifyAccessAndContext } from '../../../lib'; import { trackLegacyTerminology } from '../../../lib/track_legacy_terminology'; -import { transformFindRulesBodyV1, transformFindRulesResponseV1 } from './transforms'; +import { transformFindRulesInternalBodyV1, transformFindRulesResponseV1 } from './transforms'; export const findInternalRulesRoute = ( router: IRouter, @@ -32,14 +32,14 @@ export const findInternalRulesRoute = ( path: INTERNAL_ALERTING_API_FIND_RULES_PATH, options: { access: 'internal' }, validate: { - body: findRulesRequestQuerySchemaV1, + body: findRulesInternalRequestBodySchemaV1, }, }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); - const body: FindRulesRequestQueryV1 = req.body; + const body: FindRulesInternalRequestBodyV1 = req.body; trackLegacyTerminology( [req.body.search, req.body.search_fields, req.body.sort_field].filter( @@ -48,7 +48,7 @@ export const findInternalRulesRoute = ( usageCounter ); - const options = transformFindRulesBodyV1({ + const options = transformFindRulesInternalBodyV1({ ...body, has_reference: body.has_reference || undefined, search_fields: searchFieldsAsArray(body.search_fields), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts index 0e1f07a5ce54..27769cf23738 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.test.ts @@ -42,6 +42,7 @@ describe('findRulesRoute', () => { expect.any(Function) ); }); + it('finds rules with proper parameters', async () => { const licenseState = licenseStateMock.create(); const router = httpServiceMock.createRouter(); @@ -446,4 +447,138 @@ describe('findRulesRoute', () => { incrementBy: 1, }); }); + + it('should not support rule_type_ids', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + rule_type_ids: ['foo'], + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(rulesClient.find).toHaveBeenCalledTimes(1); + expect(rulesClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "excludeFromPublicApi": true, + "includeSnoozeData": true, + "options": Object { + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); + + it('should not support consumers', async () => { + const licenseState = licenseStateMock.create(); + const router = httpServiceMock.createRouter(); + + findRulesRoute(router, licenseState); + + const [config, handler] = router.get.mock.calls[0]; + + expect(config.path).toMatchInlineSnapshot(`"/api/alerting/rules/_find"`); + + const findResult = { + page: 1, + perPage: 1, + total: 0, + data: [], + }; + rulesClient.find.mockResolvedValueOnce(findResult); + + const [context, req, res] = mockHandlerArguments( + { rulesClient }, + { + query: { + per_page: 1, + page: 1, + default_search_operator: 'OR', + consumers: ['foo'], + }, + }, + ['ok'] + ); + + expect(await handler(context, req, res)).toMatchInlineSnapshot(` + Object { + "body": Object { + "data": Array [], + "page": 1, + "per_page": 1, + "total": 0, + }, + } + `); + + expect(rulesClient.find).toHaveBeenCalledTimes(1); + expect(rulesClient.find.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + Object { + "excludeFromPublicApi": true, + "includeSnoozeData": true, + "options": Object { + "defaultSearchOperator": "OR", + "page": 1, + "perPage": 1, + }, + }, + ] + `); + + expect(res.ok).toHaveBeenCalledWith({ + body: { + page: 1, + per_page: 1, + total: 0, + data: [], + }, + }); + }); }); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts index 90afde8f2081..37ea13c7983e 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/find_rules_route.ts @@ -52,7 +52,7 @@ export const findRulesRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const query: FindRulesRequestQueryV1 = req.query; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts index 044a845f3f8f..222215ffb9a3 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/index.ts @@ -8,5 +8,8 @@ export { transformFindRulesBody } from './transform_find_rules_body/latest'; export { transformFindRulesResponse } from './transform_find_rules_response/latest'; -export { transformFindRulesBody as transformFindRulesBodyV1 } from './transform_find_rules_body/v1'; +export { + transformFindRulesBody as transformFindRulesBodyV1, + transformFindRulesInternalBody as transformFindRulesInternalBodyV1, +} from './transform_find_rules_body/v1'; export { transformFindRulesResponse as transformFindRulesResponseV1 } from './transform_find_rules_response/v1'; diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts index a2f9d3c99b00..3248c8f45360 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/find/transforms/transform_find_rules_body/v1.ts @@ -5,7 +5,10 @@ * 2.0. */ -import type { FindRulesRequestQueryV1 } from '../../../../../../../common/routes/rule/apis/find'; +import type { + FindRulesInternalRequestBodyV1, + FindRulesRequestQueryV1, +} from '../../../../../../../common/routes/rule/apis/find'; import { FindRulesOptions } from '../../../../../../application/rule/methods/find'; export const transformFindRulesBody = (params: FindRulesRequestQueryV1): FindRulesOptions => { @@ -29,7 +32,42 @@ export const transformFindRulesBody = (params: FindRulesRequestQueryV1): FindRul ...(filter ? { filter } : {}), ...(defaultSearchOperator ? { defaultSearchOperator } : {}), ...(perPage ? { perPage } : {}), - ...(filterConsumers ? { filterConsumers } : {}), + ...(sortField ? { sortField } : {}), + ...(sortOrder ? { sortOrder } : {}), + ...(hasReference ? { hasReference } : {}), + ...(searchFields + ? { searchFields: Array.isArray(searchFields) ? searchFields : [searchFields] } + : {}), + ...(filterConsumers ? { consumers: filterConsumers } : {}), + }; +}; + +export const transformFindRulesInternalBody = ( + params: FindRulesInternalRequestBodyV1 +): FindRulesOptions => { + const { + per_page: perPage, + page, + search, + default_search_operator: defaultSearchOperator, + search_fields: searchFields, + sort_field: sortField, + sort_order: sortOrder, + has_reference: hasReference, + fields, + filter, + rule_type_ids: ruleTypeIds, + consumers, + } = params; + return { + ...(page ? { page } : {}), + ...(search ? { search } : {}), + ...(fields ? { fields } : {}), + ...(filter ? { filter } : {}), + ...(defaultSearchOperator ? { defaultSearchOperator } : {}), + ...(perPage ? { perPage } : {}), + ...(ruleTypeIds ? { ruleTypeIds } : {}), + ...(consumers ? { consumers } : {}), ...(sortField ? { sortField } : {}), ...(sortOrder ? { sortOrder } : {}), ...(hasReference ? { hasReference } : {}), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts index 0c19d0c9c4f7..46ccc00e3362 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/get/get_rule_route.ts @@ -64,7 +64,8 @@ const buildGetRuleRoute = ({ }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: GetRuleRequestParamsV1 = req.params; // TODO (http-versioning): Remove this cast, this enables us to move forward diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts index e130679a7843..b91c0841df91 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/get_schedule_frequency/get_schedule_frequency_route.ts @@ -24,7 +24,8 @@ export const getScheduleFrequencyRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async (context, req, res) => { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const scheduleFrequencyResult = await rulesClient.getScheduleFrequency(); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts index e6293a589743..d32df997eb2c 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.test.ts @@ -97,7 +97,7 @@ describe('ruleTypesRoute', () => { has_fields_for_a_a_d: false, }, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments({ rulesClient }, {}, ['ok']); @@ -183,7 +183,7 @@ describe('ruleTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, @@ -240,7 +240,7 @@ describe('ruleTypesRoute', () => { } as RegistryAlertTypeWithAuth, ]; - rulesClient.listRuleTypes.mockResolvedValueOnce(new Set(listTypes)); + rulesClient.listRuleTypes.mockResolvedValueOnce(listTypes); const [context, req, res] = mockHandlerArguments( { rulesClient }, diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts index da9c62ab5f3f..a49820704d74 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/rule_types.ts @@ -42,7 +42,7 @@ export const ruleTypesRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const ruleTypes = await rulesClient.listRuleTypes(); const responseBody: TypesRulesResponseBodyV1 = transformRuleTypesResponseV1(ruleTypes); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts index 54a5874331c8..e331fd913333 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/list_types/transforms/transform_rule_types_response/v1.ts @@ -10,9 +10,9 @@ import { RegistryAlertTypeWithAuth } from '../../../../../../authorization'; import type { TypesRulesResponseBodyV1 } from '../../../../../../../common/routes/rule/apis/list_types'; export const transformRuleTypesResponse = ( - ruleTypes: Set + ruleTypes: RegistryAlertTypeWithAuth[] ): TypesRulesResponseBodyV1 => { - return Array.from(ruleTypes).map((ruleType: RegistryAlertTypeWithAuth) => { + return ruleTypes.map((ruleType: RegistryAlertTypeWithAuth) => { return { ...(ruleType.actionGroups ? { action_groups: ruleType.actionGroups } : {}), ...(ruleType.actionVariables ? { action_variables: ruleType.actionVariables } : {}), diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts index 5ce924b445ca..f9b7fa8bfbf0 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/mute_alert/mute_alert.ts @@ -48,7 +48,8 @@ export const muteAlertRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: MuteAlertRequestParamsV1 = req.params; try { await rulesClient.muteInstance(transformRequestParamsToApplicationV1(params)); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts b/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts index e9aa0e42a046..46f108cb3a94 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/mute_all/mute_all_rule.ts @@ -51,7 +51,8 @@ export const muteAllRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: MuteAllRuleRequestParamsV1 = req.params; trackDeprecatedRouteUsage('muteAll', usageCounter); try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts index f67485279edc..ad0e846d452e 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/resolve/resolve_rule_route.ts @@ -34,7 +34,8 @@ export const resolveRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: ResolveRuleRequestParamsV1 = req.params; const { id } = params; // TODO (http-versioning): Remove this cast, this enables us to move forward diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts index 1de46fd78490..3e0e22070d67 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/snooze/snooze_rule_route.ts @@ -33,7 +33,8 @@ export const snoozeRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: SnoozeRuleRequestParamsV1 = req.params; const body = transformSnoozeBodyV1(req.body); try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts b/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts index c66bf0d61009..05e4433f5e53 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/tags/get_rule_tags.ts @@ -29,7 +29,8 @@ export const getRuleTagsRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const query: RuleTagsRequestQueryV1 = req.query; const options = transformRuleTagsQueryRequestV1(query); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts index 63560e354dc1..34108b937cc4 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_alert/unmute_alert_route.ts @@ -49,7 +49,7 @@ export const unmuteAlertRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const params: UnmuteAlertRequestParamsV1 = req.params; try { await rulesClient.unmuteInstance(transformRequestParamsToApplicationV1(params)); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts index 8409128da624..bf9d1660d0de 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/unmute_all/unmute_all_rule.ts @@ -48,7 +48,8 @@ export const unmuteAllRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: UnmuteAllRuleRequestParamsV1 = req.params; try { await rulesClient.unmuteAll(params); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts index 69e4c91eeaf3..e5f476cbb203 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/unsnooze/unsnooze_rule_route.ts @@ -33,7 +33,8 @@ export const unsnoozeRuleRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const params: UnsnoozeRuleRequestParamsV1 = req.params; const body = transformUnsnoozeBodyV1(req.body); try { diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts index 5c925b05bace..8fee470cb3bd 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update/update_rule_route.ts @@ -64,7 +64,8 @@ export const updateRuleRoute = ( handleDisabledApiKeysError( router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const actionsClient = (await context.actions).getActionsClient(); const rulesSettingsClient = (await context.alerting).getRulesSettingsClient(true); diff --git a/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts b/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts index 7ba858941235..4f16d873dfaa 100644 --- a/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts +++ b/x-pack/plugins/alerting/server/routes/rule/apis/update_api_key/update_rule_api_key_route.ts @@ -51,7 +51,7 @@ export const updateRuleApiKeyRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const { id }: UpdateApiKeyParamsV1 = req.params; try { diff --git a/x-pack/plugins/alerting/server/routes/run_soon.ts b/x-pack/plugins/alerting/server/routes/run_soon.ts index 589724ab57b0..1b7fa271c958 100644 --- a/x-pack/plugins/alerting/server/routes/run_soon.ts +++ b/x-pack/plugins/alerting/server/routes/run_soon.ts @@ -31,7 +31,8 @@ export const runSoonRoute = ( }, router.handleLegacyErrors( verifyAccessAndContext(licenseState, async function (context, req, res) { - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); const message = await rulesClient.runSoon(req.params); return message ? res.ok({ body: message }) : res.noContent(); }) diff --git a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts index f39615efa7e8..25dc8add03ab 100644 --- a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts +++ b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_alerts.ts @@ -11,15 +11,9 @@ import { firstValueFrom, Observable } from 'rxjs'; import { getRequestAbortedSignal } from '@kbn/data-plugin/server'; import { termsAggSuggestions } from '@kbn/unified-search-plugin/server/autocomplete/terms_agg'; import type { ConfigSchema } from '@kbn/unified-search-plugin/server/config'; -import { UsageCounter } from '@kbn/usage-collection-plugin/server'; import { getKbnServerError, reportServerError } from '@kbn/kibana-utils-plugin/server'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { - AlertConsumers, - ALERT_RULE_CONSUMER, - ALERT_RULE_TYPE_ID, - SPACE_IDS, -} from '@kbn/rule-data-utils'; +import { ALERT_RULE_CONSUMER, ALERT_RULE_TYPE_ID, SPACE_IDS } from '@kbn/rule-data-utils'; import { verifyAccessAndContext } from '../lib'; import { RuleAuditAction, ruleAuditEvent } from '../../rules_client/common/audit_events'; @@ -27,6 +21,7 @@ import { AlertingAuthorizationEntity, AlertingAuthorizationFilterOpts, AlertingAuthorizationFilterType, + AuthorizedRuleTypes, } from '../../authorization'; import { AlertingRequestHandlerContext } from '../../types'; import { GetAlertIndicesAlias, ILicenseState } from '../../lib'; @@ -45,20 +40,11 @@ export const AlertsSuggestionsSchema = { }), }; -const VALID_FEATURE_IDS = new Set([ - AlertConsumers.APM, - AlertConsumers.INFRASTRUCTURE, - AlertConsumers.LOGS, - AlertConsumers.SLO, - AlertConsumers.UPTIME, -]); - export function registerAlertsValueSuggestionsRoute( router: IRouter, licenseState: ILicenseState, config$: Observable, - getAlertIndicesAlias?: GetAlertIndicesAlias, - usageCounter?: UsageCounter + getAlertIndicesAlias?: GetAlertIndicesAlias ) { router.post( { @@ -73,19 +59,21 @@ export function registerAlertsValueSuggestionsRoute( const abortSignal = getRequestAbortedSignal(request.events.aborted$); const { savedObjects, elasticsearch } = await context.core; - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); let authorizationTuple; - let authorizedRuleType = []; + let authorizedRuleType: AuthorizedRuleTypes = new Map(); + try { const authorization = rulesClient.getAuthorization(); - authorizationTuple = await authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - alertingAuthorizationFilterOpts - ); - authorizedRuleType = await authorization.getAuthorizedRuleTypes( - AlertingAuthorizationEntity.Alert, - VALID_FEATURE_IDS - ); + authorizationTuple = await authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: alertingAuthorizationFilterOpts, + }); + + authorizedRuleType = await authorization.getAllAuthorizedRuleTypesFindOperation({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + }); } catch (error) { rulesClient.getAuditLogger()?.log( ruleAuditEvent({ @@ -93,8 +81,10 @@ export function registerAlertsValueSuggestionsRoute( error, }) ); + throw error; } + const spaceId = rulesClient.getSpaceId(); const { filter: authorizationFilter } = authorizationTuple; const filters = [ @@ -103,9 +93,10 @@ export function registerAlertsValueSuggestionsRoute( ] as estypes.QueryDslQueryContainer[]; const index = getAlertIndicesAlias!( - authorizedRuleType.map((art) => art.id), + Array.from(authorizedRuleType.keys()).map((id) => id), spaceId ).join(','); + try { const body = await termsAggSuggestions( config, diff --git a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts index 6ada2378b309..420d6473988f 100644 --- a/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts +++ b/x-pack/plugins/alerting/server/routes/suggestions/values_suggestion_rules.ts @@ -59,15 +59,14 @@ export function registerRulesValueSuggestionsRoute( const abortSignal = getRequestAbortedSignal(request.events.aborted$); const { savedObjects, elasticsearch } = await context.core; - const rulesClient = (await context.alerting).getRulesClient(); + const alertingContext = await context.alerting; + const rulesClient = await alertingContext.getRulesClient(); let authorizationTuple; try { - authorizationTuple = await rulesClient - .getAuthorization() - .getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ); + authorizationTuple = await rulesClient.getAuthorization().getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }); } catch (error) { rulesClient.getAuditLogger()?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rule_type_registry.test.ts b/x-pack/plugins/alerting/server/rule_type_registry.test.ts index e678228660e5..d9d7c1240922 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.test.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.test.ts @@ -856,7 +856,7 @@ describe('Create Lifecycle', () => { test('should return empty when nothing is registered', () => { const registry = new RuleTypeRegistry(ruleTypeRegistryParams); const result = registry.list(); - expect(result).toMatchInlineSnapshot(`Set {}`); + expect(result).toMatchInlineSnapshot(`Map {}`); }); test('should return registered types', () => { @@ -888,8 +888,8 @@ describe('Create Lifecycle', () => { }); const result = registry.list(); expect(result).toMatchInlineSnapshot(` - Set { - Object { + Map { + "test" => Object { "actionGroups": Array [ Object { "id": "testActionGroup", diff --git a/x-pack/plugins/alerting/server/rule_type_registry.ts b/x-pack/plugins/alerting/server/rule_type_registry.ts index 7562942f0262..40d00acbef59 100644 --- a/x-pack/plugins/alerting/server/rule_type_registry.ts +++ b/x-pack/plugins/alerting/server/rule_type_registry.ts @@ -382,59 +382,40 @@ export class RuleTypeRegistry { >; } - public list(): Set { - const mapRuleTypes: Array<[string, UntypedNormalizedRuleType]> = Array.from(this.ruleTypes); - const tempRegistryRuleType = mapRuleTypes.map( - ([ - id, - { - name, - actionGroups, - recoveryActionGroup, - defaultActionGroupId, - actionVariables, - category, - producer, - minimumLicenseRequired, - isExportable, - ruleTaskTimeout, - defaultScheduleInterval, - doesSetRecoveryContext, - alerts, - fieldsForAAD, - validLegacyConsumers, - }, - ]) => { - // KEEP the type here to be safe if not the map is ignoring it for some reason - const ruleType: RegistryRuleType = { - id, - name, - actionGroups, - recoveryActionGroup, - defaultActionGroupId, - actionVariables, - category, - producer, - minimumLicenseRequired, - isExportable, - ruleTaskTimeout, - defaultScheduleInterval, - doesSetRecoveryContext, - enabledInLicense: !!this.licenseState.getLicenseCheckForRuleType( - id, - name, - minimumLicenseRequired - ).isValid, - fieldsForAAD, - hasFieldsForAAD: Boolean(fieldsForAAD), - hasAlertsMappings: !!alerts, - validLegacyConsumers, - ...(alerts ? { alerts } : {}), - }; - return ruleType; - } - ); - return new Set(tempRegistryRuleType); + public list(): Map { + const ruleTypesMap = new Map(); + + this.ruleTypes.forEach((_ruleType) => { + const ruleType: RegistryRuleType = { + id: _ruleType.id, + name: _ruleType.name, + actionGroups: _ruleType.actionGroups, + recoveryActionGroup: _ruleType.recoveryActionGroup, + defaultActionGroupId: _ruleType.defaultActionGroupId, + actionVariables: _ruleType.actionVariables, + category: _ruleType.category, + producer: _ruleType.producer, + minimumLicenseRequired: _ruleType.minimumLicenseRequired, + isExportable: _ruleType.isExportable, + ruleTaskTimeout: _ruleType.ruleTaskTimeout, + defaultScheduleInterval: _ruleType.defaultScheduleInterval, + doesSetRecoveryContext: _ruleType.doesSetRecoveryContext, + enabledInLicense: !!this.licenseState.getLicenseCheckForRuleType( + _ruleType.id, + _ruleType.name, + _ruleType.minimumLicenseRequired + ).isValid, + fieldsForAAD: _ruleType.fieldsForAAD, + hasFieldsForAAD: Boolean(_ruleType.fieldsForAAD), + hasAlertsMappings: !!_ruleType.alerts, + ...(_ruleType.alerts ? { alerts: _ruleType.alerts } : {}), + validLegacyConsumers: _ruleType.validLegacyConsumers, + }; + + ruleTypesMap.set(ruleType.id, ruleType); + }); + + return ruleTypesMap; } public getAllTypes(): string[] { diff --git a/x-pack/plugins/alerting/server/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client.mock.ts index 0616591cbe56..c7577656306d 100644 --- a/x-pack/plugins/alerting/server/rules_client.mock.ts +++ b/x-pack/plugins/alerting/server/rules_client.mock.ts @@ -5,12 +5,15 @@ * 2.0. */ +import { alertingAuthorizationMock } from './authorization/alerting_authorization.mock'; import { RulesClientApi } from './types'; type Schema = RulesClientApi; export type RulesClientMock = jest.Mocked; const createRulesClientMock = () => { + const alertingAuthorization = alertingAuthorizationMock.create(); + const mocked: RulesClientMock = { aggregate: jest.fn().mockReturnValue({ ruleExecutionStatus: {}, ruleLastRunOutcome: {} }), getTags: jest.fn(), @@ -31,10 +34,7 @@ const createRulesClientMock = () => { listRuleTypes: jest.fn(), getAlertSummary: jest.fn(), getAuditLogger: jest.fn(), - getAuthorization: jest.fn().mockImplementation(() => ({ - getFindAuthorizationFilter: jest.fn().mockReturnValue({ filter: null }), - getAuthorizedRuleTypes: jest.fn().mockResolvedValue([]), - })), + getAuthorization: jest.fn().mockReturnValue(alertingAuthorization), getExecutionLogForRule: jest.fn(), getRuleExecutionKPI: jest.fn(), getGlobalExecutionKpiWithAuth: jest.fn(), diff --git a/x-pack/plugins/alerting/server/rules_client/common/filters.test.ts b/x-pack/plugins/alerting/server/rules_client/common/filters.test.ts new file mode 100644 index 000000000000..fc14cb19bb80 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/common/filters.test.ts @@ -0,0 +1,463 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { nodeBuilder } from '@kbn/es-query'; +import { + buildConsumersFilter, + buildFilter, + buildRuleTypeIdsFilter, + combineFilterWithAuthorizationFilter, + combineFilters, +} from './filters'; + +describe('filters', () => { + describe('combineFilterWithAuthorizationFilter', () => { + it('returns undefined if neither a filter or authorizationFilter are passed', () => { + expect(combineFilterWithAuthorizationFilter()).toBeUndefined(); + }); + + it('returns a single KueryNode when only a filter is passed in', () => { + const node = nodeBuilder.is('a', 'hello'); + expect(combineFilterWithAuthorizationFilter(node)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it('returns a single KueryNode when only an authorizationFilter is passed in', () => { + const node = nodeBuilder.is('a', 'hello'); + expect(combineFilterWithAuthorizationFilter(undefined, node)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it("returns a single KueryNode and'ing together the passed in parameters", () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilterWithAuthorizationFilter(node, node2)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + } + `); + }); + + it("returns a single KueryNode and'ing together the passed in parameters in opposite order", () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilterWithAuthorizationFilter(node2, node)).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + } + `); + }); + }); + + describe('buildFilter', () => { + it('returns undefined if filters is undefined', () => { + expect(buildFilter({ filters: undefined, field: 'abc', operator: 'or' })).toBeUndefined(); + }); + + it('returns undefined if filters is is an empty array', () => { + expect(buildFilter({ filters: [], field: 'abc', operator: 'or' })).toBeUndefined(); + }); + + it('returns a KueryNode using or operator', () => { + expect(buildFilter({ filters: ['value1'], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value1", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + + it("returns multiple nodes or'd together", () => { + expect(buildFilter({ filters: ['value1', 'value2'], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "value2", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + + it('does not escape special kql characters in the filter values', () => { + const specialCharacters = 'awesome:()\\<>"*'; + + expect(buildFilter({ filters: [specialCharacters], field: 'abc', operator: 'or' })) + .toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.abc", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "awesome:()\\\\<>\\"*", + }, + ], + "function": "is", + "type": "function", + } + `); + }); + }); + + describe('combineFilters', () => { + it('returns undefined if the nodes are undefined or null', () => { + expect(combineFilters([null, undefined])).toBeUndefined(); + }); + + it('combines the filters correctly', () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilters([node, null, undefined, node2])).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + } + `); + }); + + it('combines the filters correctly with an operator', () => { + const node = nodeBuilder.is('a', 'hello'); + const node2 = nodeBuilder.is('b', 'hi'); + + expect(combineFilters([node, null, undefined, node2], 'or')).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "a", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hello", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "b", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "hi", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + }); + + describe('buildRuleTypeIdsFilter', () => { + it('returns undefined if ruleTypeIds is undefined', () => { + expect(buildRuleTypeIdsFilter()).toBeUndefined(); + }); + + it('returns undefined if ruleTypeIds is is an empty array', () => { + expect(buildRuleTypeIdsFilter([])).toBeUndefined(); + }); + + it('builds the filter correctly', () => { + expect(buildRuleTypeIdsFilter(['foo', 'bar'])).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "bar", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + }); + + describe('buildConsumersFilter', () => { + it('returns undefined if ruleTypeIds is undefined', () => { + expect(buildConsumersFilter()).toBeUndefined(); + }); + + it('returns undefined if ruleTypeIds is is an empty array', () => { + expect(buildConsumersFilter([])).toBeUndefined(); + }); + + it('builds the filter correctly', () => { + expect(buildConsumersFilter(['foo', 'bar'])).toMatchInlineSnapshot(` + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "bar", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "or", + "type": "function", + } + `); + }); + }); +}); diff --git a/x-pack/plugins/alerting/server/rules_client/common/filters.ts b/x-pack/plugins/alerting/server/rules_client/common/filters.ts new file mode 100644 index 000000000000..b0c3ccc5e1ec --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/common/filters.ts @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KueryNode, nodeBuilder } from '@kbn/es-query'; +import { RULE_SAVED_OBJECT_TYPE } from '../..'; + +export const NodeBuilderOperators = { + and: 'and', + or: 'or', +} as const; + +type NodeBuilderOperatorsType = keyof typeof NodeBuilderOperators; + +interface FilterField { + filters?: string | string[]; + field: string; + operator: NodeBuilderOperatorsType; + type?: string; +} + +export const buildFilter = ({ + filters, + field, + operator, + type = RULE_SAVED_OBJECT_TYPE, +}: FilterField): KueryNode | undefined => { + if (filters === undefined) { + return; + } + + const filtersAsArray = Array.isArray(filters) ? filters : [filters]; + + if (filtersAsArray.length === 0) { + return; + } + + return nodeBuilder[operator]( + filtersAsArray.map((filter) => nodeBuilder.is(`${type}.attributes.${field}`, filter)) + ); +}; + +export const buildRuleTypeIdsFilter = (ruleTypeIds?: string[]) => { + if (!ruleTypeIds || !ruleTypeIds?.length) { + return; + } + + return buildFilter({ filters: ruleTypeIds, field: 'alertTypeId', operator: 'or' }); +}; + +export const buildConsumersFilter = (consumers?: string[]) => { + if (!consumers || !consumers?.length) { + return; + } + + return buildFilter({ filters: consumers, field: 'consumer', operator: 'or' }); +}; + +/** + * Combines Kuery nodes and accepts an array with a mixture of undefined and KueryNodes. This will filter out the undefined + * filters and return a KueryNode with the filters combined using the specified operator which defaults to and if not defined. + */ +export function combineFilters( + nodes: Array, + operator: NodeBuilderOperatorsType = NodeBuilderOperators.and +): KueryNode | undefined { + const filters = nodes.filter(Boolean) as KueryNode[]; + + if (filters.length <= 0) { + return; + } + + return nodeBuilder[operator](filters); +} + +export const combineFilterWithAuthorizationFilter = ( + filter?: KueryNode, + authorizationFilter?: KueryNode +) => { + if (!filter && !authorizationFilter) { + return; + } + + const kueries = [ + ...(filter !== undefined ? [filter] : []), + ...(authorizationFilter !== undefined ? [authorizationFilter] : []), + ]; + return nodeBuilder.and(kueries); +}; diff --git a/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts b/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts index b9cc41a0fd7c..591602effc47 100644 --- a/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts +++ b/x-pack/plugins/alerting/server/rules_client/lib/get_authorization_filter.ts @@ -6,11 +6,11 @@ */ import { withSpan } from '@kbn/apm-utils'; -import { AlertingAuthorizationEntity } from '../../authorization'; import { ruleAuditEvent, RuleAuditAction } from '../common/audit_events'; import { RulesClientContext } from '../types'; import { alertingAuthorizationFilterOpts } from '../common/constants'; import { BulkAction } from '../types'; +import { AlertingAuthorizationEntity } from '../../authorization/types'; export const getAuthorizationFilter = async ( context: RulesClientContext, @@ -20,10 +20,10 @@ export const getAuthorizationFilter = async ( const authorizationTuple = await withSpan( { name: 'authorization.getFindAuthorizationFilter', type: 'rules' }, () => - context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Rule, - alertingAuthorizationFilterOpts - ) + context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Rule, + filterOpts: alertingAuthorizationFilterOpts, + }) ); return authorizationTuple.filter; } catch (error) { diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts index a7d60fc8f8ca..4d71af6573b5 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_action_error_log.ts @@ -108,16 +108,16 @@ export async function getActionErrorLogWithAuth( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'kibana.alert.rule.rule_type_id', consumer: 'kibana.alert.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts index fc2c1298f69a..4441cc69a5f7 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_kpi.ts @@ -105,16 +105,16 @@ export async function getGlobalExecutionKpiWithAuth( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'kibana.alert.rule.rule_type_id', consumer: 'kibana.alert.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts index 18d65c28fc9b..95d41a02a685 100644 --- a/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts +++ b/x-pack/plugins/alerting/server/rules_client/methods/get_execution_log.ts @@ -118,16 +118,16 @@ export async function getGlobalExecutionLogWithAuth( let authorizationTuple; try { - authorizationTuple = await context.authorization.getFindAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + authorizationTuple = await context.authorization.getFindAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'kibana.alert.rule.rule_type_id', consumer: 'kibana.alert.rule.consumer', }, - } - ); + }, + }); } catch (error) { context.auditLogger?.log( ruleAuditEvent({ diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.mock.ts new file mode 100644 index 000000000000..f8e2beba7ee6 --- /dev/null +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.mock.ts @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ActionsAuthorization } from '@kbn/actions-plugin/server'; +import { loggingSystemMock } from '@kbn/core-logging-server-mocks'; +import { uiSettingsServiceMock } from '@kbn/core-ui-settings-server-mocks'; +import { AlertingAuthorization } from '../authorization'; +import { ConnectorAdapterRegistry } from '../connector_adapters/connector_adapter_registry'; +import type { ConstructorOptions } from './rules_client'; +import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; +import { + savedObjectsClientMock, + savedObjectsRepositoryMock, +} from '@kbn/core-saved-objects-api-server-mocks'; +import { auditLoggerMock } from '@kbn/core-security-server-mocks'; +import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; +import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { alertingAuthorizationMock } from '../authorization/alerting_authorization.mock'; +import { backfillClientMock } from '../backfill_client/backfill_client.mock'; +import { ruleTypeRegistryMock } from '../rule_type_registry.mock'; + +const create = () => { + const kibanaVersion = 'v8.17.0'; + const taskManager = taskManagerMock.createStart(); + const ruleTypeRegistry = ruleTypeRegistryMock.create(); + const unsecuredSavedObjectsClient = savedObjectsClientMock.create(); + const encryptedSavedObjects = encryptedSavedObjectsMock.createClient(); + const authorization = alertingAuthorizationMock.create(); + const actionsAuthorization = actionsAuthorizationMock.create(); + const auditLogger = auditLoggerMock.create(); + const internalSavedObjectsRepository = savedObjectsRepositoryMock.create(); + const backfillClient = backfillClientMock.create(); + + const rulesClientParams: jest.Mocked = { + taskManager, + ruleTypeRegistry, + unsecuredSavedObjectsClient, + authorization: authorization as unknown as AlertingAuthorization, + actionsAuthorization: actionsAuthorization as unknown as ActionsAuthorization, + spaceId: 'default', + namespace: 'default', + getUserName: jest.fn(), + createAPIKey: jest.fn(), + logger: loggingSystemMock.create().get(), + internalSavedObjectsRepository, + encryptedSavedObjectsClient: encryptedSavedObjects, + getActionsClient: jest.fn(), + getEventLogClient: jest.fn(), + kibanaVersion, + auditLogger, + maxScheduledPerMinute: 10000, + minimumScheduleInterval: { value: '1m', enforce: false }, + isAuthenticationTypeAPIKey: jest.fn(), + getAuthenticationAPIKey: jest.fn(), + getAlertIndicesAlias: jest.fn(), + alertsService: null, + backfillClient, + isSystemAction: jest.fn(), + connectorAdapterRegistry: new ConnectorAdapterRegistry(), + uiSettings: uiSettingsServiceMock.createStartContract(), + }; + + return rulesClientParams; +}; + +export const rulesClientContextMock = { create }; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts index b096ec1c75f7..7205decb32bb 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/list_rule_types.test.ts @@ -17,10 +17,7 @@ import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; import { actionsAuthorizationMock } from '@kbn/actions-plugin/server/mocks'; -import { - AlertingAuthorization, - RegistryAlertTypeWithAuth, -} from '../../authorization/alerting_authorization'; +import { AlertingAuthorization } from '../../authorization/alerting_authorization'; import { ActionsAuthorization } from '@kbn/actions-plugin/server'; import { getBeforeSetup } from './lib'; import { RecoveredActionGroup } from '../../../common'; @@ -88,6 +85,7 @@ describe('listRuleTypes', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }; + const myAppAlertType: RegistryRuleType = { actionGroups: [], actionVariables: undefined, @@ -104,7 +102,11 @@ describe('listRuleTypes', () => { hasFieldsForAAD: false, validLegacyConsumers: [], }; - const setOfAlertTypes = new Set([myAppAlertType, alertingAlertType]); + + const setOfAlertTypes = new Map([ + [myAppAlertType.id, myAppAlertType], + [alertingAlertType.id, alertingAlertType], + ]); const authorizedConsumers = { alerts: { read: true, all: true }, @@ -118,62 +120,162 @@ describe('listRuleTypes', () => { test('should return a list of AlertTypes that exist in the registry', async () => { ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); - authorization.filterByRuleTypeAuthorization.mockResolvedValue( - new Set([ - { ...myAppAlertType, authorizedConsumers }, - { ...alertingAlertType, authorizedConsumers }, + ruleTypeRegistry.has.mockReturnValue(true); + + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [myAppAlertType.id, { authorizedConsumers }], + [alertingAlertType.id, { authorizedConsumers }], ]) ); - expect(await rulesClient.listRuleTypes()).toEqual( - new Set([ - { ...myAppAlertType, authorizedConsumers }, - { ...alertingAlertType, authorizedConsumers }, + + expect(await rulesClient.listRuleTypes()).toMatchInlineSnapshot(` + Array [ + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "myApp": Object { + "all": true, + "read": true, + }, + "myOtherApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "myAppAlertType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "myAppAlertType", + "producer": "myApp", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "myApp": Object { + "all": true, + "read": true, + }, + "myOtherApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "alertingAlertType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "alertingAlertType", + "producer": "alerts", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + ] + `); + }); + + test('should filter out rule types that are not registered in the registry', async () => { + ruleTypeRegistry.list.mockReturnValue(setOfAlertTypes); + ruleTypeRegistry.has.mockImplementation((id: string) => id === myAppAlertType.id); + + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [myAppAlertType.id, { authorizedConsumers }], + [alertingAlertType.id, { authorizedConsumers }], ]) ); + + expect(await rulesClient.listRuleTypes()).toMatchInlineSnapshot(` + Array [ + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "alerts": Object { + "all": true, + "read": true, + }, + "myApp": Object { + "all": true, + "read": true, + }, + "myOtherApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "myAppAlertType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "myAppAlertType", + "producer": "myApp", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + ] + `); }); describe('authorization', () => { - const listedTypes = new Set([ - { - actionGroups: [], - actionVariables: undefined, - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - id: 'myType', - name: 'myType', - category: 'test', - producer: 'myApp', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - { - id: 'myOtherType', - name: 'Test', - actionGroups: [{ id: 'default', name: 'Default' }], - defaultActionGroupId: 'default', - minimumLicenseRequired: 'basic', - isExportable: true, - recoveryActionGroup: RecoveredActionGroup, - category: 'test', - producer: 'alerts', - enabledInLicense: true, - hasAlertsMappings: false, - hasFieldsForAAD: false, - validLegacyConsumers: [], - }, - ]); - beforeEach(() => { - ruleTypeRegistry.list.mockReturnValue(listedTypes); - }); - - test('should return a list of AlertTypes that exist in the registry only if the user is authorised to get them', async () => { - const authorizedTypes = new Set([ + const listedTypes = new Map([ + [ + 'myType', { + actionGroups: [], + actionVariables: undefined, + defaultActionGroupId: 'default', + minimumLicenseRequired: 'basic', + isExportable: true, + recoveryActionGroup: RecoveredActionGroup, id: 'myType', + name: 'myType', + category: 'test', + producer: 'myApp', + enabledInLicense: true, + hasAlertsMappings: false, + hasFieldsForAAD: false, + validLegacyConsumers: [], + }, + ], + [ + 'myOtherType', + { + id: 'myOtherType', name: 'Test', actionGroups: [{ id: 'default', name: 'Default' }], defaultActionGroupId: 'default', @@ -182,18 +284,62 @@ describe('listRuleTypes', () => { recoveryActionGroup: RecoveredActionGroup, category: 'test', producer: 'alerts', - authorizedConsumers: { - myApp: { read: true, all: true }, - }, enabledInLicense: true, hasAlertsMappings: false, hasFieldsForAAD: false, validLegacyConsumers: [], }, - ]); - authorization.filterByRuleTypeAuthorization.mockResolvedValue(authorizedTypes); + ], + ]); + + beforeEach(() => { + ruleTypeRegistry.list.mockReturnValue(listedTypes); + ruleTypeRegistry.has.mockReturnValue(true); + }); - expect(await rulesClient.listRuleTypes()).toEqual(authorizedTypes); + test('should return a list of AlertTypes that exist in the registry only if the user is authorized to get them', async () => { + authorization.getAuthorizedRuleTypes.mockResolvedValue( + new Map([ + [ + 'myType', + { + authorizedConsumers: { + myApp: { read: true, all: true }, + }, + }, + ], + ]) + ); + + expect(await rulesClient.listRuleTypes()).toMatchInlineSnapshot(` + Array [ + Object { + "actionGroups": Array [], + "actionVariables": undefined, + "authorizedConsumers": Object { + "myApp": Object { + "all": true, + "read": true, + }, + }, + "category": "test", + "defaultActionGroupId": "default", + "enabledInLicense": true, + "hasAlertsMappings": false, + "hasFieldsForAAD": false, + "id": "myType", + "isExportable": true, + "minimumLicenseRequired": "basic", + "name": "myType", + "producer": "myApp", + "recoveryActionGroup": Object { + "id": "recovered", + "name": "Recovered", + }, + "validLegacyConsumers": Array [], + }, + ] + `); }); }); }); diff --git a/x-pack/plugins/alerting/server/rules_client/types.ts b/x-pack/plugins/alerting/server/rules_client/types.ts index 9a701e1c95c8..afcb4e1037a6 100644 --- a/x-pack/plugins/alerting/server/rules_client/types.ts +++ b/x-pack/plugins/alerting/server/rules_client/types.ts @@ -23,7 +23,6 @@ import { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; import { IEventLogClient, IEventLogger } from '@kbn/event-log-plugin/server'; import { AuditLogger } from '@kbn/security-plugin/server'; import { DistributiveOmit } from '@elastic/eui'; -import { RegistryRuleType } from '../rule_type_registry'; import { RuleTypeRegistry, IntervalSchedule, @@ -108,9 +107,6 @@ export type NormalizedAlertActionWithGeneratedValues = | NormalizedAlertDefaultActionWithGeneratedValues | NormalizedAlertSystemActionWithGeneratedValues; -export interface RegistryAlertTypeWithAuth extends RegistryRuleType { - authorizedConsumers: string[]; -} export type CreateAPIKeyResult = | { apiKeysEnabled: false } | { apiKeysEnabled: true; result: SecurityPluginGrantAPIKeyResult }; diff --git a/x-pack/plugins/alerting/server/rules_client_factory.test.ts b/x-pack/plugins/alerting/server/rules_client_factory.test.ts index 4cd7ffbcf0c6..9af5962915d7 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.test.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.test.ts @@ -98,11 +98,11 @@ test('creates a rules client with proper constructor arguments when security is const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); - alertingAuthorizationClientFactory.create.mockReturnValue( + alertingAuthorizationClientFactory.create.mockResolvedValue( alertingAuthorization as unknown as AlertingAuthorization ); - factory.create(request, savedObjectsService); + await factory.create(request, savedObjectsService); expect(savedObjectsService.getScopedClient).toHaveBeenCalledWith(request, { excludedExtensions: [SECURITY_EXTENSION_ID], @@ -154,11 +154,11 @@ test('creates a rules client with proper constructor arguments', async () => { const request = mockRouter.createKibanaRequest(); savedObjectsService.getScopedClient.mockReturnValue(savedObjectsClient); - alertingAuthorizationClientFactory.create.mockReturnValue( + alertingAuthorizationClientFactory.create.mockResolvedValue( alertingAuthorization as unknown as AlertingAuthorization ); - factory.create(request, savedObjectsService); + await factory.create(request, savedObjectsService); expect(savedObjectsService.getScopedClient).toHaveBeenCalledWith(request, { excludedExtensions: [SECURITY_EXTENSION_ID], @@ -203,7 +203,7 @@ test('creates a rules client with proper constructor arguments', async () => { test('getUserName() returns null when security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const userNameResult = await constructorCall.getUserName(); @@ -216,7 +216,7 @@ test('getUserName() returns a name when security is enabled', async () => { ...rulesClientFactoryParams, securityService, }); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityService.authc.getCurrentUser.mockReturnValueOnce({ @@ -229,7 +229,7 @@ test('getUserName() returns a name when security is enabled', async () => { test('getActionsClient() returns ActionsClient', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const actionsClient = await constructorCall.getActionsClient(); @@ -239,7 +239,7 @@ test('getActionsClient() returns ActionsClient', async () => { test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; const createAPIKeyResult = await constructorCall.createAPIKey(); @@ -249,7 +249,7 @@ test('createAPIKey() returns { apiKeysEnabled: false } when security is disabled test('createAPIKey() returns { apiKeysEnabled: false } when security is enabled but ES security is disabled', async () => { const factory = new RulesClientFactory(); factory.initialize(rulesClientFactoryParams); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce(null); @@ -265,7 +265,7 @@ test('createAPIKey() returns an API key when security is enabled', async () => { securityPluginSetup, securityPluginStart, }); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockResolvedValueOnce({ @@ -296,7 +296,7 @@ test('createAPIKey() throws when security plugin createAPIKey throws an error', securityPluginSetup, securityPluginStart, }); - factory.create(mockRouter.createKibanaRequest(), savedObjectsService); + await factory.create(mockRouter.createKibanaRequest(), savedObjectsService); const constructorCall = jest.requireMock('./rules_client').RulesClient.mock.calls[0][0]; securityPluginStart.authc.apiKeys.grantAsInternalUser.mockRejectedValueOnce( diff --git a/x-pack/plugins/alerting/server/rules_client_factory.ts b/x-pack/plugins/alerting/server/rules_client_factory.ts index f28170b277ac..f56b0840317b 100644 --- a/x-pack/plugins/alerting/server/rules_client_factory.ts +++ b/x-pack/plugins/alerting/server/rules_client_factory.ts @@ -115,7 +115,10 @@ export class RulesClientFactory { this.securityService = options.securityService; } - public create(request: KibanaRequest, savedObjects: SavedObjectsServiceStart): RulesClient { + public async create( + request: KibanaRequest, + savedObjects: SavedObjectsServiceStart + ): Promise { const { securityPluginSetup, securityService, securityPluginStart, actions, eventLog } = this; const spaceId = this.getSpaceId(request); @@ -123,6 +126,8 @@ export class RulesClientFactory { throw new Error('AlertingAuthorizationClientFactory is not defined'); } + const authorization = await this.authorization.create(request); + return new RulesClient({ spaceId, kibanaVersion: this.kibanaVersion, @@ -139,7 +144,7 @@ export class RulesClientFactory { AD_HOC_RUN_SAVED_OBJECT_TYPE, ], }), - authorization: this.authorization.create(request), + authorization, actionsAuthorization: actions.getActionsAuthorizationWithRequest(request), namespace: this.spaceIdToNamespace(spaceId), internalSavedObjectsRepository: this.internalSavedObjectsRepository, @@ -169,6 +174,7 @@ export class RulesClientFactory { if (!createAPIKeyResult) { return { apiKeysEnabled: false }; } + return { apiKeysEnabled: true, result: createAPIKeyResult, diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts index 00f1a87aefd7..c0eb08e6d582 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.test.ts @@ -2617,7 +2617,6 @@ describe('Action Scheduler', () => { }); expect(buildActionParams).not.toHaveBeenCalledWith(); - expect(actionsClient.ephemeralEnqueuedExecution).not.toHaveBeenCalled(); expect(actionsClient.bulkEnqueueExecution).not.toHaveBeenCalled(); expect(alertingEventLogger.logAction).not.toHaveBeenCalled(); expect(executorParams.logger.warn).toHaveBeenCalledWith( @@ -2662,7 +2661,6 @@ describe('Action Scheduler', () => { expect(res).toEqual({ throttledSummaryActions: {} }); expect(buildActionParams).not.toHaveBeenCalled(); expect(alertsClient.getSummarizedAlerts).not.toHaveBeenCalled(); - expect(actionsClient.ephemeralEnqueuedExecution).not.toHaveBeenCalled(); expect(actionsClient.bulkEnqueueExecution).not.toHaveBeenCalled(); expect(alertingEventLogger.logAction).not.toHaveBeenCalled(); }); diff --git a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts index fa16cfcabb09..9a174dd236cf 100644 --- a/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts +++ b/x-pack/plugins/alerting/server/task_runner/action_scheduler/action_scheduler.ts @@ -5,13 +5,8 @@ * 2.0. */ +import { createTaskRunError, TaskErrorSource } from '@kbn/task-manager-plugin/server'; import { - createTaskRunError, - isEphemeralTaskRejectedDueToCapacityError, - TaskErrorSource, -} from '@kbn/task-manager-plugin/server'; -import { - ExecuteOptions as EnqueueExecutionOptions, ExecutionResponseItem, ExecutionResponseType, } from '@kbn/actions-plugin/server/create_execute_function'; @@ -51,8 +46,6 @@ export class ActionScheduler< IActionScheduler > = []; - private ephemeralActionsToSchedule: number; - constructor( private readonly context: ActionSchedulerOptions< Params, @@ -65,7 +58,6 @@ export class ActionScheduler< AlertData > ) { - this.ephemeralActionsToSchedule = context.taskRunnerContext.maxEphemeralActionsPerRule; for (const [_, scheduler] of Object.entries(schedulers)) { this.schedulers.push(new scheduler(context)); } @@ -101,37 +93,28 @@ export class ActionScheduler< return { throttledSummaryActions }; } - const bulkScheduleRequest: EnqueueExecutionOptions[] = []; - - for (const result of allActionsToScheduleResult) { - await this.runActionAsEphemeralOrAddToBulkScheduleRequest({ - enqueueOptions: result.actionToEnqueue, - bulkScheduleRequest, - }); - } - let bulkScheduleResponse: ExecutionResponseItem[] = []; - if (!!bulkScheduleRequest.length) { - for (const c of chunk(bulkScheduleRequest, BULK_SCHEDULE_CHUNK_SIZE)) { - let enqueueResponse; - try { - enqueueResponse = await withAlertingSpan('alerting:bulk-enqueue-actions', () => - this.context.actionsClient!.bulkEnqueueExecution(c) - ); - } catch (e) { - if (e.statusCode === 404) { - throw createTaskRunError(e, TaskErrorSource.USER); - } - throw createTaskRunError(e, TaskErrorSource.FRAMEWORK); - } - if (enqueueResponse.errors) { - bulkScheduleResponse = bulkScheduleResponse.concat( - enqueueResponse.items.filter( - (i) => i.response === ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR - ) - ); + for (const c of chunk(allActionsToScheduleResult, BULK_SCHEDULE_CHUNK_SIZE)) { + let enqueueResponse; + try { + enqueueResponse = await withAlertingSpan('alerting:bulk-enqueue-actions', () => + this.context.actionsClient!.bulkEnqueueExecution( + c.map((actions) => actions.actionToEnqueue) + ) + ); + } catch (e) { + if (e.statusCode === 404) { + throw createTaskRunError(e, TaskErrorSource.USER); } + throw createTaskRunError(e, TaskErrorSource.FRAMEWORK); + } + if (enqueueResponse.errors) { + bulkScheduleResponse = bulkScheduleResponse.concat( + enqueueResponse.items.filter( + (i) => i.response === ExecutionResponseType.QUEUED_ACTIONS_LIMIT_ERROR + ) + ); } } @@ -175,28 +158,4 @@ export class ActionScheduler< return { throttledSummaryActions }; } - - private async runActionAsEphemeralOrAddToBulkScheduleRequest({ - enqueueOptions, - bulkScheduleRequest, - }: { - enqueueOptions: EnqueueExecutionOptions; - bulkScheduleRequest: EnqueueExecutionOptions[]; - }) { - if ( - this.context.taskRunnerContext.supportsEphemeralTasks && - this.ephemeralActionsToSchedule > 0 - ) { - this.ephemeralActionsToSchedule--; - try { - await this.context.actionsClient!.ephemeralEnqueuedExecution(enqueueOptions); - } catch (err) { - if (isEphemeralTaskRejectedDueToCapacityError(err)) { - bulkScheduleRequest.push(enqueueOptions); - } - } - } else { - bulkScheduleRequest.push(enqueueOptions); - } - } } diff --git a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts index 0e0d7983e59f..ae6467d0dcbf 100644 --- a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.test.ts @@ -131,6 +131,7 @@ const alertsService = new AlertsService({ elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), elasticsearchAndSOAvailability$, + isServerless: false, }); const backfillClient = backfillClientMock.create(); const dataPlugin = dataPluginMock.createStartContract(); @@ -167,15 +168,14 @@ const taskRunnerFactoryInitializerParams: TaskRunnerFactoryInitializerParamsType kibanaBaseUrl: 'https://localhost:5601', logger, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; const mockedTaskInstance: ConcreteTaskInstance = { @@ -459,7 +459,7 @@ describe('Ad Hoc Task Runner', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts index d12615103067..c9932820ff80 100644 --- a/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/ad_hoc_task_runner.ts @@ -185,6 +185,7 @@ export class AdHocTaskRunner implements CancellableTask { ruleLogPrefix: ruleLabel, ruleRunMetricsStore, spaceId: adHocRunData.spaceId, + isServerless: this.context.isServerless, }; const alertsClient = await initializeAlertsClient< RuleTypeParams, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts b/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts index 4690ccc653a3..c5e833dee105 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_loader.test.ts @@ -113,7 +113,7 @@ describe('rule_loader', () => { }); }); - test('throws when rule is not enabled', async () => { + test('throws when rule is not enabled', () => { let outcome = 'success'; try { validateRuleAndCreateFakeRequest({ @@ -128,7 +128,7 @@ describe('rule_loader', () => { expect(outcome).toBe('failure'); }); - test('throws when rule type is not enabled', async () => { + test('throws when rule type is not enabled', () => { ruleTypeRegistry.ensureRuleTypeEnabled.mockImplementation(() => { throw new Error('rule-type-not-enabled: 2112'); }); @@ -148,7 +148,7 @@ describe('rule_loader', () => { expect(outcome).toBe('failure'); }); - test('test throws when rule params fail validation', async () => { + test('test throws when rule params fail validation', () => { mockGetAlertFromRaw.mockReturnValueOnce({ name: ruleName, alertTypeId: ruleTypeId, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts index 1d218e50f927..68c01770fd6f 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.test.ts @@ -189,6 +189,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -231,6 +232,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -295,6 +297,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -337,6 +340,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: true, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -404,6 +408,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -465,6 +470,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -507,6 +513,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -567,6 +574,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -609,6 +617,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -669,6 +678,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -706,6 +716,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -748,6 +759,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -819,6 +831,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -861,6 +874,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -932,6 +946,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -975,6 +990,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -1036,6 +1052,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -1079,6 +1096,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, @@ -1140,6 +1158,7 @@ describe('RuleTypeRunner', () => { ruleLogPrefix: `${RULE_TYPE_ID}:${RULE_ID}: '${RULE_NAME}'`, ruleRunMetricsStore, spaceId: 'default', + isServerless: false, }, alertsClient, executionId: 'abc', @@ -1183,6 +1202,7 @@ describe('RuleTypeRunner', () => { startedAtOverridden: false, previousStartedAt: null, spaceId: 'default', + isServerless: false, rule: { id: RULE_ID, name: mockedRule.name, diff --git a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts index c10871613ea2..5a9a88d85674 100644 --- a/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/rule_type_runner.ts @@ -285,6 +285,7 @@ export class RuleTypeRunner< ...(context.queryDelaySec ? { queryDelay: context.queryDelaySec } : {}), ...(startedAtOverridden ? { forceNow: startedAt } : {}), }), + isServerless: context.isServerless, }) ) ); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts index a79dfe8f59c7..bbe927833afd 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.test.ts @@ -53,7 +53,6 @@ import { generateActionOpts, mockDate, mockedRuleTypeSavedObject, - mockRunNowResponse, ruleType, RULE_NAME, generateRunnerResult, @@ -187,37 +186,16 @@ describe('Task Runner', () => { logger, maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; - const ephemeralTestParams: Array< - [ - nameExtension: string, - customTaskRunnerFactoryInitializerParams: TaskRunnerFactoryInitializerParamsType, - enqueueFunction: unknown, - isBulk: boolean - ] - > = [ - ['', taskRunnerFactoryInitializerParams, actionsClient.bulkEnqueueExecution, true], - [ - ' (with ephemeral support)', - { - ...taskRunnerFactoryInitializerParams, - supportsEphemeralTasks: true, - }, - actionsClient.ephemeralEnqueuedExecution, - false, - ], - ]; - beforeEach(() => { jest.resetAllMocks(); jest.restoreAllMocks(); // clear spy mock implementations @@ -362,103 +340,95 @@ describe('Task Runner', () => { ).toHaveBeenCalled(); }); - test.each(ephemeralTestParams)( - 'actionsPlugin.execute is called per alert alert that is scheduled %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - internalSavedObjectsRepository, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + test('actionsPlugin.execute is called per alert alert that is scheduled', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + internalSavedObjectsRepository, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true }) - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true }) + ); - expect(logger.debug).toHaveBeenCalledTimes(6); - expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { - tags: ['1', 'test'], - }); - expect(logger.debug).nthCalledWith( - 2, - `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 3, - 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":1,"recovered":0,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":1,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', - { tags: ['1', 'test'] } - ); + expect(logger.debug).toHaveBeenCalledTimes(6); + expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { + tags: ['1', 'test'], + }); + expect(logger.debug).nthCalledWith( + 2, + `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 3, + 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":1,"recovered":0,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":1,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', + { tags: ['1', 'test'] } + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - generatedActions: 1, - newAlerts: 1, - triggeredActions: 1, - status: 'active', - logAlert: 2, - logAction: 1, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.newInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 2, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts()); + testAlertingEventLogCalls({ + activeAlerts: 1, + generatedActions: 1, + newAlerts: 1, + triggeredActions: 1, + status: 'active', + logAlert: 2, + logAction: 1, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.newInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 2, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts()); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); test('actionsPlugin.execute is skipped if muteAll is true', async () => { taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); @@ -493,7 +463,6 @@ describe('Task Runner', () => { }); encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); expect(logger.debug).toHaveBeenCalledTimes(7); expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { @@ -632,7 +601,6 @@ describe('Task Runner', () => { const expectedExecutions = shouldBeSnoozed ? 0 : 1; expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(expectedExecutions); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); const expectedMessage = `no scheduling of actions for rule test:1: '${RULE_NAME}': rule is snoozed.`; if (expectedExecutions) { @@ -688,7 +656,6 @@ describe('Task Runner', () => { encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -760,7 +727,6 @@ describe('Task Runner', () => { encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -823,7 +789,6 @@ describe('Task Runner', () => { encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -854,202 +819,10 @@ describe('Task Runner', () => { expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); }); - test.each(ephemeralTestParams)( - 'skips firing actions for active alert if alert is muted %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - ( - customTaskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType - ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - executorServices.alertFactory.create('2').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - internalSavedObjectsRepository, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - mutedInstanceIds: ['2'], - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - - expect(logger.debug).toHaveBeenCalledTimes(7); - expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { - tags: ['1', 'test'], - }); - expect(logger.debug).nthCalledWith( - 2, - `rule test:1: '${RULE_NAME}' has 2 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"},{\"instanceId\":\"2\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 3, - `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":2,"new":2,"recovered":0,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 6, - 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":2,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":2,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', - { tags: ['1', 'test'] } - ); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); - - test.each(ephemeralTestParams)( - 'skips firing actions for active alert if alert is throttled %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - ( - customTaskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType - ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - executorServices.alertFactory.create('2').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '2': { - meta: { - lastScheduledActions: { date: moment().toISOString(), group: 'default' }, - }, - state: { - bar: false, - start: DATE_1969, - duration: MOCK_DURATION, - }, - }, - }, - }, - }, - context: taskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - notifyWhen: 'onThrottleInterval', - throttle: '1d', - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - // expect(enqueueFunction).toHaveBeenCalledTimes(1); - - // expect(logger.debug).toHaveBeenCalledTimes(5); - expect(logger.debug).nthCalledWith( - 3, - `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is throttled`, - { tags: ['1', 'test'] } - ); - } - ); - - test.each(ephemeralTestParams)( - 'skips firing actions for active alert when alert is muted even if notifyWhen === onActionGroupChange %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - executorServices.alertFactory.create('2').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - mutedInstanceIds: ['2'], - notifyWhen: 'onActionGroupChange', - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(logger.debug).toHaveBeenCalledTimes(7); - expect(logger.debug).nthCalledWith( - 3, - `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, - { tags: ['1', 'test'] } - ); - } - ); - - test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert state does not change', async () => { - taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + test('skips firing actions for active alert if alert is muted', async () => { + ( + taskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType + ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); ruleType.executor.mockImplementation( async ({ @@ -1063,13 +836,188 @@ describe('Task Runner', () => { RuleAlertData >) => { executorServices.alertFactory.create('1').scheduleActions('default'); + executorServices.alertFactory.create('2').scheduleActions('default'); return { state: {} }; } ); const taskRunner = new TaskRunner({ ruleType, - internalSavedObjectsRepository, - taskInstance: { + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + internalSavedObjectsRepository, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + mutedInstanceIds: ['2'], + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + + expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { + tags: ['1', 'test'], + }); + expect(logger.debug).nthCalledWith( + 2, + `rule test:1: '${RULE_NAME}' has 2 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"},{\"instanceId\":\"2\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 3, + `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":2,"new":2,"recovered":0,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 6, + 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":1,"numberOfGeneratedActions":1,"numberOfActiveAlerts":2,"numberOfRecoveredAlerts":0,"numberOfNewAlerts":2,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', + { tags: ['1', 'test'] } + ); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); + + test('skips firing actions for active alert if alert is throttled', async () => { + ( + taskRunnerFactoryInitializerParams as TaskRunnerFactoryInitializerParamsType + ).actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + executorServices.alertFactory.create('2').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '2': { + meta: { + lastScheduledActions: { date: moment().toISOString(), group: 'default' }, + }, + state: { + bar: false, + start: DATE_1969, + duration: MOCK_DURATION, + }, + }, + }, + }, + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + notifyWhen: 'onThrottleInterval', + throttle: '1d', + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + // expect(enqueueFunction).toHaveBeenCalledTimes(1); + + // expect(logger.debug).toHaveBeenCalledTimes(5); + expect(logger.debug).nthCalledWith( + 3, + `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is throttled`, + { tags: ['1', 'test'] } + ); + }); + + test('skips firing actions for active alert when alert is muted even if notifyWhen === onActionGroupChange', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + executorServices.alertFactory.create('2').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + mutedInstanceIds: ['2'], + notifyWhen: 'onActionGroupChange', + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).nthCalledWith( + 3, + `skipping scheduling of actions for '2' in rule test:1: '${RULE_NAME}': rule is muted`, + { tags: ['1', 'test'] } + ); + }); + + test('actionsPlugin.execute is not called when notifyWhen=onActionGroupChange and alert state does not change', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { ...mockedTaskInstance, state: { ...mockedTaskInstance.state, @@ -1098,7 +1046,6 @@ describe('Task Runner', () => { }); encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); await taskRunner.run(); - expect(actionsClient.ephemeralEnqueuedExecution).toHaveBeenCalledTimes(0); testAlertingEventLogCalls({ activeAlerts: 1, @@ -1117,690 +1064,620 @@ describe('Task Runner', () => { expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); }); - test.each(ephemeralTestParams)( - 'actionsPlugin.execute is called when notifyWhen=onActionGroupChange and alert state has changed %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { - meta: { - lastScheduledActions: { group: 'newGroup', date: new Date().toISOString() }, - }, - state: { bar: false }, + test('actionsPlugin.execute is called when notifyWhen=onActionGroupChange and alert state has changed', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { + meta: { + lastScheduledActions: { group: 'newGroup', date: new Date().toISOString() }, }, + state: { bar: false }, }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - notifyWhen: 'onActionGroupChange', - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + notifyWhen: 'onActionGroupChange', + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); + await taskRunner.run(); - testAlertingEventLogCalls({ - activeAlerts: 1, - triggeredActions: 1, - generatedActions: 1, - status: 'active', - logAlert: 1, - logAction: 1, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { bar: false }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); + testAlertingEventLogCalls({ + activeAlerts: 1, + triggeredActions: 1, + generatedActions: 1, + status: 'active', + logAlert: 1, + logAction: 1, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { bar: false }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - test.each(ephemeralTestParams)( - 'includes the apiKey in the request used to initialize the actionsClient %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); + test('includes the apiKey in the request used to initialize the actionsClient', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); - expect( - customTaskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest - ).toHaveBeenCalledWith( - expect.objectContaining({ - headers: { - // base64 encoded "123:abc" - authorization: 'ApiKey MTIzOmFiYw==', - }, - }) - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); + expect( + taskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest + ).toHaveBeenCalledWith( + expect.objectContaining({ + headers: { + // base64 encoded "123:abc" + authorization: 'ApiKey MTIzOmFiYw==', + }, + }) + ); - const [request] = - customTaskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest.mock - .calls[0]; + const [request] = + taskRunnerFactoryInitializerParams.actionsPlugin.getActionsClientWithRequest.mock.calls[0]; - expect(customTaskRunnerFactoryInitializerParams.basePathService.set).toHaveBeenCalledWith( - request, - '/' - ); + expect(taskRunnerFactoryInitializerParams.basePathService.set).toHaveBeenCalledWith( + request, + '/' + ); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true }) - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true }) + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - newAlerts: 1, - triggeredActions: 1, - generatedActions: 1, - status: 'active', - logAlert: 2, - logAction: 1, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.newInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 2, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { start: DATE_1970, duration: '0' }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); + testAlertingEventLogCalls({ + activeAlerts: 1, + newAlerts: 1, + triggeredActions: 1, + generatedActions: 1, + status: 'active', + logAlert: 2, + logAction: 1, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.newInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 2, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { start: DATE_1970, duration: '0' }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - test.each(ephemeralTestParams)( - 'fire recovered actions for execution for the alertInstances which is in the recovered state %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); + test('fire recovered actions for execution for the alertInstances which is in the recovered state', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { - meta: {}, - state: { - bar: false, - start: DATE_1969, - duration: '80000000000', - }, + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { + meta: {}, + state: { + bar: false, + start: DATE_1969, + duration: '80000000000', }, - '2': { - meta: {}, - state: { - bar: false, - start: '1969-12-31T06:00:00.000Z', - duration: '70000000000', - }, + }, + '2': { + meta: {}, + state: { + bar: false, + start: '1969-12-31T06:00:00.000Z', + duration: '70000000000', }, }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const runnerResult = await taskRunner.run(); - expect(runnerResult.state.alertInstances).toEqual( - generateAlertInstance({ - id: 1, - duration: MOCK_DURATION, - start: DATE_1969, - flappingHistory: [false], - }) - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const runnerResult = await taskRunner.run(); + expect(runnerResult.state.alertInstances).toEqual( + generateAlertInstance({ + id: 1, + duration: MOCK_DURATION, + start: DATE_1969, + flappingHistory: [false], + }) + ); - expect(logger.debug).toHaveBeenCalledTimes(7); - expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { - tags: ['1', 'test'], - }); - expect(logger.debug).nthCalledWith( - 2, - `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 3, - `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 6, - 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', - { tags: ['1', 'test'] } - ); + expect(logger.debug).toHaveBeenCalledTimes(7); + expect(logger.debug).nthCalledWith(1, 'executing rule test:1 at 1970-01-01T00:00:00.000Z', { + tags: ['1', 'test'], + }); + expect(logger.debug).nthCalledWith( + 2, + `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 3, + `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + 'deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 6, + 'ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}', + { tags: ['1', 'test'] } + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - recoveredAlerts: 1, - triggeredActions: 2, - generatedActions: 2, - status: 'active', - logAlert: 2, - logAction: 2, - }); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 1, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.recoveredInstance, - id: '2', - state: { - bar: false, - start: '1969-12-31T06:00:00.000Z', - duration: '64800000000000', - end: DATE_1970, - }, - }) - ); - expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( - 2, - generateAlertOpts({ - action: EVENT_LOG_ACTIONS.activeInstance, - group: 'default', - state: { bar: false, start: DATE_1969, duration: MOCK_DURATION }, - }) - ); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); - expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( - 2, - generateActionOpts({ id: '2', alertId: '2', alertGroup: 'recovered', uuid: '222-222' }) - ); + testAlertingEventLogCalls({ + activeAlerts: 1, + recoveredAlerts: 1, + triggeredActions: 2, + generatedActions: 2, + status: 'active', + logAlert: 2, + logAction: 2, + }); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 1, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.recoveredInstance, + id: '2', + state: { + bar: false, + start: '1969-12-31T06:00:00.000Z', + duration: '64800000000000', + end: DATE_1970, + }, + }) + ); + expect(alertingEventLogger.logAlert).toHaveBeenNthCalledWith( + 2, + generateAlertOpts({ + action: EVENT_LOG_ACTIONS.activeInstance, + group: 'default', + state: { bar: false, start: DATE_1969, duration: MOCK_DURATION }, + }) + ); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith(1, generateActionOpts({})); + expect(alertingEventLogger.logAction).toHaveBeenNthCalledWith( + 2, + generateActionOpts({ id: '2', alertId: '2', alertGroup: 'recovered', uuid: '222-222' }) + ); - expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); - expect(enqueueFunction).toHaveBeenCalledWith( - isBulk - ? [ - generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), - generateEnqueueFunctionInput({ - isBulk: false, - id: '2', - isResolved: true, - uuid: '222-222', - }), - ] - : generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }) - ); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - jest.resetAllMocks(); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith([ + generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), + generateEnqueueFunctionInput({ + isBulk: false, + id: '2', + isResolved: true, + uuid: '222-222', + }), + ]); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + jest.resetAllMocks(); + }); - test.each(ephemeralTestParams)( - "should skip alertInstances which weren't active on the previous execution %s", - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); + test("should skip alertInstances which weren't active on the previous execution", async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); - ruleType.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); + ruleType.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); - // create an instance, but don't schedule any actions, so it doesn't go active - executorServices.alertFactory.create('3'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { meta: {}, state: { bar: false } }, - '2': { meta: {}, state: { bar: false } }, - }, + // create an instance, but don't schedule any actions, so it doesn't go active + executorServices.alertFactory.create('3'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { meta: {}, state: { bar: false } }, + '2': { meta: {}, state: { bar: false } }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); - - mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const runnerResult = await taskRunner.run(); - expect(runnerResult.state.alertInstances).toEqual( - generateAlertInstance({ - id: 1, - flappingHistory: [false], - }) - ); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - expect(logger.debug).toHaveBeenCalledWith( - `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, - { tags: ['1', 'test'] } - ); + mockGetAlertFromRaw.mockReturnValue(mockedRuleTypeSavedObject as Rule); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const runnerResult = await taskRunner.run(); + expect(runnerResult.state.alertInstances).toEqual( + generateAlertInstance({ + id: 1, + flappingHistory: [false], + }) + ); - expect(logger.debug).nthCalledWith( - 3, - `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 4, - `deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}`, - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 5, - 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', - { tags: ['1', 'test'] } - ); - expect(logger.debug).nthCalledWith( - 6, - `ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}`, - { tags: ['1', 'test'] } - ); + expect(logger.debug).toHaveBeenCalledWith( + `rule test:1: '${RULE_NAME}' has 1 active alerts: [{\"instanceId\":\"1\",\"actionGroup\":\"default\"}]`, + { tags: ['1', 'test'] } + ); - testAlertingEventLogCalls({ - activeAlerts: 1, - recoveredAlerts: 1, - triggeredActions: 2, - generatedActions: 2, - status: 'active', - logAlert: 2, - logAction: 2, - }); + expect(logger.debug).nthCalledWith( + 3, + `rule test:1: '${RULE_NAME}' has 1 recovered alerts: [\"2\"]`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 4, + `deprecated ruleRunStatus for test:1: {"lastExecutionDate":"1970-01-01T00:00:00.000Z","status":"active"}`, + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 5, + 'ruleRunStatus for test:1: {"outcome":"succeeded","outcomeOrder":0,"outcomeMsg":null,"warning":null,"alertsCount":{"active":1,"new":0,"recovered":1,"ignored":0}}', + { tags: ['1', 'test'] } + ); + expect(logger.debug).nthCalledWith( + 6, + `ruleRunMetrics for test:1: {"numSearches":3,"totalSearchDurationMs":23423,"esSearchDurationMs":33,"numberOfTriggeredActions":2,"numberOfGeneratedActions":2,"numberOfActiveAlerts":1,"numberOfRecoveredAlerts":1,"numberOfNewAlerts":0,"numberOfDelayedAlerts":0,"hasReachedAlertLimit":false,"hasReachedQueuedActionsLimit":false,"triggeredActionsStatus":"complete"}`, + { tags: ['1', 'test'] } + ); - expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); - if (isBulk) { - expect((enqueueFunction as jest.Mock).mock.calls[0][0][0].id).toEqual('1'); - expect((enqueueFunction as jest.Mock).mock.calls[0][0][1].id).toEqual('2'); - } else { - expect((enqueueFunction as jest.Mock).mock.calls[0][0].id).toEqual('1'); - expect((enqueueFunction as jest.Mock).mock.calls[1][0].id).toEqual('2'); - } - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + testAlertingEventLogCalls({ + activeAlerts: 1, + recoveredAlerts: 1, + triggeredActions: 2, + generatedActions: 2, + status: 'active', + logAlert: 2, + logAction: 2, + }); - test.each(ephemeralTestParams)( - 'fire actions under a custom recovery group when specified on an alert type for alertInstances which are in the recovered state %s', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect((actionsClient.bulkEnqueueExecution as jest.Mock).mock.calls[0][0][0].id).toEqual('1'); + expect((actionsClient.bulkEnqueueExecution as jest.Mock).mock.calls[0][0][1].id).toEqual('2'); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); + test('fire actions under a custom recovery group when specified on an alert type for alertInstances which are in the recovered state', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); - const recoveryActionGroup = { - id: 'customRecovered', - name: 'Custom Recovered', - }; - const ruleTypeWithCustomRecovery = { - ...ruleType, - recoveryActionGroup, - actionGroups: [{ id: 'default', name: 'Default' }, recoveryActionGroup], - }; + const recoveryActionGroup = { + id: 'customRecovered', + name: 'Custom Recovered', + }; + const ruleTypeWithCustomRecovery = { + ...ruleType, + recoveryActionGroup, + actionGroups: [{ id: 'default', name: 'Default' }, recoveryActionGroup], + }; - ruleTypeWithCustomRecovery.executor.mockImplementation( - async ({ - services: executorServices, - }: RuleExecutorOptions< - RuleTypeParams, - RuleTypeState, - AlertInstanceState, - AlertInstanceContext, - string, - RuleAlertData - >) => { - executorServices.alertFactory.create('1').scheduleActions('default'); - return { state: {} }; - } - ); - const taskRunner = new TaskRunner({ - ruleType: ruleTypeWithCustomRecovery, - internalSavedObjectsRepository, - taskInstance: { - ...mockedTaskInstance, - state: { - ...mockedTaskInstance.state, - alertInstances: { - '1': { meta: {}, state: { bar: false } }, - '2': { meta: {}, state: { bar: false } }, - }, + ruleTypeWithCustomRecovery.executor.mockImplementation( + async ({ + services: executorServices, + }: RuleExecutorOptions< + RuleTypeParams, + RuleTypeState, + AlertInstanceState, + AlertInstanceContext, + string, + RuleAlertData + >) => { + executorServices.alertFactory.create('1').scheduleActions('default'); + return { state: {} }; + } + ); + const taskRunner = new TaskRunner({ + ruleType: ruleTypeWithCustomRecovery, + internalSavedObjectsRepository, + taskInstance: { + ...mockedTaskInstance, + state: { + ...mockedTaskInstance.state, + alertInstances: { + '1': { meta: {}, state: { bar: false } }, + '2': { meta: {}, state: { bar: false } }, }, }, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalled(); + }, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalled(); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - actions: [ - { - group: 'default', - id: '1', - actionTypeId: 'action', - params: { - foo: true, - }, - uuid: '111-111', + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + actions: [ + { + group: 'default', + id: '1', + actionTypeId: 'action', + params: { + foo: true, }, - { - group: recoveryActionGroup.id, - id: '2', - actionTypeId: 'action', - params: { - isResolved: true, - }, - uuid: '222-222', + uuid: '111-111', + }, + { + group: recoveryActionGroup.id, + id: '2', + actionTypeId: 'action', + params: { + isResolved: true, }, - ], - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const runnerResult = await taskRunner.run(); - expect(runnerResult.state.alertInstances).toEqual( - generateAlertInstance({ - id: 1, - flappingHistory: [false], - }) - ); + uuid: '222-222', + }, + ], + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const runnerResult = await taskRunner.run(); + expect(runnerResult.state.alertInstances).toEqual( + generateAlertInstance({ + id: 1, + flappingHistory: [false], + }) + ); - testAlertingEventLogCalls({ - ruleTypeDef: ruleTypeWithCustomRecovery, - activeAlerts: 1, - recoveredAlerts: 1, - triggeredActions: 2, - generatedActions: 2, - status: 'active', - logAlert: 2, - logAction: 2, - }); + testAlertingEventLogCalls({ + ruleTypeDef: ruleTypeWithCustomRecovery, + activeAlerts: 1, + recoveredAlerts: 1, + triggeredActions: 2, + generatedActions: 2, + status: 'active', + logAlert: 2, + logAction: 2, + }); - expect(enqueueFunction).toHaveBeenCalledTimes(isBulk ? 1 : 2); - expect(enqueueFunction).toHaveBeenCalledWith( - isBulk - ? [ - generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), - generateEnqueueFunctionInput({ - isBulk: false, - id: '2', - isResolved: true, - uuid: '222-222', - }), - ] - : generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }) - ); - expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith([ + generateEnqueueFunctionInput({ isBulk: false, id: '1', foo: true }), + generateEnqueueFunctionInput({ + isBulk: false, + id: '2', + isResolved: true, + uuid: '222-222', + }), + ]); + expect(mockUsageCounter.incrementCounter).not.toHaveBeenCalled(); + }); - test.each(ephemeralTestParams)( - 'triggers summary actions (Per rule run)', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation(async () => { - return { state: {} }; - }); + test('triggers summary actions (Per rule run)', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation(async () => { + return { state: {} }; + }); - alertsClient.getProcessedAlerts.mockReturnValue({}); - alertsClient.getSummarizedAlerts.mockResolvedValue({ - new: { - count: 1, - data: [mockAAD], - }, - ongoing: { count: 0, data: [] }, - recovered: { count: 0, data: [] }, - }); - alertsService.createAlertsClient.mockImplementation(() => alertsClient); + alertsClient.getProcessedAlerts.mockReturnValue({}); + alertsClient.getSummarizedAlerts.mockResolvedValue({ + new: { + count: 1, + data: [mockAAD], + }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }); + alertsService.createAlertsClient.mockImplementation(() => alertsClient); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - actions: [ - { - group: 'default', - id: '1', - actionTypeId: 'slack', - frequency: { - notifyWhen: 'onActiveAlert', - summary: true, - throttle: null, - }, - params: { - foo: true, - }, - uuid: '111-111', + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + actions: [ + { + group: 'default', + id: '1', + actionTypeId: 'slack', + frequency: { + notifyWhen: 'onActiveAlert', + summary: true, + throttle: null, }, - ], - }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - await taskRunner.run(); + params: { + foo: true, + }, + uuid: '111-111', + }, + ], + }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true, actionTypeId: 'slack' }) - ); - } - ); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true, actionTypeId: 'slack' }) + ); + }); - test.each(ephemeralTestParams)( - 'triggers summary actions (Custom Frequency)', - async (nameExtension, customTaskRunnerFactoryInitializerParams, enqueueFunction, isBulk) => { - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue( - true - ); - customTaskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue( - true - ); - actionsClient.ephemeralEnqueuedExecution.mockResolvedValue(mockRunNowResponse); - ruleType.executor.mockImplementation(async () => { - return { state: {} }; - }); - alertsClient.getProcessedAlerts.mockReturnValue({}); - alertsClient.getSummarizedAlerts.mockResolvedValue({ - new: { - count: 1, - data: [mockAAD], - }, - ongoing: { count: 0, data: [] }, - recovered: { count: 0, data: [] }, - }); + test('triggers summary actions (Custom Frequency)', async () => { + taskRunnerFactoryInitializerParams.actionsPlugin.isActionTypeEnabled.mockReturnValue(true); + taskRunnerFactoryInitializerParams.actionsPlugin.isActionExecutable.mockReturnValue(true); + ruleType.executor.mockImplementation(async () => { + return { state: {} }; + }); + alertsClient.getProcessedAlerts.mockReturnValue({}); + alertsClient.getSummarizedAlerts.mockResolvedValue({ + new: { + count: 1, + data: [mockAAD], + }, + ongoing: { count: 0, data: [] }, + recovered: { count: 0, data: [] }, + }); - alertsClient.getAlertsToSerialize.mockResolvedValueOnce({ state: {}, meta: {} }); - alertsService.createAlertsClient.mockImplementation(() => alertsClient); + alertsClient.getAlertsToSerialize.mockResolvedValueOnce({ state: {}, meta: {} }); + alertsService.createAlertsClient.mockImplementation(() => alertsClient); - const taskRunner = new TaskRunner({ - ruleType, - internalSavedObjectsRepository, - taskInstance: mockedTaskInstance, - context: customTaskRunnerFactoryInitializerParams, - inMemoryMetrics, - }); - expect(AlertingEventLogger).toHaveBeenCalledTimes(1); + const taskRunner = new TaskRunner({ + ruleType, + internalSavedObjectsRepository, + taskInstance: mockedTaskInstance, + context: taskRunnerFactoryInitializerParams, + inMemoryMetrics, + }); + expect(AlertingEventLogger).toHaveBeenCalledTimes(1); - mockGetAlertFromRaw.mockReturnValue({ - ...(mockedRuleTypeSavedObject as Rule), - actions: [ - { - group: 'default', - id: '1', - actionTypeId: 'slack', - frequency: { - notifyWhen: 'onThrottleInterval', - summary: true, - throttle: '1h', - }, - params: { - foo: true, - }, - uuid: '111-111', + mockGetAlertFromRaw.mockReturnValue({ + ...(mockedRuleTypeSavedObject as Rule), + actions: [ + { + group: 'default', + id: '1', + actionTypeId: 'slack', + frequency: { + notifyWhen: 'onThrottleInterval', + summary: true, + throttle: '1h', }, - ], - }); + params: { + foo: true, + }, + uuid: '111-111', + }, + ], + }); - encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); - const result = await taskRunner.run(); - - expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ - start: new Date('1969-12-31T23:00:00.000Z'), - end: new Date(DATE_1970), - ruleId: '1', - spaceId: 'default', - excludedAlertInstanceIds: [], - }); + encryptedSavedObjectsClient.getDecryptedAsInternalUser.mockResolvedValue(mockedRawRuleSO); + const result = await taskRunner.run(); - expect(enqueueFunction).toHaveBeenCalledTimes(1); - expect(enqueueFunction).toHaveBeenCalledWith( - generateEnqueueFunctionInput({ isBulk, id: '1', foo: true, actionTypeId: 'slack' }) - ); - expect(result.state.summaryActions).toEqual({ - '111-111': { date: new Date(DATE_1970).toISOString() }, - }); - } - ); + expect(alertsClient.getSummarizedAlerts).toHaveBeenCalledWith({ + start: new Date('1969-12-31T23:00:00.000Z'), + end: new Date(DATE_1970), + ruleId: '1', + spaceId: 'default', + excludedAlertInstanceIds: [], + }); + + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledTimes(1); + expect(actionsClient.bulkEnqueueExecution).toHaveBeenCalledWith( + generateEnqueueFunctionInput({ isBulk: true, id: '1', foo: true, actionTypeId: 'slack' }) + ); + expect(result.state.summaryActions).toEqual({ + '111-111': { date: new Date(DATE_1970).toISOString() }, + }); + }); test('persists alertInstances passed in from state, only if they are scheduled for execution', async () => { ruleType.executor.mockImplementation( @@ -2628,7 +2505,6 @@ describe('Task Runner', () => { }, context: { ...taskRunnerFactoryInitializerParams, - supportsEphemeralTasks: true, }, inMemoryMetrics, }); diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner.ts b/x-pack/plugins/alerting/server/task_runner/task_runner.ts index 89432e182202..cd351054f993 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner.ts @@ -317,6 +317,7 @@ export class TaskRunner< ruleLogPrefix: ruleLabel, ruleRunMetricsStore, spaceId, + isServerless: this.context.isServerless, }; const alertsClient = await withAlertingSpan('alerting:initialize-alerts-client', () => initializeAlertsClient< diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts index 958ecaf8d270..3d0cd5ab0505 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_alerts_client.test.ts @@ -216,15 +216,14 @@ describe('Task Runner', () => { logger, maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; describe(`using ${label} for alert indices`, () => { @@ -412,6 +411,7 @@ describe('Task Runner', () => { elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), elasticsearchAndSOAvailability$, + isServerless: false, }); elasticsearchAndSOAvailability$.next(true); @@ -544,6 +544,7 @@ describe('Task Runner', () => { elasticsearchClientPromise: Promise.resolve(clusterClient), dataStreamAdapter: getDataStreamAdapter({ useDataStreamForAlerts }), elasticsearchAndSOAvailability$, + isServerless: false, }); elasticsearchAndSOAvailability$.next(true); @@ -590,7 +591,7 @@ describe('Task Runner', () => { expect(clusterClient.bulk).toHaveBeenCalledWith({ index: '.alerts-test.alerts-default', - refresh: true, + refresh: 'wait_for', require_alias: !useDataStreamForAlerts, body: [ { diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts index c96a3f95c636..54faa13de835 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_cancel.test.ts @@ -149,15 +149,14 @@ describe('Task Runner Cancel', () => { logger, maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry, rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: false, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts index ed4b5a080223..94acd3a0b2db 100644 --- a/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts +++ b/x-pack/plugins/alerting/server/task_runner/task_runner_factory.test.ts @@ -120,15 +120,14 @@ describe('Task Runner Factory', () => { logger: loggingSystemMock.create().get(), maintenanceWindowsService, maxAlerts: 1000, - maxEphemeralActionsPerRule: 10, ruleTypeRegistry: ruleTypeRegistryMock.create(), rulesSettingsService, savedObjects: savedObjectsService, share: {} as SharePluginStart, spaceIdToNamespace: jest.fn().mockReturnValue(undefined), - supportsEphemeralTasks: true, uiSettings: uiSettingsService, usageCounter: mockUsageCounter, + isServerless: false, }; beforeEach(() => { diff --git a/x-pack/plugins/alerting/server/task_runner/types.ts b/x-pack/plugins/alerting/server/task_runner/types.ts index a92ee2a89d65..f3e08aff2c3b 100644 --- a/x-pack/plugins/alerting/server/task_runner/types.ts +++ b/x-pack/plugins/alerting/server/task_runner/types.ts @@ -146,6 +146,7 @@ export interface RuleTypeRunnerContext { ruleLogPrefix: string; ruleRunMetricsStore: RuleRunMetricsStore; spaceId: string; + isServerless: boolean; } export interface RuleRunnerErrorStackTraceLog { @@ -171,13 +172,12 @@ export interface TaskRunnerContext { logger: Logger; maintenanceWindowsService: MaintenanceWindowsService; maxAlerts: number; - maxEphemeralActionsPerRule: number; ruleTypeRegistry: RuleTypeRegistry; rulesSettingsService: RulesSettingsService; savedObjects: SavedObjectsServiceStart; share: SharePluginStart; spaceIdToNamespace: SpaceIdToNamespaceFunction; - supportsEphemeralTasks: boolean; uiSettings: UiSettingsServiceStart; usageCounter?: UsageCounter; + isServerless: boolean; } diff --git a/x-pack/plugins/alerting/server/test_utils/index.ts b/x-pack/plugins/alerting/server/test_utils/index.ts index 036454f2f80c..401225f171f0 100644 --- a/x-pack/plugins/alerting/server/test_utils/index.ts +++ b/x-pack/plugins/alerting/server/test_utils/index.ts @@ -57,7 +57,6 @@ export function generateAlertingConfig(): AlertingConfig { interval: '5m', removalDelay: '1h', }, - maxEphemeralActionsPerAlert: 10, cancelAlertsOnRuleTimeout: true, rules: { maxScheduledPerMinute: 10000, diff --git a/x-pack/plugins/alerting/server/types.ts b/x-pack/plugins/alerting/server/types.ts index b660d348b9e0..4c3d9ee57f51 100644 --- a/x-pack/plugins/alerting/server/types.ts +++ b/x-pack/plugins/alerting/server/types.ts @@ -29,7 +29,7 @@ import { Alert } from '@kbn/alerts-as-data-utils'; import { ActionsApiRequestHandlerContext } from '@kbn/actions-plugin/server'; import { AlertsHealth } from '@kbn/alerting-types'; import { RuleTypeRegistry as OrigruleTypeRegistry } from './rule_type_registry'; -import { PluginSetupContract, PluginStartContract } from './plugin'; +import { AlertingServerSetup, AlertingServerStart } from './plugin'; import { RulesClient } from './rules_client'; import { RulesSettingsClient, @@ -62,7 +62,7 @@ export type { RuleTypeParams }; * @public */ export interface AlertingApiRequestHandlerContext { - getRulesClient: () => RulesClient; + getRulesClient: () => Promise; getRulesSettingsClient: (withoutAuth?: boolean) => RulesSettingsClient; getMaintenanceWindowClient: () => MaintenanceWindowClient; listTypes: RuleTypeRegistry['list']; @@ -133,6 +133,7 @@ export interface RuleExecutorOptions< namespace?: string; flappingSettings: RulesSettingsFlappingProperties; getTimeRange: (timeWindow?: string) => GetTimeRangeResult; + isServerless: boolean; } export interface RuleParamsAndRefs { @@ -361,8 +362,8 @@ export type PartialRuleWithLegacyId = Pic Partial, 'id'>>; export interface AlertingPlugin { - setup: PluginSetupContract; - start: PluginStartContract; + setup: AlertingServerSetup; + start: AlertingServerStart; } export interface AlertsConfigType { diff --git a/x-pack/plugins/alerting/tsconfig.json b/x-pack/plugins/alerting/tsconfig.json index d261a00db74c..6019f8711d68 100644 --- a/x-pack/plugins/alerting/tsconfig.json +++ b/x-pack/plugins/alerting/tsconfig.json @@ -70,9 +70,11 @@ "@kbn/search-types", "@kbn/alerting-state-types", "@kbn/core-security-server", + "@kbn/security-plugin-types-server", "@kbn/core-http-server", "@kbn/zod", "@kbn/core-saved-objects-base-server-internal", + "@kbn/core-security-server-mocks", "@kbn/response-ops-rule-params", "@kbn/core-http-server-utils" ], diff --git a/x-pack/plugins/asset_inventory/README.md b/x-pack/plugins/asset_inventory/README.md new file mode 100755 index 000000000000..e1dd9d4ac890 --- /dev/null +++ b/x-pack/plugins/asset_inventory/README.md @@ -0,0 +1,13 @@ +# Asset Inventory Kibana Plugin + +Centralized asset inventory experience within the Elastic Security solution. A central place for users to view and manage all their assets from different environments. + +--- + +## Development + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/CONTRIBUTING.md) for instructions setting up your development environment. + +## Testing + +For general guidelines, read [Kibana Testing Guide](https://www.elastic.co/guide/en/kibana/current/development-tests.html) for more details diff --git a/x-pack/plugins/asset_inventory/common/index.ts b/x-pack/plugins/asset_inventory/common/index.ts new file mode 100644 index 000000000000..9f5311be877c --- /dev/null +++ b/x-pack/plugins/asset_inventory/common/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +export const PLUGIN_ID = 'assetInventory'; +export const PLUGIN_NAME = 'assetInventory'; diff --git a/x-pack/plugins/asset_inventory/kibana.jsonc b/x-pack/plugins/asset_inventory/kibana.jsonc new file mode 100644 index 000000000000..dbb813be7aa4 --- /dev/null +++ b/x-pack/plugins/asset_inventory/kibana.jsonc @@ -0,0 +1,17 @@ +{ + "type": "plugin", + "id": "@kbn/asset-inventory-plugin", + "owner": ["@elastic/kibana-cloud-security-posture"], + "group": "security", + "visibility": "private", + "description": "Centralized asset inventory experience within the Elastic Security solution. A central place for users to view and manage all their assets from different environments", + "plugin": { + "id": "assetInventory", + "browser": true, + "server": true, + "configPath": ["xpack", "assetInventory"], + "requiredPlugins": [], + "requiredBundles": [], + "optionalPlugins": [] + } +} diff --git a/x-pack/plugins/asset_inventory/package.json b/x-pack/plugins/asset_inventory/package.json new file mode 100644 index 000000000000..7abfb7bf6337 --- /dev/null +++ b/x-pack/plugins/asset_inventory/package.json @@ -0,0 +1,7 @@ +{ + "author": "Elastic", + "name": "@kbn/asset-inventory-plugin", + "version": "1.0.0", + "private": true, + "license": "Elastic License 2.0" +} diff --git a/x-pack/plugins/asset_inventory/public/application.tsx b/x-pack/plugins/asset_inventory/public/application.tsx new file mode 100644 index 000000000000..f442f01d17f7 --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/application.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import ReactDOM from 'react-dom'; +import type { AppMountParameters, CoreStart } from '@kbn/core/public'; +import type { AppPluginStartDependencies } from './types'; +import { AssetInventoryApp } from './components/app'; + +export const renderApp = ( + { notifications, http }: CoreStart, + {}: AppPluginStartDependencies, + { appBasePath, element }: AppMountParameters +) => { + ReactDOM.render( + , + element + ); + + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/x-pack/plugins/asset_inventory/public/components/app.tsx b/x-pack/plugins/asset_inventory/public/components/app.tsx new file mode 100644 index 000000000000..924091034353 --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/components/app.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { FormattedMessage, I18nProvider } from '@kbn/i18n-react'; +import { BrowserRouter as Router } from '@kbn/shared-ux-router'; +import { EuiPageTemplate, EuiTitle } from '@elastic/eui'; +import type { CoreStart } from '@kbn/core/public'; + +interface AssetInventoryAppDeps { + basename: string; + notifications: CoreStart['notifications']; + http: CoreStart['http']; +} + +export const AssetInventoryApp = ({ basename }: AssetInventoryAppDeps) => { + return ( + + + <> + + + +

        + +

        +
        +
        + +
        + +
        +
        + ); +}; diff --git a/x-pack/plugins/asset_inventory/public/index.ts b/x-pack/plugins/asset_inventory/public/index.ts new file mode 100644 index 000000000000..269cab2ad181 --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/index.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { AssetInventoryPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new AssetInventoryPlugin(); +} +export type { AssetInventoryPluginSetup, AssetInventoryPluginStart } from './types'; diff --git a/x-pack/plugins/asset_inventory/public/plugin.ts b/x-pack/plugins/asset_inventory/public/plugin.ts new file mode 100644 index 000000000000..fd2841f5b233 --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/plugin.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import type { + AssetInventoryPluginSetup, + AssetInventoryPluginStart, + AppPluginStartDependencies, +} from './types'; + +export class AssetInventoryPlugin + implements Plugin +{ + public setup(core: CoreSetup): AssetInventoryPluginSetup { + return {}; + } + public start( + coreStart: CoreStart, + depsStart: AppPluginStartDependencies + ): AssetInventoryPluginStart { + return { + getAssetInventoryPage: async (params: AppMountParameters) => { + // Load application bundle + const { renderApp } = await import('./application'); + // Render the application + return renderApp(coreStart, depsStart as AppPluginStartDependencies, params); + }, + }; + } + + public stop() {} +} diff --git a/x-pack/plugins/asset_inventory/public/types.ts b/x-pack/plugins/asset_inventory/public/types.ts new file mode 100644 index 000000000000..a551b4d231c3 --- /dev/null +++ b/x-pack/plugins/asset_inventory/public/types.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginSetup {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginStart {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AppPluginStartDependencies {} diff --git a/x-pack/plugins/asset_inventory/server/create_transforms/create_transforms.ts b/x-pack/plugins/asset_inventory/server/create_transforms/create_transforms.ts new file mode 100644 index 000000000000..0d3d0e8f8e0c --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/create_transforms/create_transforms.ts @@ -0,0 +1,142 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { transformError } from '@kbn/securitysolution-es-utils'; +import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/types'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { errors } from '@elastic/elasticsearch'; + +// TODO: Move transforms to integration package +export const initializeTransforms = async ( + esClient: ElasticsearchClient, + logger: Logger +): Promise => { + // Deletes old assets from previous versions as part of upgrade process + await deletePreviousTransformsVersions(esClient, logger); + // TODO initialize transforms here + // await initializeTransform(esClient, , logger); +}; + +export const initializeTransform = async ( + esClient: ElasticsearchClient, + transform: TransformPutTransformRequest, + logger: Logger +) => { + const success = await createTransformIfNotExists(esClient, transform, logger); + + if (success) { + await startTransformIfNotStarted(esClient, transform.transform_id, logger); + } +}; + +/** + * Checks if a transform exists, And if not creates it + * + * @param transform - the transform to create. If a transform with the same transform_id already exists, nothing is created or updated. + * + * @return true if the transform exits or created, false otherwise. + */ +export const createTransformIfNotExists = async ( + esClient: ElasticsearchClient, + transform: TransformPutTransformRequest, + logger: Logger +) => { + try { + await esClient.transform.getTransform({ + transform_id: transform.transform_id, + }); + return true; + } catch (existErr) { + const existError = transformError(existErr); + if (existError.statusCode === 404) { + try { + await esClient.transform.putTransform(transform); + return true; + } catch (createErr) { + const createError = transformError(createErr); + logger.error( + `Failed to create transform ${transform.transform_id}: ${createError.message}` + ); + } + } else { + logger.error( + `Failed to check if transform ${transform.transform_id} exists: ${existError.message}` + ); + } + } + return false; +}; + +export const startTransformIfNotStarted = async ( + esClient: ElasticsearchClient, + transformId: string, + logger: Logger +) => { + try { + const transformStats = await esClient.transform.getTransformStats({ + transform_id: transformId, + }); + + if (transformStats.count <= 0) { + logger.error(`Failed starting transform ${transformId}: couldn't find transform`); + return; + } + + const fetchedTransformStats = transformStats.transforms[0]; + + // trying to restart the transform in case it comes to a full stop or failure + if (fetchedTransformStats.state === 'stopped' || fetchedTransformStats.state === 'failed') { + try { + return await esClient.transform.startTransform({ transform_id: transformId }); + } catch (startErr) { + const startError = transformError(startErr); + logger.error( + `Failed to start transform ${transformId}. Transform State: Transform State: ${fetchedTransformStats.state}. Error: ${startError.message}` + ); + } + } + + if (fetchedTransformStats.state === 'stopping' || fetchedTransformStats.state === 'aborting') { + logger.error( + `Not starting transform ${transformId} since it's state is: ${fetchedTransformStats.state}` + ); + } + } catch (statsErr) { + const statsError = transformError(statsErr); + logger.error(`Failed to check if transform ${transformId} is started: ${statsError.message}`); + } +}; + +const deletePreviousTransformsVersions = async (esClient: ElasticsearchClient, logger: Logger) => { + // TODO Concat all deprecated transforms versions + const deprecatedTransforms: string[] = []; + + for (const transform of deprecatedTransforms) { + const response = await deleteTransformSafe(esClient, logger, transform); + if (response) return; + } +}; + +const deleteTransformSafe = async ( + esClient: ElasticsearchClient, + logger: Logger, + name: string +): Promise => { + try { + await esClient.transform.deleteTransform({ transform_id: name, force: true }); + logger.info(`Deleted transform successfully [Name: ${name}]`); + return true; + } catch (e) { + if (e instanceof errors.ResponseError && e.statusCode === 404) { + logger.trace(`Transform not exists [Name: ${name}]`); + return false; + } else { + logger.error(`Failed to delete transform [Name: ${name}]`); + logger.error(e); + return false; + } + } +}; diff --git a/x-pack/plugins/asset_inventory/server/index.ts b/x-pack/plugins/asset_inventory/server/index.ts new file mode 100644 index 000000000000..630661807889 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { PluginInitializerContext } from '@kbn/core/server'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export async function plugin(initializerContext: PluginInitializerContext) { + const { AssetInventoryPlugin } = await import('./plugin'); + return new AssetInventoryPlugin(initializerContext); +} + +export type { AssetInventoryPluginSetup, AssetInventoryPluginStart } from './types'; diff --git a/x-pack/plugins/asset_inventory/server/plugin.ts b/x-pack/plugins/asset_inventory/server/plugin.ts new file mode 100644 index 000000000000..3f35991c379d --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/plugin.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + Logger, +} from '@kbn/core/server'; + +import type { AssetInventoryPluginSetup, AssetInventoryPluginStart } from './types'; +import { defineRoutes } from './routes'; +// TODO Uncomment this line when initialize() is enabled +// import { initializeTransforms } from './create_transforms/create_transforms'; + +export class AssetInventoryPlugin + implements Plugin +{ + private readonly logger: Logger; + + // TODO Uncomment this line when initialize() is enabled + // private isInitialized: boolean = false; + + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup) { + this.logger.debug('assetInventory: Setup'); + const router = core.http.createRouter(); + + // Register server side APIs + defineRoutes(router); + + return {}; + } + + public start(core: CoreStart) { + this.logger.debug('assetInventory: Started'); + + // TODO Invoke initialize() when it's due + // this.initialize(core).catch(() => {}); + + return {}; + } + + public stop() {} + + /** + * Initialization is idempotent and required for (re)creating indices and transforms. + */ + // TODO Uncomment these lines when initialize() is enabled + // async initialize(core: CoreStart): Promise { + // this.logger.debug('initialize'); + // const esClient = core.elasticsearch.client.asInternalUser; + // await initializeTransforms(esClient, this.logger); + // this.isInitialized = true; + // } +} diff --git a/x-pack/plugins/asset_inventory/server/routes/index.ts b/x-pack/plugins/asset_inventory/server/routes/index.ts new file mode 100644 index 000000000000..f577bfa19f71 --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/routes/index.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { IRouter } from '@kbn/core/server'; + +export function defineRoutes(router: IRouter) { + router.get( + { + path: '/api/asset_inventory/example', + validate: false, + }, + async (context, request, response) => { + return response.ok({ + body: { + time: new Date().toISOString(), + }, + }); + } + ); +} diff --git a/x-pack/plugins/asset_inventory/server/types.ts b/x-pack/plugins/asset_inventory/server/types.ts new file mode 100644 index 000000000000..1d9380e8514f --- /dev/null +++ b/x-pack/plugins/asset_inventory/server/types.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface AssetInventoryPluginStart {} diff --git a/x-pack/plugins/asset_inventory/tsconfig.json b/x-pack/plugins/asset_inventory/tsconfig.json new file mode 100644 index 000000000000..dc669eb3a694 --- /dev/null +++ b/x-pack/plugins/asset_inventory/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "common/**/*.ts", + "common/**/*.json", + "public/**/*.ts", + "public/**/*.tsx", + "public/**/*.json", + "server/**/*.ts", + "server/**/*.json", + "../../../typings/**/*" + ], + "exclude": ["target/**/*"], + "kbn_references": [ + "@kbn/core", + "@kbn/i18n-react", + "@kbn/shared-ux-router", + "@kbn/securitysolution-es-utils" + ] +} diff --git a/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx b/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx index fa302c57ead8..d815864fb4a6 100644 --- a/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx +++ b/x-pack/plugins/canvas/public/components/hooks/use_canvas_api.tsx @@ -49,6 +49,8 @@ export const useCanvasApi: () => CanvasContainerApi = () => { createNewEmbeddable(panelType, initialState); }, disableTriggers: true, + // this is required to disable inline editing now enabled by default + canEditInline: false, type: 'canvas', /** * getSerializedStateForChild is left out here because we cannot access the state here. That method diff --git a/x-pack/plugins/cases/common/constants/owner.test.ts b/x-pack/plugins/cases/common/constants/owner.test.ts index 07b6866f857a..b53f177dd7d2 100644 --- a/x-pack/plugins/cases/common/constants/owner.test.ts +++ b/x-pack/plugins/cases/common/constants/owner.test.ts @@ -10,7 +10,11 @@ import { OWNER_INFO } from './owners'; describe('OWNER_INFO', () => { it('should use all available rule consumers', () => { - const allConsumers = new Set(Object.values(AlertConsumers)); + const allConsumers = new Set( + // Alerts consumer fallbacks to producer so it is not counted as valid one + Object.values(AlertConsumers).filter((consumer) => consumer !== AlertConsumers.ALERTS) + ); + const ownersMappingConsumers = new Set( Object.values(OWNER_INFO) .map((value) => value.validRuleConsumers ?? []) diff --git a/x-pack/plugins/cases/common/constants/owners.ts b/x-pack/plugins/cases/common/constants/owners.ts index a7628628a7dc..79db38345e56 100644 --- a/x-pack/plugins/cases/common/constants/owners.ts +++ b/x-pack/plugins/cases/common/constants/owners.ts @@ -59,6 +59,11 @@ export const OWNER_INFO: Record = { label: 'Management', iconType: 'managementApp', appRoute: '/app/management/insightsAndAlerting', - validRuleConsumers: [AlertConsumers.ML, AlertConsumers.STACK_ALERTS, AlertConsumers.EXAMPLE], + validRuleConsumers: [ + AlertConsumers.ML, + AlertConsumers.STACK_ALERTS, + AlertConsumers.EXAMPLE, + AlertConsumers.DISCOVER, + ], }, } as const; diff --git a/x-pack/plugins/cases/common/index.ts b/x-pack/plugins/cases/common/index.ts index 8e3b2644ee01..916b49163b69 100644 --- a/x-pack/plugins/cases/common/index.ts +++ b/x-pack/plugins/cases/common/index.ts @@ -31,7 +31,6 @@ export type { CaseViewRefreshPropInterface, CasesPermissions, CasesCapabilities, - CasesStatus, } from './ui/types'; export { CaseSeverity } from './types/domain'; diff --git a/x-pack/plugins/cases/common/types/api/metrics/v1.ts b/x-pack/plugins/cases/common/types/api/metrics/v1.ts index 895c0fe99b3b..43302cfb3bd8 100644 --- a/x-pack/plugins/cases/common/types/api/metrics/v1.ts +++ b/x-pack/plugins/cases/common/types/api/metrics/v1.ts @@ -23,6 +23,7 @@ export enum CaseMetricsFeature { CONNECTORS = 'connectors', LIFESPAN = 'lifespan', MTTR = 'mttr', + STATUS = 'status', } export const SingleCaseMetricsFeatureFieldRt = rt.union([ @@ -37,6 +38,7 @@ export const SingleCaseMetricsFeatureFieldRt = rt.union([ export const CasesMetricsFeatureFieldRt = rt.union([ SingleCaseMetricsFeatureFieldRt, rt.literal(CaseMetricsFeature.MTTR), + rt.literal(CaseMetricsFeature.STATUS), ]); const StatusInfoRt = rt.strict({ @@ -210,6 +212,10 @@ export const CasesMetricsResponseRt = rt.exact( * The average resolve time of all cases in seconds */ mttr: rt.union([rt.number, rt.null]), + /** + * The number of total cases per status + */ + status: rt.strict({ open: rt.number, inProgress: rt.number, closed: rt.number }), }) ); diff --git a/x-pack/plugins/cases/common/ui/types.ts b/x-pack/plugins/cases/common/ui/types.ts index 99c92e0dbb55..a03f38979cea 100644 --- a/x-pack/plugins/cases/common/ui/types.ts +++ b/x-pack/plugins/cases/common/ui/types.ts @@ -37,7 +37,6 @@ import type { import type { CasePatchRequest, CasesFindResponse, - CasesStatusResponse, CaseUserActionStatsResponse, GetCaseConnectorsResponse, GetCaseUsersResponse, @@ -105,7 +104,6 @@ export type CasesUI = CaseUI[]; export type CasesFindResponseUI = Omit, 'cases'> & { cases: CasesUI; }; -export type CasesStatus = SnakeToCamelCase; export type CasesMetrics = SnakeToCamelCase; export type CaseUpdateRequest = SnakeToCamelCase; export type CaseConnectors = SnakeToCamelCase; diff --git a/x-pack/plugins/cases/common/utils/owner.test.ts b/x-pack/plugins/cases/common/utils/owner.test.ts index a6f7c99f540b..4e005750ad36 100644 --- a/x-pack/plugins/cases/common/utils/owner.test.ts +++ b/x-pack/plugins/cases/common/utils/owner.test.ts @@ -40,7 +40,7 @@ describe('owner utils', () => { validRuleConsumers: item.validRuleConsumers, })); - it.each(owners)('returns owner %s correctly for consumer', (owner) => { + it.each(owners)('returns owner %j correctly for consumer', (owner) => { for (const consumer of owner.validRuleConsumers ?? []) { const result = getOwnerFromRuleConsumerProducer({ consumer }); @@ -48,7 +48,7 @@ describe('owner utils', () => { } }); - it.each(owners)('returns owner %s correctly for producer', (owner) => { + it.each(owners)('returns owner %j correctly for producer', (owner) => { for (const producer of owner.validRuleConsumers ?? []) { const result = getOwnerFromRuleConsumerProducer({ producer }); @@ -80,5 +80,14 @@ describe('owner utils', () => { expect(owner).toBe(OWNER_INFO.securitySolution.id); }); + + it('fallbacks to producer when the consumer is alerts', () => { + const owner = getOwnerFromRuleConsumerProducer({ + consumer: AlertConsumers.ALERTS, + producer: AlertConsumers.OBSERVABILITY, + }); + + expect(owner).toBe(OWNER_INFO.observability.id); + }); }); }); diff --git a/x-pack/plugins/cases/common/utils/owner.ts b/x-pack/plugins/cases/common/utils/owner.ts index 7bde7220233d..d159a3d55ee7 100644 --- a/x-pack/plugins/cases/common/utils/owner.ts +++ b/x-pack/plugins/cases/common/utils/owner.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { AlertConsumers } from '@kbn/rule-data-utils'; import { OWNER_INFO } from '../constants'; import type { Owner } from '../constants/types'; @@ -29,9 +30,12 @@ export const getOwnerFromRuleConsumerProducer = ({ return OWNER_INFO.securitySolution.id; } + // Fallback to producer if the consumer is alerts + const consumerValue = consumer === AlertConsumers.ALERTS ? producer : consumer; + for (const value of Object.values(OWNER_INFO)) { const foundConsumer = value.validRuleConsumers?.find( - (validConsumer) => validConsumer === consumer || validConsumer === producer + (validConsumer) => validConsumer === consumerValue || validConsumer === producer ); if (foundConsumer) { diff --git a/x-pack/plugins/cases/public/api/__mocks__/index.ts b/x-pack/plugins/cases/public/api/__mocks__/index.ts index ddf651b008d4..9b9d1e90d2c3 100644 --- a/x-pack/plugins/cases/public/api/__mocks__/index.ts +++ b/x-pack/plugins/cases/public/api/__mocks__/index.ts @@ -6,15 +6,9 @@ */ import type { HTTPService } from '..'; -import { casesMetrics, casesStatus } from '../../containers/mock'; -import type { CasesMetrics, CasesStatus } from '../../containers/types'; -import type { CasesFindRequest, CasesMetricsRequest } from '../../../common/types/api'; - -export const getCasesStatus = async ({ - http, - signal, - query, -}: HTTPService & { query: CasesFindRequest }): Promise => Promise.resolve(casesStatus); +import { casesMetrics } from '../../containers/mock'; +import type { CasesMetrics } from '../../containers/types'; +import type { CasesMetricsRequest } from '../../../common/types/api'; export const getCasesMetrics = async ({ http, diff --git a/x-pack/plugins/cases/public/api/decoders.ts b/x-pack/plugins/cases/public/api/decoders.ts index 57c5f03a1790..c2f9f466ec69 100644 --- a/x-pack/plugins/cases/public/api/decoders.ts +++ b/x-pack/plugins/cases/public/api/decoders.ts @@ -11,13 +11,11 @@ import { pipe } from 'fp-ts/lib/pipeable'; import type { CasesFindResponse, - CasesStatusResponse, CasesBulkGetResponse, CasesMetricsResponse, } from '../../common/types/api'; import { CasesFindResponseRt, - CasesStatusResponseRt, CasesBulkGetResponseRt, CasesMetricsResponseRt, } from '../../common/types/api'; @@ -26,13 +24,6 @@ import { throwErrors } from '../../common'; export const decodeCasesFindResponse = (respCases?: CasesFindResponse) => pipe(CasesFindResponseRt.decode(respCases), fold(throwErrors(createToasterPlainError), identity)); - -export const decodeCasesStatusResponse = (respCase?: CasesStatusResponse) => - pipe( - CasesStatusResponseRt.decode(respCase), - fold(throwErrors(createToasterPlainError), identity) - ); - export const decodeCasesMetricsResponse = (metrics?: CasesMetricsResponse) => pipe( CasesMetricsResponseRt.decode(metrics), diff --git a/x-pack/plugins/cases/public/api/index.ts b/x-pack/plugins/cases/public/api/index.ts index fbdf3c0bf6bc..86fc266224ac 100644 --- a/x-pack/plugins/cases/public/api/index.ts +++ b/x-pack/plugins/cases/public/api/index.ts @@ -9,18 +9,15 @@ import type { HttpStart } from '@kbn/core/public'; import type { CasesFindRequest, CasesFindResponse, - CasesStatusRequest, - CasesStatusResponse, CasesBulkGetRequest, CasesBulkGetResponse, CasesMetricsRequest, CasesMetricsResponse, } from '../../common/types/api'; -import type { CasesStatus, CasesMetrics, CasesFindResponseUI } from '../../common/ui'; +import type { CasesMetrics, CasesFindResponseUI } from '../../common/ui'; import { CASE_FIND_URL, INTERNAL_CASE_METRICS_URL, - CASE_STATUS_URL, INTERNAL_BULK_GET_CASES_URL, } from '../../common/constants'; import { convertAllCasesToCamel, convertToCamelCase } from './utils'; @@ -28,7 +25,6 @@ import { decodeCasesBulkGetResponse, decodeCasesFindResponse, decodeCasesMetricsResponse, - decodeCasesStatusResponse, } from './decoders'; export interface HTTPService { @@ -45,19 +41,6 @@ export const getCases = async ({ return convertAllCasesToCamel(decodeCasesFindResponse(res)); }; -export const getCasesStatus = async ({ - http, - query, - signal, -}: HTTPService & { query: CasesStatusRequest }): Promise => { - const response = await http.get(CASE_STATUS_URL, { - signal, - query, - }); - - return convertToCamelCase(decodeCasesStatusResponse(response)); -}; - export const getCasesMetrics = async ({ http, signal, diff --git a/x-pack/plugins/cases/public/client/api/index.ts b/x-pack/plugins/cases/public/client/api/index.ts index 822d8cea2737..214c5d80f39e 100644 --- a/x-pack/plugins/cases/public/client/api/index.ts +++ b/x-pack/plugins/cases/public/client/api/index.ts @@ -10,12 +10,11 @@ import type { CasesByAlertIDRequest, GetRelatedCasesByAlertResponse, CasesFindRequest, - CasesStatusRequest, CasesMetricsRequest, } from '../../../common/types/api'; import { getCasesFromAlertsUrl } from '../../../common/api'; -import { bulkGetCases, getCases, getCasesMetrics, getCasesStatus } from '../../api'; -import type { CasesFindResponseUI, CasesStatus, CasesMetrics } from '../../../common/ui'; +import { bulkGetCases, getCases, getCasesMetrics } from '../../api'; +import type { CasesFindResponseUI, CasesMetrics } from '../../../common/ui'; import type { CasesPublicStart } from '../../types'; export const createClientAPI = ({ http }: { http: HttpStart }): CasesPublicStart['api'] => { @@ -28,8 +27,6 @@ export const createClientAPI = ({ http }: { http: HttpStart }): CasesPublicStart cases: { find: (query: CasesFindRequest, signal?: AbortSignal): Promise => getCases({ http, query, signal }), - getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal): Promise => - getCasesStatus({ http, query, signal }), getCasesMetrics: (query: CasesMetricsRequest, signal?: AbortSignal): Promise => getCasesMetrics({ http, signal, query }), bulkGet: (params, signal?: AbortSignal) => bulkGetCases({ http, signal, params }), diff --git a/x-pack/plugins/cases/public/common/apm/use_cases_transactions.test.ts b/x-pack/plugins/cases/public/common/apm/use_cases_transactions.test.ts index c1cf6b305d48..9a5709c911fb 100644 --- a/x-pack/plugins/cases/public/common/apm/use_cases_transactions.test.ts +++ b/x-pack/plugins/cases/public/common/apm/use_cases_transactions.test.ts @@ -5,12 +5,8 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { CaseAttachmentsWithoutOwner } from '../../types'; -import type { - StartAddAttachmentToExistingCaseTransaction, - StartCreateCaseWithAttachmentsTransaction, -} from './use_cases_transactions'; import { useAddAttachmentToExistingCaseTransaction, useCreateCaseWithAttachmentsTransaction, @@ -37,14 +33,10 @@ const bulkAttachments = [ ] as CaseAttachmentsWithoutOwner; const renderUseCreateCaseWithAttachmentsTransaction = () => - renderHook( - useCreateCaseWithAttachmentsTransaction - ); + renderHook(useCreateCaseWithAttachmentsTransaction); const renderUseAddAttachmentToExistingCaseTransaction = () => - renderHook( - useAddAttachmentToExistingCaseTransaction - ); + renderHook(useAddAttachmentToExistingCaseTransaction); describe('cases transactions', () => { beforeEach(() => { diff --git a/x-pack/plugins/cases/public/common/hooks.test.tsx b/x-pack/plugins/cases/public/common/hooks.test.tsx index d2cea878504b..85dcfe11aaf5 100644 --- a/x-pack/plugins/cases/public/common/hooks.test.tsx +++ b/x-pack/plugins/cases/public/common/hooks.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { TestProviders } from './mock'; import { useIsMainApplication } from './hooks'; diff --git a/x-pack/plugins/cases/public/common/lib/kibana/hooks.test.tsx b/x-pack/plugins/cases/public/common/lib/kibana/hooks.test.tsx index 60b798d37822..73d1822c6249 100644 --- a/x-pack/plugins/cases/public/common/lib/kibana/hooks.test.tsx +++ b/x-pack/plugins/cases/public/common/lib/kibana/hooks.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useApplicationCapabilities } from './hooks'; import { allCasesPermissions, TestProviders } from '../../mock'; @@ -14,10 +14,7 @@ import { allCasesPermissions, TestProviders } from '../../mock'; describe('hooks', () => { describe('useApplicationCapabilities', () => { it('should return the correct capabilities', async () => { - const { result } = renderHook< - React.PropsWithChildren<{}>, - ReturnType - >(() => useApplicationCapabilities(), { + const { result } = renderHook(() => useApplicationCapabilities(), { wrapper: ({ children }) => {children}, }); diff --git a/x-pack/plugins/cases/public/common/lib/kibana/use_application.test.tsx b/x-pack/plugins/cases/public/common/lib/kibana/use_application.test.tsx index 81152d3d3c5a..69c5fc4f8db2 100644 --- a/x-pack/plugins/cases/public/common/lib/kibana/use_application.test.tsx +++ b/x-pack/plugins/cases/public/common/lib/kibana/use_application.test.tsx @@ -7,7 +7,7 @@ import type { PublicAppInfo } from '@kbn/core-application-browser'; import { AppStatus } from '@kbn/core-application-browser'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { BehaviorSubject, Subject } from 'rxjs'; import type { AppMockRenderer } from '../../mock'; import { createAppMockRenderer } from '../../mock'; diff --git a/x-pack/plugins/cases/public/common/navigation/hooks.test.tsx b/x-pack/plugins/cases/public/common/navigation/hooks.test.tsx index 2170ed2d0e58..867e4d682695 100644 --- a/x-pack/plugins/cases/public/common/navigation/hooks.test.tsx +++ b/x-pack/plugins/cases/public/common/navigation/hooks.test.tsx @@ -6,7 +6,8 @@ */ import React from 'react'; -import { act, renderHook } from '@testing-library/react-hooks'; + +import { renderHook, act } from '@testing-library/react'; import { APP_ID } from '../../../common/constants'; import { useNavigation } from '../lib/kibana'; diff --git a/x-pack/plugins/cases/public/common/use_cases_features.test.tsx b/x-pack/plugins/cases/public/common/use_cases_features.test.tsx index eeabf3fb0cab..c4c54af0b1c4 100644 --- a/x-pack/plugins/cases/public/common/use_cases_features.test.tsx +++ b/x-pack/plugins/cases/public/common/use_cases_features.test.tsx @@ -6,10 +6,9 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; import type { CasesContextFeatures } from '../../common/ui'; -import type { UseCasesFeatures } from './use_cases_features'; import { useCasesFeatures } from './use_cases_features'; import { TestProviders } from './mock/test_providers'; import type { LicenseType } from '@kbn/licensing-plugin/common/types'; @@ -37,14 +36,9 @@ describe('useCasesFeatures', () => { it.each(tests)( 'returns isAlertsEnabled=%s and isSyncAlertsEnabled=%s if feature.alerts=%s', async (isAlertsEnabled, isSyncAlertsEnabled, alerts) => { - const { result } = renderHook, UseCasesFeatures>( - () => useCasesFeatures(), - { - wrapper: ({ children }) => ( - {children} - ), - } - ); + const { result } = renderHook(() => useCasesFeatures(), { + wrapper: ({ children }) => {children}, + }); expect(result.current).toEqual({ isAlertsEnabled, @@ -57,16 +51,13 @@ describe('useCasesFeatures', () => { ); it('returns the metrics correctly', async () => { - const { result } = renderHook, UseCasesFeatures>( - () => useCasesFeatures(), - { - wrapper: ({ children }) => ( - - {children} - - ), - } - ); + const { result } = renderHook(() => useCasesFeatures(), { + wrapper: ({ children }) => ( + + {children} + + ), + }); expect(result.current).toEqual({ isAlertsEnabled: true, @@ -91,12 +82,9 @@ describe('useCasesFeatures', () => { license: { type }, }); - const { result } = renderHook, UseCasesFeatures>( - () => useCasesFeatures(), - { - wrapper: ({ children }) => {children}, - } - ); + const { result } = renderHook(() => useCasesFeatures(), { + wrapper: ({ children }) => {children}, + }); expect(result.current).toEqual({ isAlertsEnabled: true, diff --git a/x-pack/plugins/cases/public/common/use_cases_local_storage.test.tsx b/x-pack/plugins/cases/public/common/use_cases_local_storage.test.tsx index 740fa78dc3c0..92dd5808b6b7 100644 --- a/x-pack/plugins/cases/public/common/use_cases_local_storage.test.tsx +++ b/x-pack/plugins/cases/public/common/use_cases_local_storage.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { Subject } from 'rxjs'; import type { AppMockRenderer } from './mock/test_providers'; import { createAppMockRenderer } from './mock/test_providers'; diff --git a/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx b/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx index bb0c0b3a9f53..c1f7d67a8b8b 100644 --- a/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx +++ b/x-pack/plugins/cases/public/common/use_cases_toast.test.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; import { useKibana, useToasts } from './lib/kibana'; import type { AppMockRenderer } from './mock'; import { createAppMockRenderer, TestProviders } from './mock'; @@ -14,7 +13,7 @@ import { alertComment, basicComment, mockCase } from '../containers/mock'; import React from 'react'; import userEvent from '@testing-library/user-event'; import type { SupportedCaseAttachment } from '../types'; -import { getByTestId, queryByTestId, screen } from '@testing-library/react'; +import { getByTestId, queryByTestId, screen, renderHook } from '@testing-library/react'; import { OWNER_INFO } from '../../common/constants'; import { useApplication } from './lib/kibana/use_application'; diff --git a/x-pack/plugins/cases/public/common/use_is_user_typing.test.tsx b/x-pack/plugins/cases/public/common/use_is_user_typing.test.tsx index 229ecc13bba0..d4ec97346996 100644 --- a/x-pack/plugins/cases/public/common/use_is_user_typing.test.tsx +++ b/x-pack/plugins/cases/public/common/use_is_user_typing.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import type { AppMockRenderer } from './mock'; import { createAppMockRenderer } from './mock'; import { useIsUserTyping } from './use_is_user_typing'; diff --git a/x-pack/plugins/cases/public/common/use_license.test.tsx b/x-pack/plugins/cases/public/common/use_license.test.tsx index 0c28be2ca746..8a5c29394cc6 100644 --- a/x-pack/plugins/cases/public/common/use_license.test.tsx +++ b/x-pack/plugins/cases/public/common/use_license.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { TestProviders } from './mock'; import { useLicense } from './use_license'; diff --git a/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.test.tsx b/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.test.tsx index 98cac1dfaf46..78b7801b699f 100644 --- a/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/assignees/use_assignees_action.test.tsx @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useAssigneesAction } from './use_assignees_action'; import * as api from '../../../containers/api'; @@ -56,7 +56,7 @@ describe('useAssigneesAction', () => { it('update the assignees correctly', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useAssigneesAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -92,7 +92,7 @@ describe('useAssigneesAction', () => { }); it('shows the success toaster correctly when updating one case', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useAssigneesAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -118,7 +118,7 @@ describe('useAssigneesAction', () => { }); it('shows the success toaster correctly when updating multiple cases', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useAssigneesAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, diff --git a/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.test.tsx b/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.test.tsx index 388b3de940ec..2be5f4b83a23 100644 --- a/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/copy_id/use_copy_id_action.test.tsx @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useCopyIDAction } from './use_copy_id_action'; import { basicCase } from '../../../containers/mock'; @@ -58,7 +58,7 @@ describe('useCopyIDAction', () => { }); it('copies the id of the selected case to the clipboard', async () => { - const { result, waitFor } = renderHook(() => useCopyIDAction({ onActionSuccess }), { + const { result } = renderHook(() => useCopyIDAction({ onActionSuccess }), { wrapper: appMockRender.AppWrapper, }); @@ -73,7 +73,7 @@ describe('useCopyIDAction', () => { }); it('shows the success toaster correctly when copying the case id', async () => { - const { result, waitFor } = renderHook(() => useCopyIDAction({ onActionSuccess }), { + const { result } = renderHook(() => useCopyIDAction({ onActionSuccess }), { wrapper: appMockRender.AppWrapper, }); 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 index 9730783f39af..fee612cbf04f 100644 --- 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 @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useDeleteAction } from './use_delete_action'; import * as api from '../../../containers/api'; @@ -84,7 +84,7 @@ describe('useDeleteAction', () => { it('deletes the selected cases', async () => { const deleteSpy = jest.spyOn(api, 'deleteCases'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -112,7 +112,7 @@ describe('useDeleteAction', () => { }); it('closes the modal', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -137,7 +137,7 @@ describe('useDeleteAction', () => { }); it('shows the success toaster correctly when delete one case', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -163,7 +163,7 @@ describe('useDeleteAction', () => { }); it('shows the success toaster correctly when delete multiple case', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useDeleteAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, diff --git a/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.test.tsx b/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.test.tsx index 79ae67610d90..93982ff334c2 100644 --- a/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/severity/use_severity_action.test.tsx @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useSeverityAction } from './use_severity_action'; import * as api from '../../../containers/api'; @@ -80,7 +80,7 @@ describe('useSeverityAction', () => { it('update the severity cases', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useSeverityAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -120,7 +120,7 @@ describe('useSeverityAction', () => { it.each(singleCaseTests)( 'shows the success toaster correctly when updating the severity of the case: %s', async (_, index, expectedMessage) => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useSeverityAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -153,7 +153,7 @@ describe('useSeverityAction', () => { it.each(multipleCasesTests)( 'shows the success toaster correctly when updating the severity of the case: %s', async (_, index, expectedMessage) => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useSeverityAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, 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 index 5ad7f9803dd6..9a007e5ea28a 100644 --- 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 @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useStatusAction } from './use_status_action'; import * as api from '../../../containers/api'; @@ -82,7 +82,7 @@ describe('useStatusAction', () => { it('update the status cases', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -120,7 +120,7 @@ describe('useStatusAction', () => { it.each(singleCaseTests)( 'shows the success toaster correctly when updating the status of the case: %s', async (_, index, expectedMessage) => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -152,7 +152,7 @@ describe('useStatusAction', () => { it.each(multipleCasesTests)( 'shows the success toaster correctly when updating the status of the case: %s', async (_, index, expectedMessage) => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useStatusAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, diff --git a/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.test.tsx b/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.test.tsx index 14973cc59be7..dbe2a1cc17aa 100644 --- a/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/tags/use_tags_action.test.tsx @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useTagsAction } from './use_tags_action'; import * as api from '../../../containers/api'; @@ -56,7 +56,7 @@ describe('useTagsAction', () => { it('update the tags correctly', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useTagsAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -86,7 +86,7 @@ describe('useTagsAction', () => { }); it('shows the success toaster correctly when updating one case', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useTagsAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, @@ -112,7 +112,7 @@ describe('useTagsAction', () => { }); it('shows the success toaster correctly when updating multiple cases', async () => { - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useTagsAction({ onAction, onActionSuccess, isDisabled: false }), { wrapper: appMockRender.AppWrapper, diff --git a/x-pack/plugins/cases/public/components/actions/use_items_action.test.tsx b/x-pack/plugins/cases/public/components/actions/use_items_action.test.tsx index 25a08007ac31..b1f24562f89b 100644 --- a/x-pack/plugins/cases/public/components/actions/use_items_action.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/use_items_action.test.tsx @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useItemsAction } from './use_items_action'; import * as api from '../../containers/api'; @@ -54,7 +54,7 @@ describe('useItemsAction', () => { }); it('closes the flyout', async () => { - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -81,7 +81,7 @@ describe('useItemsAction', () => { it('update the items correctly', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -117,7 +117,7 @@ describe('useItemsAction', () => { }); it('calls fieldSelector correctly', async () => { - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -142,7 +142,7 @@ describe('useItemsAction', () => { }); it('calls itemsTransformer correctly', async () => { - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -169,7 +169,7 @@ describe('useItemsAction', () => { it('removes duplicates', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -203,7 +203,7 @@ describe('useItemsAction', () => { }); it('shows the success toaster correctly when updating a case', async () => { - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -229,7 +229,7 @@ describe('useItemsAction', () => { it('do not update cases with no changes', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -254,7 +254,7 @@ describe('useItemsAction', () => { it('do not update if the selected items are the same but with different order', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -279,7 +279,7 @@ describe('useItemsAction', () => { it('do not update if the selected items are the same', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -304,7 +304,7 @@ describe('useItemsAction', () => { it('do not update if selecting and unselecting the same item', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); @@ -329,7 +329,7 @@ describe('useItemsAction', () => { it('do not update with empty items and no selection', async () => { const updateSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor } = renderHook(() => useItemsAction(props), { + const { result } = renderHook(() => useItemsAction(props), { wrapper: appMockRender.AppWrapper, }); diff --git a/x-pack/plugins/cases/public/components/actions/use_items_state.test.tsx b/x-pack/plugins/cases/public/components/actions/use_items_state.test.tsx index a680ec655652..e0f07eaf1a5c 100644 --- a/x-pack/plugins/cases/public/components/actions/use_items_state.test.tsx +++ b/x-pack/plugins/cases/public/components/actions/use_items_state.test.tsx @@ -7,7 +7,7 @@ import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useItemsState } from './use_items_state'; import { basicCase } from '../../containers/mock'; 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 bc540040cce5..5c79aadbcfee 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 @@ -7,8 +7,7 @@ import React from 'react'; import moment from 'moment-timezone'; -import { render, waitFor, screen, within } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { render, waitFor, screen, within, renderHook } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; @@ -27,7 +26,6 @@ import { SECURITY_SOLUTION_OWNER } from '../../../common/constants'; import { getEmptyCellValue } from '../empty_value'; import { useKibana } from '../../common/lib/kibana'; import { AllCasesList } from './all_cases_list'; -import type { GetCasesColumn, UseCasesColumnsReturnValue } from './use_cases_columns'; import { useCasesColumns } from './use_cases_columns'; import { triggersActionsUiMock } from '@kbn/triggers-actions-ui-plugin/public/mocks'; import { registerConnectorsToMockActionRegistry } from '../../common/mock/register_connectors'; @@ -267,10 +265,7 @@ describe.skip('AllCasesListGeneric', () => { expect(column[key].querySelector('span')).toHaveTextContent(emptyTag); }; - const { result } = renderHook< - React.PropsWithChildren, - UseCasesColumnsReturnValue - >(() => useCasesColumns(defaultColumnArgs), { + const { result } = renderHook(() => useCasesColumns(defaultColumnArgs), { wrapper: ({ children }) => {children}, }); diff --git a/x-pack/plugins/cases/public/components/all_cases/cases_metrics.test.tsx b/x-pack/plugins/cases/public/components/all_cases/cases_metrics.test.tsx index 9105f8247689..9fd5f53af2f2 100644 --- a/x-pack/plugins/cases/public/components/all_cases/cases_metrics.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/cases_metrics.test.tsx @@ -10,27 +10,22 @@ import React from 'react'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; import { useGetCasesMetrics } from '../../containers/use_get_cases_metrics'; -import { useGetCasesStatus } from '../../containers/use_get_cases_status'; import { CasesMetrics } from './cases_metrics'; jest.mock('pretty-ms', () => jest.fn().mockReturnValue('2ms')); jest.mock('../../containers/use_get_cases_metrics'); -jest.mock('../../containers/use_get_cases_status'); const useGetCasesMetricsMock = useGetCasesMetrics as jest.Mock; -const useGetCasesStatusMock = useGetCasesStatus as jest.Mock; describe('Cases metrics', () => { let appMockRenderer: AppMockRenderer; beforeEach(() => { - useGetCasesMetricsMock.mockReturnValue({ isLoading: false, data: { mttr: 2000 } }); - useGetCasesStatusMock.mockReturnValue({ + useGetCasesMetricsMock.mockReturnValue({ isLoading: false, data: { - countOpenCases: 20, - countInProgressCases: 40, - countClosedCases: 130, + mttr: 2000, + status: { open: 20, inProgress: 40, closed: 130 }, }, }); diff --git a/x-pack/plugins/cases/public/components/all_cases/cases_metrics.tsx b/x-pack/plugins/cases/public/components/all_cases/cases_metrics.tsx index 3d883550bd4a..525b061965ff 100644 --- a/x-pack/plugins/cases/public/components/all_cases/cases_metrics.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/cases_metrics.tsx @@ -17,22 +17,13 @@ import { } from '@elastic/eui'; import prettyMilliseconds from 'pretty-ms'; import { CaseStatuses } from '../../../common/types/domain'; -import { useGetCasesStatus } from '../../containers/use_get_cases_status'; import { StatusStats } from '../status/status_stats'; import { useGetCasesMetrics } from '../../containers/use_get_cases_metrics'; import { ATTC_DESCRIPTION, ATTC_STAT, ATTC_STAT_INFO_ARIA_LABEL } from './translations'; export const CasesMetrics: React.FC = () => { - const { - data: { countOpenCases, countInProgressCases, countClosedCases } = { - countOpenCases: 0, - countInProgressCases: 0, - countClosedCases: 0, - }, - isLoading: isCasesStatusLoading, - } = useGetCasesStatus(); - - const { data: { mttr } = { mttr: 0 }, isLoading: isCasesMetricsLoading } = useGetCasesMetrics(); + const { data: { mttr, status } = { mttr: 0 }, isLoading: isCasesMetricsLoading } = + useGetCasesMetrics(); const mttrValue = useMemo( () => (mttr != null ? prettyMilliseconds(mttr * 1000, { compact: true, verbose: false }) : '-'), @@ -46,25 +37,25 @@ export const CasesMetrics: React.FC = () => { diff --git a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx index 644c67b632df..dbe7412a5d7b 100644 --- a/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/selector_modal/use_cases_add_to_existing_case_modal.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { waitFor } from '@testing-library/react'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook, act } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import type { FC, PropsWithChildren } from 'react'; import React from 'react'; @@ -96,12 +95,11 @@ describe('use cases add to existing case modal hook', () => { }); it('should throw if called outside of a cases context', () => { - const { result } = renderHook(() => { - useCasesAddToExistingCaseModal(defaultParams()); - }); - expect(result.error?.message).toContain( - 'useCasesContext must be used within a CasesProvider and have a defined value' - ); + expect(() => + renderHook(() => { + useCasesAddToExistingCaseModal(defaultParams()); + }) + ).toThrow(/useCasesContext must be used within a CasesProvider and have a defined value/); }); it('should dispatch the open action when invoked', () => { diff --git a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx index 89419d587237..c38486dfb7ea 100644 --- a/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/table_filter_config/use_filter_config.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; import type { FilterConfig, FilterConfigRenderParams } from './types'; @@ -64,7 +64,7 @@ describe('useFilterConfig', () => { it('should remove a selected option if the filter is deleted', async () => { const { rerender } = renderHook(useFilterConfig, { - wrapper: ({ children }: React.PropsWithChildren[0]>) => ( + wrapper: ({ children }: React.PropsWithChildren) => ( {children} ), initialProps: { @@ -106,7 +106,7 @@ describe('useFilterConfig', () => { ); const { result } = renderHook(useFilterConfig, { - wrapper: ({ children }: React.PropsWithChildren[0]>) => ( + wrapper: ({ children }: React.PropsWithChildren) => ( {children} ), initialProps: { 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 index bb0ba6ed009e..e98926bcd0b4 100644 --- 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 @@ -6,8 +6,7 @@ */ import userEvent, { type UserEvent } from '@testing-library/user-event'; -import { waitFor } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor, renderHook } from '@testing-library/react'; import { waitForEuiPopoverOpen, waitForEuiContextMenuPanelTransition, diff --git a/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx index 1e257c8fbcef..511edce760a4 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_all_cases_state.test.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook, act } from '@testing-library/react'; import { CaseStatuses } from '@kbn/cases-components'; import { TestProviders } from '../../common/mock'; 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 index 1838ee3b14f5..2bbd7da38545 100644 --- 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 @@ -8,8 +8,7 @@ import React from 'react'; import { EuiContextMenu } from '@elastic/eui'; import userEvent from '@testing-library/user-event'; -import { waitFor } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor, renderHook } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; import { @@ -190,7 +189,7 @@ describe('useBulkActions', () => { it('change the status of cases', async () => { const updateCasesSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -219,7 +218,7 @@ describe('useBulkActions', () => { pointerEventsCheck: 0, }); - await waitForHook(() => { + await waitFor(() => { expect(updateCasesSpy).toHaveBeenCalled(); }); }); @@ -227,7 +226,7 @@ describe('useBulkActions', () => { it('change the severity of cases', async () => { const updateCasesSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -257,7 +256,7 @@ describe('useBulkActions', () => { pointerEventsCheck: 0, }); - await waitForHook(() => { + await waitFor(() => { expect(updateCasesSpy).toHaveBeenCalled(); }); }); @@ -266,7 +265,7 @@ describe('useBulkActions', () => { it('delete a case', async () => { const deleteSpy = jest.spyOn(api, 'deleteCases'); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -299,7 +298,7 @@ describe('useBulkActions', () => { await userEvent.click(res.getByTestId('confirmModalConfirmButton')); - await waitForHook(() => { + await waitFor(() => { expect(deleteSpy).toHaveBeenCalled(); }); }); @@ -355,7 +354,7 @@ describe('useBulkActions', () => { it('change the tags of the case', async () => { const updateCasesSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -394,7 +393,7 @@ describe('useBulkActions', () => { await userEvent.click(res.getByText('coke')); await userEvent.click(res.getByTestId('cases-edit-tags-flyout-submit')); - await waitForHook(() => { + await waitFor(() => { expect(updateCasesSpy).toHaveBeenCalled(); }); }); @@ -402,7 +401,7 @@ describe('useBulkActions', () => { it('change the assignees of the case', async () => { const updateCasesSpy = jest.spyOn(api, 'updateCases'); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -441,7 +440,7 @@ describe('useBulkActions', () => { await userEvent.click(res.getByText('Damaged Raccoon')); await userEvent.click(res.getByTestId('cases-edit-assignees-flyout-submit')); - await waitForHook(() => { + await waitFor(() => { expect(updateCasesSpy).toHaveBeenCalled(); }); }); @@ -450,7 +449,7 @@ describe('useBulkActions', () => { describe('Permissions', () => { it('shows the correct actions with all permissions', async () => { appMockRender = createAppMockRenderer({ permissions: allCasesPermissions() }); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -467,7 +466,7 @@ describe('useBulkActions', () => { ); - await waitForHook(() => { + await waitFor(() => { expect(res.getByTestId('case-bulk-action-status')).toBeInTheDocument(); expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); expect(res.getByTestId('bulk-actions-separator')).toBeInTheDocument(); @@ -476,7 +475,7 @@ describe('useBulkActions', () => { it('shows the correct actions with no delete permissions', async () => { appMockRender = createAppMockRenderer({ permissions: noDeleteCasesPermissions() }); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -493,7 +492,7 @@ describe('useBulkActions', () => { ); - await waitForHook(() => { + await waitFor(() => { expect(res.getByTestId('case-bulk-action-status')).toBeInTheDocument(); expect(res.queryByTestId('cases-bulk-action-delete')).toBeFalsy(); expect(res.queryByTestId('bulk-actions-separator')).toBeFalsy(); @@ -502,7 +501,7 @@ describe('useBulkActions', () => { it('shows the correct actions with only delete permissions', async () => { appMockRender = createAppMockRenderer({ permissions: onlyDeleteCasesPermission() }); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCase] }), { wrapper: appMockRender.AppWrapper, @@ -519,7 +518,7 @@ describe('useBulkActions', () => { ); - await waitForHook(() => { + await waitFor(() => { expect(res.queryByTestId('case-bulk-action-status')).toBeFalsy(); expect(res.getByTestId('cases-bulk-action-delete')).toBeInTheDocument(); expect(res.queryByTestId('bulk-actions-separator')).toBeFalsy(); @@ -528,7 +527,7 @@ describe('useBulkActions', () => { it('shows the correct actions with no reopen permissions', async () => { appMockRender = createAppMockRenderer({ permissions: noReopenCasesPermissions() }); - const { result, waitFor: waitForHook } = renderHook( + const { result } = renderHook( () => useBulkActions({ onAction, onActionSuccess, selectedCases: [basicCaseClosed] }), { wrapper: appMockRender.AppWrapper, @@ -545,12 +544,12 @@ describe('useBulkActions', () => { ); - await waitForHook(() => { + await waitFor(() => { expect(res.queryByTestId('case-bulk-action-status')).toBeInTheDocument(); res.queryByTestId('case-bulk-action-status')?.click(); }); - await waitForHook(() => { + await waitFor(() => { expect(res.queryByTestId('cases-bulk-action-status-open')).toBeDisabled(); expect(res.queryByTestId('cases-bulk-action-status-in-progress')).toBeDisabled(); expect(res.queryByTestId('cases-bulk-action-status-closed')).toBeDisabled(); 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 index 22783cf05cfc..fc50c7a61a64 100644 --- 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 @@ -15,7 +15,7 @@ import { useGetCasesMockState } from '../../containers/mock'; import { connectors, useCaseConfigureResponse } from '../configure_cases/__mock__'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer, readCasesPermissions, TestProviders } from '../../common/mock'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { CaseStatuses, CustomFieldTypes } from '../../../common/types/domain'; import { userProfilesMap } from '../../containers/user_profiles/api.mock'; import { useGetCaseConfiguration } from '../../containers/configure/use_get_case_configuration'; @@ -83,12 +83,13 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "assignees", "name": "Assignees", "render": [Function], + "width": "10%", }, Object { "field": "tags", @@ -101,50 +102,54 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "closedAt", "name": "Closed on", "render": [Function], "sortable": true, + "width": "10%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", @@ -185,12 +190,13 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "assignees", "name": "Assignees", "render": [Function], + "width": "10%", }, Object { "field": "tags", @@ -203,44 +209,47 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", @@ -291,13 +300,14 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "severity", @@ -309,6 +319,7 @@ describe('useCasesColumns ', () => { Object { "align": "right", "render": [Function], + "width": "70px", }, ], "isLoadingColumns": false, @@ -340,13 +351,14 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "severity", @@ -358,6 +370,7 @@ describe('useCasesColumns ', () => { Object { "align": "right", "render": [Function], + "width": "70px", }, ], "isLoadingColumns": false, @@ -389,13 +402,14 @@ describe('useCasesColumns ', () => { "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "severity", @@ -407,6 +421,7 @@ describe('useCasesColumns ', () => { Object { "align": "right", "render": [Function], + "width": "70px", }, ], "isLoadingColumns": false, @@ -430,7 +445,7 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "tags", @@ -443,44 +458,47 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", @@ -538,7 +556,7 @@ describe('useCasesColumns ', () => { "name": "Name", "render": [Function], "sortable": true, - "width": "20%", + "width": "17%", }, Object { "field": "tags", @@ -551,44 +569,47 @@ describe('useCasesColumns ', () => { "field": "totalAlerts", "name": "Alerts", "render": [Function], - "width": "80px", + "width": "70px", }, Object { "align": "right", "field": "totalComment", "name": "Comments", "render": [Function], - "width": "90px", + "width": "75px", }, Object { "field": "category", "name": "Category", "render": [Function], "sortable": true, - "width": "120px", + "width": "12%", }, Object { "field": "createdAt", "name": "Created on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "field": "updatedAt", "name": "Updated on", "render": [Function], "sortable": true, + "width": "15%", }, Object { "name": "External incident", "render": [Function], + "width": "10%", }, Object { "field": "status", "name": "Status", "render": [Function], "sortable": true, - "width": "110px", + "width": "100px", }, Object { "field": "severity", diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx index efdc44336688..73292ac9d71b 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns.tsx @@ -122,7 +122,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: !isSelectorView ? '20%' : '55%', + width: !isSelectorView ? '17%' : '55%', }, assignees: { field: casesColumnsConfig.assignees.field, @@ -130,6 +130,7 @@ export const useCasesColumns = ({ render: (assignees: CaseUI['assignees']) => ( ), + width: '10%', }, tags: { field: casesColumnsConfig.tags.field, @@ -193,7 +194,7 @@ export const useCasesColumns = ({ totalAlerts != null ? renderStringField(`${totalAlerts}`, `case-table-column-alertsCount`) : getEmptyCellValue(), - width: !isSelectorView ? '80px' : '55px', + width: !isSelectorView ? '70px' : '55px', }, totalComment: { field: casesColumnsConfig.totalComment.field, @@ -203,7 +204,7 @@ export const useCasesColumns = ({ totalComment != null ? renderStringField(`${totalComment}`, `case-table-column-commentCount`) : getEmptyCellValue(), - width: '90px', + width: '75px', }, category: { field: casesColumnsConfig.category.field, @@ -217,7 +218,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, - width: '120px', + width: '12%', }, closedAt: { field: casesColumnsConfig.closedAt.field, @@ -233,6 +234,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '10%', }, createdAt: { field: casesColumnsConfig.createdAt.field, @@ -248,6 +250,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '15%', }, updatedAt: { field: casesColumnsConfig.updatedAt.field, @@ -263,6 +266,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '15%', }, externalIncident: { // no field @@ -273,6 +277,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '10%', }, status: { field: casesColumnsConfig.status.field, @@ -285,7 +290,7 @@ export const useCasesColumns = ({ return getEmptyCellValue(); }, - width: '110px', + width: '100px', }, severity: { field: casesColumnsConfig.severity.field, @@ -326,6 +331,7 @@ export const useCasesColumns = ({ } return getEmptyCellValue(); }, + width: '70px', }, }), [assignCaseAction, casesColumnsConfig, connectors, isSelectorView, userProfiles] diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_configuration.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_configuration.test.tsx index 761da1d6316e..4a4a139445c5 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_configuration.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_configuration.test.tsx @@ -6,7 +6,7 @@ */ import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; diff --git a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_selection.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_selection.test.tsx index 26f0f8c2fb85..e6603a35a1a0 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_selection.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_cases_columns_selection.test.tsx @@ -6,7 +6,7 @@ */ import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; diff --git a/x-pack/plugins/cases/public/components/all_cases/use_on_refresh_cases.test.tsx b/x-pack/plugins/cases/public/components/all_cases/use_on_refresh_cases.test.tsx index 484fabca00c3..338055e5da0c 100644 --- a/x-pack/plugins/cases/public/components/all_cases/use_on_refresh_cases.test.tsx +++ b/x-pack/plugins/cases/public/components/all_cases/use_on_refresh_cases.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; import { casesQueriesKeys } from '../../containers/constants'; diff --git a/x-pack/plugins/cases/public/components/app/use_available_owners.test.ts b/x-pack/plugins/cases/public/components/app/use_available_owners.test.ts index 4cd015de0c92..5a19e9a0f995 100644 --- a/x-pack/plugins/cases/public/components/app/use_available_owners.test.ts +++ b/x-pack/plugins/cases/public/components/app/use_available_owners.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { APP_ID, OBSERVABILITY_OWNER, SECURITY_SOLUTION_OWNER } from '../../../common/constants'; import { useKibana } from '../../common/lib/kibana'; diff --git a/x-pack/plugins/cases/public/components/app/use_readonly_header.test.tsx b/x-pack/plugins/cases/public/components/app/use_readonly_header.test.tsx index 9be5a6336b3c..69d7a9a8b65a 100644 --- a/x-pack/plugins/cases/public/components/app/use_readonly_header.test.tsx +++ b/x-pack/plugins/cases/public/components/app/use_readonly_header.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useKibana } from '../../common/lib/kibana'; import { readCasesPermissions, TestProviders } from '../../common/mock'; diff --git a/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx index 12f72a073b7f..2034d3c4099a 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/severity.test.tsx @@ -6,9 +6,7 @@ */ import React from 'react'; -import { screen, waitFor } from '@testing-library/react'; -import type { AppMockRenderer } from '../../common/mock'; -import { createAppMockRenderer } from '../../common/mock'; +import { render, screen, waitFor } from '@testing-library/react'; import { Severity } from './severity'; import userEvent from '@testing-library/user-event'; import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; @@ -16,20 +14,9 @@ import { FormTestComponent } from '../../common/test_utils'; const onSubmit = jest.fn(); -// FLAKY: https://github.com/elastic/kibana/issues/188951 -describe.skip('Severity form field', () => { - let appMockRender: AppMockRenderer; - - beforeEach(() => { - appMockRender = createAppMockRenderer(); - }); - - afterEach(async () => { - await appMockRender.clearQueryCache(); - }); - +describe('Severity form field', () => { it('renders', async () => { - appMockRender.render( + render( @@ -41,7 +28,7 @@ describe.skip('Severity form field', () => { // default to LOW in this test configuration it('defaults to the correct value', async () => { - appMockRender.render( + render( @@ -52,7 +39,7 @@ describe.skip('Severity form field', () => { }); it('selects the correct value when changed', async () => { - appMockRender.render( + render( @@ -74,7 +61,7 @@ describe.skip('Severity form field', () => { }); it('disables when loading data', async () => { - appMockRender.render( + render( diff --git a/x-pack/plugins/cases/public/components/case_form_fields/sync_alerts_toggle.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/sync_alerts_toggle.test.tsx index fbe7eca21839..238abfefeb47 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/sync_alerts_toggle.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/sync_alerts_toggle.test.tsx @@ -33,9 +33,10 @@ describe('SyncAlertsToggle', () => { ); - expect(await screen.findByTestId('caseSyncAlerts')).toBeInTheDocument(); - expect(await screen.findByRole('switch')).toHaveAttribute('aria-checked', 'true'); - expect(await screen.findByText('On')).toBeInTheDocument(); + const syncAlerts = await screen.findByTestId('caseSyncAlerts'); + expect(syncAlerts).toBeInTheDocument(); + expect(within(syncAlerts).getByRole('switch')).toHaveAttribute('aria-checked', 'true'); + expect(within(syncAlerts).getByText('On')).toBeInTheDocument(); }); it('it toggles the switch', async () => { @@ -45,9 +46,9 @@ describe('SyncAlertsToggle', () => { ); - const synAlerts = await screen.findByTestId('caseSyncAlerts'); + const syncAlerts = await screen.findByTestId('caseSyncAlerts'); - await userEvent.click(within(synAlerts).getByRole('switch')); + await userEvent.click(within(syncAlerts).getByRole('switch')); expect(await screen.findByRole('switch')).toHaveAttribute('aria-checked', 'false'); expect(await screen.findByText('Off')).toBeInTheDocument(); @@ -60,9 +61,9 @@ describe('SyncAlertsToggle', () => { ); - const synAlerts = await screen.findByTestId('caseSyncAlerts'); + const syncAlerts = await screen.findByTestId('caseSyncAlerts'); - await userEvent.click(within(synAlerts).getByRole('switch')); + await userEvent.click(within(syncAlerts).getByRole('switch')); await userEvent.click(await screen.findByText('Submit')); diff --git a/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx index 914993648e29..9b92baa30bb7 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/tags.test.tsx @@ -47,11 +47,14 @@ describe('Tags', () => { }; beforeEach(() => { - jest.clearAllMocks(); useGetTagsMock.mockReturnValue({ data: ['test'] }); appMockRender = createAppMockRenderer(); }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('it renders', async () => { appMockRender.render( diff --git a/x-pack/plugins/cases/public/components/case_form_fields/title.test.tsx b/x-pack/plugins/cases/public/components/case_form_fields/title.test.tsx index e277a992c6bd..e861b4a3babe 100644 --- a/x-pack/plugins/cases/public/components/case_form_fields/title.test.tsx +++ b/x-pack/plugins/cases/public/components/case_form_fields/title.test.tsx @@ -7,7 +7,7 @@ import type { FC, PropsWithChildren } from 'react'; import React from 'react'; -import { screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import type { FormHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; import type { CaseFormFieldsSchemaProps } from './schema'; @@ -17,11 +17,9 @@ import userEvent from '@testing-library/user-event'; import { Title } from './title'; import { schema } from '../create/schema'; -import { createAppMockRenderer, type AppMockRenderer } from '../../common/mock'; describe('Title', () => { let globalForm: FormHook; - let appMockRender: AppMockRenderer; const MockHookWrapperComponent: FC> = ({ children }) => { const { form } = useForm({ @@ -38,11 +36,10 @@ describe('Title', () => { beforeEach(() => { jest.resetAllMocks(); - appMockRender = createAppMockRenderer(); }); it('it renders', async () => { - appMockRender.render( + render( </MockHookWrapperComponent> @@ -52,7 +49,7 @@ describe('Title', () => { }); it('it disables the input when loading', async () => { - appMockRender.render( + render( <MockHookWrapperComponent> <Title isLoading={true} /> </MockHookWrapperComponent> @@ -61,7 +58,7 @@ describe('Title', () => { }); it('it changes the title', async () => { - appMockRender.render( + render( <MockHookWrapperComponent> <Title isLoading={false} /> </MockHookWrapperComponent> diff --git a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx index fe2deb74dfa1..7366acf6e051 100644 --- a/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx +++ b/x-pack/plugins/cases/public/components/case_view/components/case_view_alerts.test.tsx @@ -15,6 +15,7 @@ import type { CaseUI } from '../../../../common'; import { CaseViewAlerts } from './case_view_alerts'; import * as api from '../../../containers/api'; import type { FeatureIdsResponse } from '../../../containers/types'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; jest.mock('../../../containers/api'); @@ -54,7 +55,7 @@ describe('CaseUI View Page activity tab', () => { expect(getAlertsStateTableMock).toHaveBeenCalledWith({ alertsTableConfigurationRegistry: expect.anything(), configurationId: 'securitySolution-case', - featureIds: ['siem'], + ruleTypeIds: SECURITY_SOLUTION_RULE_TYPE_IDS, id: 'case-details-alerts-securitySolution', query: { ids: { @@ -88,7 +89,8 @@ describe('CaseUI View Page activity tab', () => { expect(getAlertsStateTableMock).toHaveBeenCalledWith({ alertsTableConfigurationRegistry: expect.anything(), configurationId: 'case-details-alerts-observability', - featureIds: ['observability'], + ruleTypeIds: ['log-threshold'], + consumers: ['observability'], id: 'case-details-alerts-observability', query: { ids: { 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 9570bee46b3f..6f8223b5305f 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 @@ -8,8 +8,8 @@ import React, { useMemo } from 'react'; import { EuiFlexItem, EuiFlexGroup, EuiProgress } from '@elastic/eui'; -import type { ValidFeatureId } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; import { SECURITY_SOLUTION_OWNER } from '../../../../common/constants'; import type { CaseUI } from '../../../../common'; import { useKibana } from '../../../common/lib/kibana'; @@ -49,14 +49,16 @@ export const CaseViewAlerts = ({ caseData, onAlertsTableLoaded }: CaseViewAlerts ) : ''; - const alertStateProps = useMemo( + const alertStateProps: AlertsTableStateProps = useMemo( () => ({ alertsTableConfigurationRegistry: triggersActionsUi.alertsTableConfigurationRegistry, configurationId: configId, id: `case-details-alerts-${caseData.owner}`, - featureIds: (caseData.owner === SECURITY_SOLUTION_OWNER - ? [AlertConsumers.SIEM] - : alertData?.featureIds ?? []) as ValidFeatureId[], + ruleTypeIds: + caseData.owner === SECURITY_SOLUTION_OWNER + ? SECURITY_SOLUTION_RULE_TYPE_IDS + : alertData?.ruleTypeIds ?? [], + consumers: alertData?.featureIds, query: alertIdsQuery, showAlertStatusWithFlapping: caseData.owner !== SECURITY_SOLUTION_OWNER, onLoaded: onAlertsTableLoaded, @@ -65,6 +67,7 @@ export const CaseViewAlerts = ({ caseData, onAlertsTableLoaded }: CaseViewAlerts triggersActionsUi.alertsTableConfigurationRegistry, configId, caseData.owner, + alertData?.ruleTypeIds, alertData?.featureIds, alertIdsQuery, onAlertsTableLoaded, diff --git a/x-pack/plugins/cases/public/components/cases_context/state/use_is_add_to_case_open.test.tsx b/x-pack/plugins/cases/public/components/cases_context/state/use_is_add_to_case_open.test.tsx index 9974d0cb530d..61cf35522966 100644 --- a/x-pack/plugins/cases/public/components/cases_context/state/use_is_add_to_case_open.test.tsx +++ b/x-pack/plugins/cases/public/components/cases_context/state/use_is_add_to_case_open.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useCasesAddToExistingCaseModal } from '../../all_cases/selector_modal/use_cases_add_to_existing_case_modal'; import { createAppMockRenderer } from '../../../common/mock'; import { useIsAddToCaseOpen } from './use_is_add_to_case_open'; @@ -26,9 +26,8 @@ describe('use is add to existing case modal open hook', () => { }); it('should throw if called outside of a cases context', () => { - const { result } = renderHook(useIsAddToCaseOpen); - expect(result.error?.message).toContain( - 'useCasesStateContext must be used within a CasesProvider and have a defined value' + expect(() => renderHook(useIsAddToCaseOpen)).toThrow( + /useCasesStateContext must be used within a CasesProvider and have a defined value/ ); }); diff --git a/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx b/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx index e2aed2c39783..1b7a7c2eba7d 100644 --- a/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx +++ b/x-pack/plugins/cases/public/components/category/category_form_field.test.tsx @@ -14,7 +14,8 @@ import { categories } from '../../containers/mock'; import { MAX_CATEGORY_LENGTH } from '../../../common/constants'; import { FormTestComponent } from '../../common/test_utils'; -describe('Category', () => { +// Failing: See https://github.com/elastic/kibana/issues/177791 +describe.skip('Category', () => { const onSubmit = jest.fn(); it('renders the category field correctly', async () => { diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx index f1cb277f1a24..b529139644d5 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/use_get_fields_by_issue_type.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import { connector } from '../mock'; @@ -30,7 +30,7 @@ describe('useGetFieldsByIssueType', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getFieldsByIssueType'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetFieldsByIssueType({ http, @@ -88,7 +88,7 @@ describe('useGetFieldsByIssueType', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetFieldsByIssueType({ http, @@ -114,7 +114,7 @@ describe('useGetFieldsByIssueType', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetFieldsByIssueType({ http, diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue.test.tsx index 876738025e6a..04f1995f6cc8 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import { connector as actionConnector } from '../mock'; @@ -30,7 +30,7 @@ describe('useGetIssue', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getIssue'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssue({ http, @@ -40,7 +40,7 @@ describe('useGetIssue', () => { { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isSuccess); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(spy).toHaveBeenCalledWith({ http, @@ -88,7 +88,7 @@ describe('useGetIssue', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssue({ http, @@ -98,9 +98,10 @@ describe('useGetIssue', () => { { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isError); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(result.current.isError).toBe(true); + expect(addError).toHaveBeenCalled(); + }); }); it('calls addError when the getIssue api returns successfully but contains an error', async () => { @@ -114,7 +115,7 @@ describe('useGetIssue', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssue({ http, @@ -124,8 +125,9 @@ describe('useGetIssue', () => { { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isSuccess); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx index 0d7e3127dd9f..dde59c2dd64b 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issue_types.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import { connector } from '../mock'; @@ -30,7 +30,7 @@ describe('useGetIssueTypes', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getIssueTypes'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssueTypes({ http, @@ -70,7 +70,7 @@ describe('useGetIssueTypes', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetIssueTypes({ http, @@ -95,7 +95,7 @@ describe('useGetIssueTypes', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetIssueTypes({ http, diff --git a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx index a06cd4391f76..b43a231e4eb0 100644 --- a/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/jira/use_get_issues.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import { connector as actionConnector } from '../mock'; @@ -30,7 +30,7 @@ describe('useGetIssues', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getIssues'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssues({ http, @@ -40,13 +40,14 @@ describe('useGetIssues', () => { { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isSuccess); - - expect(spy).toHaveBeenCalledWith({ - http, - signal: expect.anything(), - connectorId: actionConnector.id, - title: 'Task', + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + expect(spy).toHaveBeenCalledWith({ + http, + signal: expect.anything(), + connectorId: actionConnector.id, + title: 'Task', + }); }); }); @@ -74,7 +75,7 @@ describe('useGetIssues', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssues({ http, @@ -84,9 +85,10 @@ describe('useGetIssues', () => { { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isError); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(result.current.isError).toBe(true); + expect(addError).toHaveBeenCalled(); + }); }); it('calls addError when the getIssues api returns successfully but contains an error', async () => { @@ -100,7 +102,7 @@ describe('useGetIssues', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIssues({ http, @@ -110,8 +112,9 @@ describe('useGetIssues', () => { { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isSuccess); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(result.current.isSuccess).toBe(true); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx index 7bd0c16a6a4d..bfe20b4dc4de 100644 --- a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_incident_types.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import { connector } from '../mock'; @@ -30,7 +30,7 @@ describe('useGetIncidentTypes', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getIncidentTypes'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetIncidentTypes({ http, @@ -70,7 +70,7 @@ describe('useGetIncidentTypes', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetIncidentTypes({ http, @@ -95,7 +95,7 @@ describe('useGetIncidentTypes', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetIncidentTypes({ http, diff --git a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx index 6f59b4d50c31..71d09a0cc68e 100644 --- a/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/resilient/use_get_severity.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import { connector } from '../mock'; @@ -30,7 +30,7 @@ describe('useGetSeverity', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getSeverity'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useGetSeverity({ http, @@ -70,7 +70,7 @@ describe('useGetSeverity', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetSeverity({ http, @@ -95,7 +95,7 @@ describe('useGetSeverity', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetSeverity({ http, diff --git a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx b/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx index 150881761950..3f44f4c30f7c 100644 --- a/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx +++ b/x-pack/plugins/cases/public/components/connectors/servicenow/use_get_choices.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana, useToasts } from '../../../common/lib/kibana'; import type { ActionConnector } from '../../../../common/types/domain'; @@ -47,7 +47,7 @@ describe('useGetChoices', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getChoices'); - const { waitFor } = renderHook( + renderHook( () => useGetChoices({ http, @@ -92,7 +92,7 @@ describe('useGetChoices', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetChoices({ http, @@ -118,7 +118,7 @@ describe('useGetChoices', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess: jest.fn(), addError }); - const { waitFor } = renderHook( + renderHook( () => useGetChoices({ http, diff --git a/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx index 168cae0e478f..0d1ad5b8b65b 100644 --- a/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx +++ b/x-pack/plugins/cases/public/components/create/flyout/use_cases_add_to_new_case_flyout.test.tsx @@ -6,7 +6,7 @@ */ import { alertComment } from '../../../containers/mock'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { FC, PropsWithChildren } from 'react'; import React from 'react'; import { CasesContext } from '../../cases_context'; @@ -47,12 +47,11 @@ describe('use cases add to new case flyout hook', () => { }); it('should throw if called outside of a cases context', () => { - const { result } = renderHook(() => { - useCasesAddToNewCaseFlyout(); - }); - expect(result.error?.message).toContain( - 'useCasesContext must be used within a CasesProvider and have a defined value' - ); + expect(() => + renderHook(() => { + useCasesAddToNewCaseFlyout(); + }) + ).toThrow(/useCasesContext must be used within a CasesProvider and have a defined value/); }); it('should dispatch the open action when invoked without attachments', () => { diff --git a/x-pack/plugins/cases/public/components/create/use_cancel_creation_action.test.tsx b/x-pack/plugins/cases/public/components/create/use_cancel_creation_action.test.tsx index 4174d33c44d2..080009feb184 100644 --- a/x-pack/plugins/cases/public/components/create/use_cancel_creation_action.test.tsx +++ b/x-pack/plugins/cases/public/components/create/use_cancel_creation_action.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; import { useCancelCreationAction } from './use_cancel_creation_action'; diff --git a/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx b/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx index 2a8a515df01e..17bbcbfa045e 100644 --- a/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx +++ b/x-pack/plugins/cases/public/components/custom_fields/number/create.test.tsx @@ -12,7 +12,8 @@ import { FormTestComponent } from '../../../common/test_utils'; import { Create } from './create'; import { customFieldsConfigurationMock } from '../../../containers/mock'; -describe('Create ', () => { +// FLAKY: https://github.com/elastic/kibana/issues/202115 +describe.skip('Create ', () => { const onSubmit = jest.fn(); beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx b/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx index 49e18fb818cd..f5a502f49077 100644 --- a/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx +++ b/x-pack/plugins/cases/public/components/files/use_file_preview.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useFilePreview } from './use_file_preview'; diff --git a/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx b/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx index 0467bb7a2efe..a064667f93c0 100644 --- a/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx +++ b/x-pack/plugins/cases/public/components/files/use_files_table_columns.test.tsx @@ -9,7 +9,7 @@ import type { FilesTableColumnsProps } from './use_files_table_columns'; import { useFilesTableColumns } from './use_files_table_columns'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { basicCase } from '../../containers/mock'; describe('useFilesTableColumns', () => { diff --git a/x-pack/plugins/cases/public/components/filter_popover/index.test.tsx b/x-pack/plugins/cases/public/components/filter_popover/index.test.tsx index 77e5593671c7..351cc6e77a98 100644 --- a/x-pack/plugins/cases/public/components/filter_popover/index.test.tsx +++ b/x-pack/plugins/cases/public/components/filter_popover/index.test.tsx @@ -6,31 +6,22 @@ */ import React from 'react'; -import { waitForEuiPopoverOpen, screen } from '@elastic/eui/lib/test/rtl'; -import { waitFor } from '@testing-library/react'; +import { waitForEuiPopoverOpen } from '@elastic/eui/lib/test/rtl'; +import { render, waitFor, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; - -import type { AppMockRenderer } from '../../common/mock'; -import { createAppMockRenderer } from '../../common/mock'; - import { FilterPopover } from '.'; -describe('FilterPopover ', () => { - let appMockRender: AppMockRenderer; +// Failing: See https://github.com/elastic/kibana/issues/176679 +describe.skip('FilterPopover ', () => { const onSelectedOptionsChanged = jest.fn(); const tags: string[] = ['coke', 'pepsi']; beforeEach(() => { - appMockRender = createAppMockRenderer(); jest.clearAllMocks(); }); - afterEach(async () => { - await appMockRender.clearQueryCache(); - }); - it('renders button label correctly', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -43,7 +34,7 @@ describe('FilterPopover ', () => { }); it('renders empty label correctly', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -61,7 +52,7 @@ describe('FilterPopover ', () => { }); it('renders string type options correctly', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -79,7 +70,7 @@ describe('FilterPopover ', () => { }); it('should call onSelectionChange with selected option', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -100,7 +91,7 @@ describe('FilterPopover ', () => { }); it('should call onSelectionChange with empty array when option is deselected', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -126,7 +117,7 @@ describe('FilterPopover ', () => { const maxLengthLabel = `You have selected maximum number of ${maxLength} tags to filter`; it('should show message when maximum options are selected', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -152,7 +143,7 @@ describe('FilterPopover ', () => { }); it('should not show message when maximum length label is missing', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -176,7 +167,7 @@ describe('FilterPopover ', () => { }); it('should not show message and disable options when maximum length property is missing', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} @@ -198,7 +189,7 @@ describe('FilterPopover ', () => { }); it('should allow to select more options when maximum length property is missing', async () => { - appMockRender.render( + render( <FilterPopover buttonLabel={'Tags'} onSelectedOptionsChanged={onSelectedOptionsChanged} diff --git a/x-pack/plugins/cases/public/components/markdown_editor/use_markdown_session_storage.test.tsx b/x-pack/plugins/cases/public/components/markdown_editor/use_markdown_session_storage.test.tsx index e4ce68ed4523..06a92712f63d 100644 --- a/x-pack/plugins/cases/public/components/markdown_editor/use_markdown_session_storage.test.tsx +++ b/x-pack/plugins/cases/public/components/markdown_editor/use_markdown_session_storage.test.tsx @@ -5,11 +5,9 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { waitFor, renderHook, act } from '@testing-library/react'; import type { FieldHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import type { SessionStorageType } from './use_markdown_session_storage'; import { useMarkdownSessionStorage } from './use_markdown_session_storage'; -import { waitForComponentToUpdate } from '../../common/test_utils'; describe('useMarkdownSessionStorage', () => { const field = { @@ -45,7 +43,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should return hasConflicts as false', async () => { - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useMarkdownSessionStorage({ field, sessionKey, initialValue }) ); @@ -55,7 +53,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should return hasConflicts as false when sessionKey is empty', async () => { - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useMarkdownSessionStorage({ field, sessionKey: '', initialValue }) ); @@ -66,7 +64,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should update the session value with field value when it is first render', async () => { - const { waitFor } = renderHook<SessionStorageType, { hasConflicts: boolean }>( + renderHook( (props) => { return useMarkdownSessionStorage(props); }, @@ -86,7 +84,7 @@ describe('useMarkdownSessionStorage', () => { it('should set session storage when field has value and session key is not created yet', async () => { const specialCharsValue = '!{tooltip[Hello again](This is tooltip!)}'; - const { waitFor, result } = renderHook<SessionStorageType, { hasConflicts: boolean }>( + const { result } = renderHook( (props) => { return useMarkdownSessionStorage(props); }, @@ -101,8 +99,6 @@ describe('useMarkdownSessionStorage', () => { jest.advanceTimersByTime(1000); }); - await waitForComponentToUpdate(); - await waitFor(() => { expect(result.current.hasConflicts).toBe(false); expect(sessionStorage.getItem(sessionKey)).toBe(specialCharsValue); @@ -110,7 +106,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should update session value ', async () => { - const { result, rerender, waitFor } = renderHook<SessionStorageType, { hasConflicts: boolean }>( + const { result, rerender } = renderHook( (props) => { return useMarkdownSessionStorage(props); }, @@ -129,8 +125,6 @@ describe('useMarkdownSessionStorage', () => { jest.advanceTimersByTime(1000); }); - await waitForComponentToUpdate(); - await waitFor(() => { expect(result.current.hasConflicts).toBe(false); expect(sessionStorage.getItem(sessionKey)).toBe('new value'); @@ -138,7 +132,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should return has conflict true', async () => { - const { result, rerender, waitFor } = renderHook<SessionStorageType, { hasConflicts: boolean }>( + const { result, rerender } = renderHook( (props) => { return useMarkdownSessionStorage(props); }, @@ -162,7 +156,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should set field value if session already exists and it is a first render', async () => { - const { waitFor, result } = renderHook<SessionStorageType, { hasConflicts: boolean }>( + const { result } = renderHook( (props) => { return useMarkdownSessionStorage(props); }, @@ -171,8 +165,6 @@ describe('useMarkdownSessionStorage', () => { } ); - await waitForComponentToUpdate(); - await waitFor(() => { expect(field.setValue).toHaveBeenCalled(); }); @@ -181,8 +173,6 @@ describe('useMarkdownSessionStorage', () => { jest.advanceTimersByTime(1000); }); - await waitForComponentToUpdate(); - await waitFor(() => { expect(result.current.hasConflicts).toBe(false); expect(field.value).toBe(sessionStorage.getItem(sessionKey)); @@ -190,10 +180,7 @@ describe('useMarkdownSessionStorage', () => { }); it('should update existing session key if field value changed', async () => { - const { waitFor, rerender, result } = renderHook< - SessionStorageType, - { hasConflicts: boolean } - >( + const { rerender, result } = renderHook( (props) => { return useMarkdownSessionStorage(props); }, @@ -202,8 +189,6 @@ describe('useMarkdownSessionStorage', () => { } ); - await waitForComponentToUpdate(); - await waitFor(() => { expect(field.setValue).toHaveBeenCalled(); }); @@ -218,8 +203,6 @@ describe('useMarkdownSessionStorage', () => { jest.advanceTimersByTime(1000); }); - await waitForComponentToUpdate(); - await waitFor(() => { expect(result.current.hasConflicts).toBe(false); expect(sessionStorage.getItem(sessionKey)).toBe('new value'); diff --git a/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx b/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx index 9fabf39db0bc..e77e8313c696 100644 --- a/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx +++ b/x-pack/plugins/cases/public/components/system_actions/cases/cases_params.tsx @@ -8,7 +8,6 @@ import React, { memo, useCallback, useEffect, useMemo } from 'react'; import type { ActionParamsProps } from '@kbn/triggers-actions-ui-plugin/public/types'; -import type { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; import { EuiCheckbox, @@ -37,7 +36,7 @@ const DEFAULT_EMPTY_TEMPLATE_KEY = 'defaultEmptyTemplateKey'; export const CasesParamsFieldsComponent: React.FunctionComponent< ActionParamsProps<CasesActionParams> -> = ({ actionParams, editAction, errors, index, producerId, featureId }) => { +> = ({ actionParams, editAction, errors, index, producerId, featureId, ruleTypeId }) => { const { cloud, data: { dataViews: dataViewsService }, @@ -58,9 +57,7 @@ export const CasesParamsFieldsComponent: React.FunctionComponent< http, toasts, dataViewsService, - featureIds: producerId - ? [producerId as Exclude<ValidFeatureId, typeof AlertConsumers.SIEM>] - : [], + ruleTypeIds: ruleTypeId ? [ruleTypeId] : [], }); const { data: configurations, isLoading: isLoadingCaseConfiguration } = diff --git a/x-pack/plugins/cases/public/components/templates/index.test.tsx b/x-pack/plugins/cases/public/components/templates/index.test.tsx index 7fcb563a54dd..4cfa7a22750b 100644 --- a/x-pack/plugins/cases/public/components/templates/index.test.tsx +++ b/x-pack/plugins/cases/public/components/templates/index.test.tsx @@ -17,7 +17,8 @@ import { Templates } from '.'; import * as i18n from './translations'; import { templatesConfigurationMock } from '../../containers/mock'; -describe('Templates', () => { +// FLAKY: https://github.com/elastic/kibana/issues/196628 +describe.skip('Templates', () => { let appMockRender: AppMockRenderer; const props = { diff --git a/x-pack/plugins/cases/public/components/use_breadcrumbs/index.test.tsx b/x-pack/plugins/cases/public/components/use_breadcrumbs/index.test.tsx index 9f48783fde24..b494bd1d8183 100644 --- a/x-pack/plugins/cases/public/components/use_breadcrumbs/index.test.tsx +++ b/x-pack/plugins/cases/public/components/use_breadcrumbs/index.test.tsx @@ -7,7 +7,7 @@ import type { ReactNode } from 'react'; import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { TestProviders } from '../../common/mock'; import { useCasesBreadcrumbs, useCasesTitleBreadcrumbs } from '.'; import { CasesDeepLinkId } from '../../common/navigation'; diff --git a/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx b/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx index dcef6d26393a..56599299fd0a 100644 --- a/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx +++ b/x-pack/plugins/cases/public/components/use_create_case_modal/index.test.tsx @@ -6,10 +6,10 @@ */ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; + +import { renderHook, act } from '@testing-library/react'; import { useKibana } from '../../common/lib/kibana'; -import type { UseCreateCaseModalProps, UseCreateCaseModalReturnedValues } from '.'; import { useCreateCaseModal } from '.'; import { TestProviders } from '../../common/mock'; @@ -27,10 +27,7 @@ describe('useCreateCaseModal', () => { }); it('init', async () => { - const { result } = renderHook< - React.PropsWithChildren<UseCreateCaseModalProps>, - UseCreateCaseModalReturnedValues - >(() => useCreateCaseModal({ onCaseCreated }), { + const { result } = renderHook(() => useCreateCaseModal({ onCaseCreated }), { wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, }); @@ -38,10 +35,7 @@ describe('useCreateCaseModal', () => { }); it('opens the modal', async () => { - const { result } = renderHook< - React.PropsWithChildren<UseCreateCaseModalProps>, - UseCreateCaseModalReturnedValues - >(() => useCreateCaseModal({ onCaseCreated }), { + const { result } = renderHook(() => useCreateCaseModal({ onCaseCreated }), { wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, }); @@ -53,10 +47,7 @@ describe('useCreateCaseModal', () => { }); it('closes the modal', async () => { - const { result } = renderHook< - React.PropsWithChildren<UseCreateCaseModalProps>, - UseCreateCaseModalReturnedValues - >(() => useCreateCaseModal({ onCaseCreated }), { + const { result } = renderHook(() => useCreateCaseModal({ onCaseCreated }), { wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, }); @@ -69,10 +60,7 @@ describe('useCreateCaseModal', () => { }); it('returns a memoized value', async () => { - const { result, rerender } = renderHook< - React.PropsWithChildren<UseCreateCaseModalProps>, - UseCreateCaseModalReturnedValues - >(() => useCreateCaseModal({ onCaseCreated }), { + const { result, rerender } = renderHook(() => useCreateCaseModal({ onCaseCreated }), { wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, }); @@ -84,10 +72,7 @@ describe('useCreateCaseModal', () => { }); it('closes the modal when creating a case', async () => { - const { result } = renderHook< - React.PropsWithChildren<UseCreateCaseModalProps>, - UseCreateCaseModalReturnedValues - >(() => useCreateCaseModal({ onCaseCreated }), { + const { result } = renderHook(() => useCreateCaseModal({ onCaseCreated }), { wrapper: ({ children }) => <TestProviders>{children}</TestProviders>, }); diff --git a/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx b/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx index 75c2694f8947..02e1a99fd063 100644 --- a/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx +++ b/x-pack/plugins/cases/public/components/use_push_to_service/index.test.tsx @@ -6,9 +6,8 @@ */ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; -import type { ReturnUsePushToService, UsePushToService } from '.'; import { usePushToService } from '.'; import { noPushCasesPermissions, readCasesPermissions, TestProviders } from '../../common/mock'; import { usePostPushToService } from '../../containers/use_post_push_to_service'; @@ -67,10 +66,7 @@ describe('usePushToService', () => { }); it('calls pushCaseToExternalService with correct arguments', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -93,10 +89,7 @@ describe('usePushToService', () => { }, })); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -115,10 +108,7 @@ describe('usePushToService', () => { }, })); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -129,10 +119,7 @@ describe('usePushToService', () => { }); it('Displays message when user has select none as connector', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -155,10 +142,7 @@ describe('usePushToService', () => { }); it('Displays message when connector is deleted', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -182,10 +166,7 @@ describe('usePushToService', () => { }); it('should not call pushCaseToExternalService when the selected connector is none', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -209,10 +190,7 @@ describe('usePushToService', () => { }); it('refresh case view page after push', async () => { - const { result, waitFor } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -227,10 +205,7 @@ describe('usePushToService', () => { describe('user does not have write or push permissions', () => { it('returns correct information about push permissions', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => ( <TestProviders permissions={noPushCasesPermissions()}> {children}</TestProviders> ), @@ -248,10 +223,7 @@ describe('usePushToService', () => { }, })); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => ( <TestProviders permissions={readCasesPermissions()}> {children}</TestProviders> ), @@ -270,10 +242,7 @@ describe('usePushToService', () => { }, })); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => ( <TestProviders permissions={readCasesPermissions()}> {children}</TestProviders> ), @@ -284,10 +253,7 @@ describe('usePushToService', () => { }); it('does not display a message when user does not have any connector configured', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -310,10 +276,7 @@ describe('usePushToService', () => { }); it('does not display a message when user does have a connector but is configured to none', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -336,10 +299,7 @@ describe('usePushToService', () => { }); it('does not display a message when connector is deleted', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -363,10 +323,7 @@ describe('usePushToService', () => { }); it('does not display a message when case is closed', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -386,10 +343,7 @@ describe('usePushToService', () => { describe('returned values', () => { it('initial', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -408,10 +362,7 @@ describe('usePushToService', () => { it('isLoading is true when usePostPushToService is loading', async () => { usePostPushToServiceMock.mockReturnValue({ ...mockPostPush, isLoading: true }); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -424,10 +375,7 @@ describe('usePushToService', () => { data: actionLicense, }); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -435,21 +383,18 @@ describe('usePushToService', () => { }); it('hasErrorMessages=true if there are error messages', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService({ ...defaultArgs, isValidConnector: false }), { - wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, - }); + const { result } = renderHook( + () => usePushToService({ ...defaultArgs, isValidConnector: false }), + { + wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, + } + ); expect(result.current.hasErrorMessages).toBe(true); }); it('needsToBePushed=true if the connector needs to be pushed', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -473,10 +418,7 @@ describe('usePushToService', () => { }); it('needsToBePushed=false if the connector does not exist', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -497,10 +439,7 @@ describe('usePushToService', () => { }); it('hasBeenPushed=false if the connector has been pushed', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -524,10 +463,7 @@ describe('usePushToService', () => { }); it('hasBeenPushed=false if the connector does not exist', async () => { - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >( + const { result } = renderHook( () => usePushToService({ ...defaultArgs, @@ -553,10 +489,7 @@ describe('usePushToService', () => { data: actionLicense, }); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => ( <TestProviders permissions={noPushCasesPermissions()}> {children}</TestProviders> ), @@ -574,10 +507,7 @@ describe('usePushToService', () => { }, })); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); @@ -590,10 +520,7 @@ describe('usePushToService', () => { data: undefined, })); - const { result } = renderHook< - React.PropsWithChildren<UsePushToService>, - ReturnUsePushToService - >(() => usePushToService(defaultArgs), { + const { result } = renderHook(() => usePushToService(defaultArgs), { wrapper: ({ children }) => <TestProviders> {children}</TestProviders>, }); diff --git a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.test.tsx b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.test.tsx index 0a31b0cb875a..0f485845fcd3 100644 --- a/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/comment/registered_attachments.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { screen } from '@testing-library/react'; +import { render, screen } from '@testing-library/react'; import type { AttachmentType, @@ -16,8 +16,6 @@ import { AttachmentActionType } from '../../../client/attachment_framework/types import { AttachmentTypeRegistry } from '../../../../common/registry'; import { getMockBuilderArgs } from '../mock'; import { createRegisteredAttachmentUserActionBuilder } from './registered_attachments'; -import type { AppMockRenderer } from '../../../common/mock'; -import { createAppMockRenderer } from '../../../common/mock'; const getLazyComponent = () => React.lazy(() => { @@ -32,8 +30,6 @@ const getLazyComponent = () => }); describe('createRegisteredAttachmentUserActionBuilder', () => { - let appMockRender: AppMockRenderer; - const attachmentTypeId = 'test'; const builderArgs = getMockBuilderArgs(); const registry = new AttachmentTypeRegistry<AttachmentType<CommonAttachmentViewProps>>( @@ -77,7 +73,6 @@ describe('createRegisteredAttachmentUserActionBuilder', () => { }; beforeEach(() => { - appMockRender = createAppMockRenderer(); jest.clearAllMocks(); }); @@ -161,8 +156,7 @@ describe('createRegisteredAttachmentUserActionBuilder', () => { const userAction = createRegisteredAttachmentUserActionBuilder(userActionBuilderArgs).build()[0]; - // @ts-expect-error: children is a proper React element - appMockRender.render(userAction.children); + render(userAction.children); expect(await screen.findByText('My component')).toBeInTheDocument(); }); diff --git a/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.tsx b/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.tsx index 2db865ee3b22..dba35699e2d8 100644 --- a/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/property_actions/use_delete_property_action.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import type { AppMockRenderer } from '../../../common/mock'; import { createAppMockRenderer } from '../../../common/mock'; import { useDeletePropertyAction } from './use_delete_property_action'; diff --git a/x-pack/plugins/cases/public/components/user_actions/show_more_button.test.tsx b/x-pack/plugins/cases/public/components/user_actions/show_more_button.test.tsx index 34a0ad271337..515cc5085f28 100644 --- a/x-pack/plugins/cases/public/components/user_actions/show_more_button.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/show_more_button.test.tsx @@ -6,31 +6,25 @@ */ import React from 'react'; -import { screen } from '@testing-library/react'; +import { screen, render } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { ShowMoreButton } from './show_more_button'; -import type { AppMockRenderer } from '../../common/mock'; -import { createAppMockRenderer } from '../../common/mock'; const showMoreClickMock = jest.fn(); -// FLAKY: https://github.com/elastic/kibana/issues/192672 -describe.skip('ShowMoreButton', () => { - let appMockRender: AppMockRenderer; - +describe('ShowMoreButton', () => { beforeEach(() => { jest.clearAllMocks(); - appMockRender = createAppMockRenderer(); }); it('renders correctly', () => { - appMockRender.render(<ShowMoreButton onShowMoreClick={showMoreClickMock} />); + render(<ShowMoreButton onShowMoreClick={showMoreClickMock} />); expect(screen.getByTestId('cases-show-more-user-actions')).toBeInTheDocument(); }); it('shows loading state and is disabled when isLoading is true', () => { - appMockRender.render(<ShowMoreButton onShowMoreClick={showMoreClickMock} isLoading={true} />); + render(<ShowMoreButton onShowMoreClick={showMoreClickMock} isLoading={true} />); const btn = screen.getByTestId('cases-show-more-user-actions'); @@ -40,7 +34,7 @@ describe.skip('ShowMoreButton', () => { }); it('calls onShowMoreClick on button click', async () => { - appMockRender.render(<ShowMoreButton onShowMoreClick={showMoreClickMock} />); + render(<ShowMoreButton onShowMoreClick={showMoreClickMock} />); await userEvent.click(screen.getByTestId('cases-show-more-user-actions')); expect(showMoreClickMock).toHaveBeenCalled(); diff --git a/x-pack/plugins/cases/public/components/user_actions/use_last_page.test.tsx b/x-pack/plugins/cases/public/components/user_actions/use_last_page.test.tsx index 525fe19771e4..a05097e7f7b2 100644 --- a/x-pack/plugins/cases/public/components/user_actions/use_last_page.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/use_last_page.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useLastPage } from './use_last_page'; import type { UserActivityParams } from '../user_actions_activity_bar/types'; diff --git a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx index 3600a247540f..4acd8ce0ee10 100644 --- a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_handler.test.tsx @@ -7,7 +7,7 @@ import type { FC, PropsWithChildren } from 'react'; import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { basicCase } from '../../containers/mock'; import { useUpdateComment } from '../../containers/use_update_comment'; diff --git a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_last_page.test.tsx b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_last_page.test.tsx index 3207e4ffb13f..ec50c60bb559 100644 --- a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_last_page.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_last_page.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useLastPageUserActions } from './use_user_actions_last_page'; import type { UserActivityParams } from '../user_actions_activity_bar/types'; @@ -32,7 +32,7 @@ describe('useLastPageUserActions', () => { }); it('renders correctly', async () => { - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useLastPageUserActions({ lastPage: 5, userActivityQueryParams, @@ -79,7 +79,7 @@ describe('useLastPageUserActions', () => { it('returns loading state correctly', async () => { useFindCaseUserActionsMock.mockReturnValue({ isLoading: true }); - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useLastPageUserActions({ lastPage: 2, userActivityQueryParams, @@ -108,7 +108,7 @@ describe('useLastPageUserActions', () => { it('returns empty array when data is undefined', async () => { useFindCaseUserActionsMock.mockReturnValue({ isLoading: false, data: undefined }); - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useLastPageUserActions({ lastPage: 2, userActivityQueryParams, diff --git a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_pagination.test.tsx b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_pagination.test.tsx index 0d005a8b404f..21702583e029 100644 --- a/x-pack/plugins/cases/public/components/user_actions/use_user_actions_pagination.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/use_user_actions_pagination.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useUserActionsPagination } from './use_user_actions_pagination'; import type { UserActivityParams } from '../user_actions_activity_bar/types'; @@ -32,7 +32,7 @@ describe('useUserActionsPagination', () => { }); it('renders expandable option correctly when user actions are more than 10', async () => { - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useUserActionsPagination({ userActivityQueryParams, caseId: basicCase.id, @@ -62,7 +62,7 @@ describe('useUserActionsPagination', () => { }); it('renders less than 10 user actions correctly', async () => { - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useUserActionsPagination({ userActivityQueryParams, caseId: basicCase.id, @@ -92,7 +92,7 @@ describe('useUserActionsPagination', () => { it('returns loading state correctly', async () => { useInfiniteFindCaseUserActionsMock.mockReturnValue({ isLoading: true }); - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useUserActionsPagination({ userActivityQueryParams, caseId: basicCase.id, @@ -124,7 +124,7 @@ describe('useUserActionsPagination', () => { it('returns empty array when data is undefined', async () => { useInfiniteFindCaseUserActionsMock.mockReturnValue({ isLoading: false, data: undefined }); - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useUserActionsPagination({ userActivityQueryParams, caseId: basicCase.id, @@ -161,7 +161,7 @@ describe('useUserActionsPagination', () => { }, }); - const { result, waitFor } = renderHook(() => + const { result } = renderHook(() => useUserActionsPagination({ userActivityQueryParams, caseId: basicCase.id, diff --git a/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx b/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx index d09ebc9d747a..d2874ad20246 100644 --- a/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx +++ b/x-pack/plugins/cases/public/components/user_actions/user_actions_list.test.tsx @@ -31,7 +31,8 @@ const defaultProps = { jest.mock('../../common/lib/kibana'); -describe(`UserActionsList`, () => { +// FLAKY: https://github.com/elastic/kibana/issues/176524 +describe.skip(`UserActionsList`, () => { let appMockRender: AppMockRenderer; beforeEach(() => { diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/is_compatible.ts b/x-pack/plugins/cases/public/components/visualizations/actions/is_compatible.ts index 64becf44e266..90347cb8d406 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/is_compatible.ts +++ b/x-pack/plugins/cases/public/components/visualizations/actions/is_compatible.ts @@ -7,7 +7,7 @@ import type { CoreStart } from '@kbn/core-lifecycle-browser'; import { isLensApi } from '@kbn/lens-plugin/public'; -import { hasBlockingError } from '@kbn/presentation-publishing'; +import { apiPublishesTimeRange, hasBlockingError } from '@kbn/presentation-publishing'; import { canUseCases } from '../../../client/helpers/can_use_cases'; import { getCaseOwnerByAppId } from '../../../../common/utils/owner'; @@ -20,7 +20,11 @@ export function isCompatible( if (!embeddable.getFullAttributes()) { return false; } - const timeRange = embeddable.timeRange$?.value ?? embeddable.parentApi?.timeRange$?.value; + const timeRange = + embeddable.timeRange$?.value ?? + (embeddable.parentApi && apiPublishesTimeRange(embeddable.parentApi) + ? embeddable.parentApi?.timeRange$?.value + : undefined); if (!timeRange) { return false; } diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts b/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts index dea0c1ace09a..94c7e5a1c939 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts +++ b/x-pack/plugins/cases/public/components/visualizations/actions/mocks.ts @@ -7,11 +7,11 @@ import { createBrowserHistory } from 'history'; import { BehaviorSubject } from 'rxjs'; - +import { getLensApiMock } from '@kbn/lens-plugin/public/react_embeddable/mocks'; import type { PublicAppInfo } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import type { LensApi, LensSavedObjectAttributes } from '@kbn/lens-plugin/public'; -import type { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; +import type { TimeRange } from '@kbn/es-query'; import type { Services } from './types'; const coreStart = coreMock.createStart(); @@ -39,24 +39,16 @@ export const mockLensAttributes = { export const getMockLensApi = ( { from, to = 'now' }: { from: string; to: string } = { from: 'now-24h', to: 'now' } ): LensApi => - ({ - type: 'lens', - getSavedVis: () => {}, - canViewUnderlyingData$: new BehaviorSubject(true), - getViewUnderlyingDataArgs: () => {}, + getLensApiMock({ getFullAttributes: () => { return mockLensAttributes; }, - panelTitle: new BehaviorSubject('myPanel'), - hidePanelTitle: new BehaviorSubject(false), - timeslice$: new BehaviorSubject<[number, number] | undefined>(undefined), + panelTitle: new BehaviorSubject<string | undefined>('myPanel'), timeRange$: new BehaviorSubject<TimeRange | undefined>({ from, to, }), - filters$: new BehaviorSubject<Filter[] | undefined>(undefined), - query$: new BehaviorSubject<Query | AggregateQuery | undefined>(undefined), - } as unknown as LensApi); + }); export const getMockCurrentAppId$ = () => new BehaviorSubject<string>('securitySolutionUI'); export const getMockApplications$ = () => diff --git a/x-pack/plugins/cases/public/components/visualizations/actions/open_modal.tsx b/x-pack/plugins/cases/public/components/visualizations/actions/open_modal.tsx index 0542a13b1ef2..c781098b44b5 100644 --- a/x-pack/plugins/cases/public/components/visualizations/actions/open_modal.tsx +++ b/x-pack/plugins/cases/public/components/visualizations/actions/open_modal.tsx @@ -9,7 +9,7 @@ import React, { useEffect, useMemo } from 'react'; import { unmountComponentAtNode } from 'react-dom'; import type { LensApi } from '@kbn/lens-plugin/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; -import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; +import { apiPublishesTimeRange, useStateFromPublishingSubject } from '@kbn/presentation-publishing'; import { ActionWrapper } from './action_wrapper'; import type { CasesActionContextProps, Services } from './types'; import type { CaseUI } from '../../../../common'; @@ -30,7 +30,9 @@ const AddExistingCaseModalWrapper: React.FC<Props> = ({ lensApi, onClose, onSucc }); const timeRange = useStateFromPublishingSubject(lensApi.timeRange$); - const parentTimeRange = useStateFromPublishingSubject(lensApi.parentApi?.timeRange$); + const parentTimeRange = useStateFromPublishingSubject( + apiPublishesTimeRange(lensApi.parentApi) ? lensApi.parentApi?.timeRange$ : undefined + ); const absoluteTimeRange = convertToAbsoluteTimeRange(timeRange); const absoluteParentTimeRange = convertToAbsoluteTimeRange(parentTimeRange); diff --git a/x-pack/plugins/cases/public/containers/__mocks__/api.ts b/x-pack/plugins/cases/public/containers/__mocks__/api.ts index a24c8b5b677c..2e792fbd134c 100644 --- a/x-pack/plugins/cases/public/containers/__mocks__/api.ts +++ b/x-pack/plugins/cases/public/containers/__mocks__/api.ts @@ -10,7 +10,6 @@ import type { CasesFindResponseUI, CaseUI, CasesUI, - CasesStatus, FetchCasesProps, FindCaseUserActions, CaseUICustomField, @@ -24,7 +23,6 @@ import { basicCaseCommentPatch, basicCasePost, basicResolvedCase, - casesStatus, pushedCase, tags, categories, @@ -69,9 +67,6 @@ export const getSingleCaseMetrics = async ( signal: AbortSignal ): Promise<SingleCaseMetricsResponse> => Promise.resolve(basicCaseMetrics); -export const getCasesStatus = async (signal: AbortSignal): Promise<CasesStatus> => - Promise.resolve(casesStatus); - export const getTags = async (signal: AbortSignal): Promise<string[]> => Promise.resolve(tags); export const findAssignees = async (): Promise<UserProfile[]> => userProfiles; diff --git a/x-pack/plugins/cases/public/containers/api.test.tsx b/x-pack/plugins/cases/public/containers/api.test.tsx index 02d639b79088..d72eece49e1e 100644 --- a/x-pack/plugins/cases/public/containers/api.test.tsx +++ b/x-pack/plugins/cases/public/containers/api.test.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import { httpServiceMock } from '@kbn/core/public/mocks'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; import { KibanaServices } from '../common/lib/kibana'; @@ -51,13 +50,11 @@ import { basicCaseSnake, pushedCaseSnake, categories, - casesStatus, casesSnake, cases, pushedCase, tags, findCaseUserActionsResponse, - casesStatusSnake, basicCaseId, caseWithRegisteredAttachmentsSnake, caseWithRegisteredAttachments, @@ -69,7 +66,6 @@ import { } from './mock'; import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './constants'; -import { getCasesStatus } from '../api'; import { getCaseConnectorsMockResponse } from '../common/mock/connectors'; import { set } from '@kbn/safer-lodash-set'; import { cloneDeep, omit } from 'lodash'; @@ -531,38 +527,6 @@ describe('Cases API', () => { }); }); - describe('getCasesStatus', () => { - const http = httpServiceMock.createStartContract({ basePath: '' }); - http.get.mockResolvedValue(casesStatusSnake); - - beforeEach(() => { - fetchMock.mockClear(); - }); - - it('should be called with correct check url, method, signal', async () => { - await getCasesStatus({ - http, - signal: abortCtrl.signal, - query: { owner: [SECURITY_SOLUTION_OWNER] }, - }); - - expect(http.get).toHaveBeenCalledWith(`${CASES_URL}/status`, { - signal: abortCtrl.signal, - query: { owner: [SECURITY_SOLUTION_OWNER] }, - }); - }); - - it('should return correct response', async () => { - const resp = await getCasesStatus({ - http, - signal: abortCtrl.signal, - query: { owner: SECURITY_SOLUTION_OWNER }, - }); - - expect(resp).toEqual(casesStatus); - }); - }); - describe('findCaseUserActions', () => { const findCaseUserActionsSnake = { page: 1, diff --git a/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx index 5718b07438a9..99d79484b17c 100644 --- a/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx +++ b/x-pack/plugins/cases/public/containers/configure/use_action_types.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; @@ -43,10 +43,10 @@ describe('useActionTypes', () => { (useToasts as jest.Mock).mockReturnValue({ addError: addErrorMock }); - const { waitForNextUpdate } = renderHook(() => useGetActionTypes(), { + renderHook(() => useGetActionTypes(), { wrapper: appMockRenderer.AppWrapper, }); - await waitForNextUpdate({ timeout: 2000 }); - expect(addErrorMock).toHaveBeenCalled(); + + await waitFor(() => expect(addErrorMock).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/configure/use_get_all_case_configurations.test.ts b/x-pack/plugins/cases/public/containers/configure/use_get_all_case_configurations.test.ts index cd9e44d1bdaa..52d4df20e540 100644 --- a/x-pack/plugins/cases/public/containers/configure/use_get_all_case_configurations.test.ts +++ b/x-pack/plugins/cases/public/containers/configure/use_get_all_case_configurations.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useGetAllCaseConfigurations } from './use_get_all_case_configurations'; import * as api from './api'; import type { AppMockRenderer } from '../../common/mock'; @@ -32,18 +32,11 @@ describe('Use get all case configurations hook', () => { { id: 'my-configuration-3', owner: '3' }, ]); - const { result, waitForNextUpdate } = renderHook(() => useGetAllCaseConfigurations(), { + const { result } = renderHook(() => useGetAllCaseConfigurations(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - /** - * Ensures that the initial data is returned≠ - * before fetching - */ - // @ts-expect-error: data is defined - expect(result.all[0].data).toEqual([ + expect(result.current.data).toEqual([ { closureType: 'close-by-user', connector: { fields: null, id: 'none', name: 'none', type: '.none' }, @@ -56,43 +49,36 @@ describe('Use get all case configurations hook', () => { }, ]); - /** - * The response after fetching - */ - // @ts-expect-error: data is defined - expect(result.all[1].data).toEqual([ - { id: 'my-configuration-1', owner: '1' }, - { id: 'my-configuration-2', owner: '2' }, - { id: 'my-configuration-3', owner: '3' }, - ]); + await waitFor(() => + expect(result.current.data).toEqual([ + { id: 'my-configuration-1', owner: '1' }, + { id: 'my-configuration-2', owner: '2' }, + { id: 'my-configuration-3', owner: '3' }, + ]) + ); }); it('returns the initial configuration if none is available', async () => { const spy = jest.spyOn(api, 'getCaseConfigure'); spy.mockResolvedValue([]); - const { result, waitForNextUpdate } = renderHook(() => useGetAllCaseConfigurations(), { + const { result } = renderHook(() => useGetAllCaseConfigurations(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - /** - * Ensures that the initial data is returned≠ - * before fetching - */ - // @ts-expect-error: data is defined - expect(result.all[0].data).toEqual([ - { - closureType: 'close-by-user', - connector: { fields: null, id: 'none', name: 'none', type: '.none' }, - customFields: [], - templates: [], - id: '', - mappings: [], - version: '', - owner: '', - }, - ]); + await waitFor(() => + expect(result.current.data).toEqual([ + { + closureType: 'close-by-user', + connector: { fields: null, id: 'none', name: 'none', type: '.none' }, + customFields: [], + templates: [], + id: '', + mappings: [], + version: '', + owner: '', + }, + ]) + ); }); }); diff --git a/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx index e504bd22e9cc..35faebd12a78 100644 --- a/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx +++ b/x-pack/plugins/cases/public/containers/configure/use_get_case_configuration.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useGetCaseConfiguration } from './use_get_case_configuration'; import * as api from './api'; import type { AppMockRenderer } from '../../common/mock'; @@ -35,16 +35,14 @@ describe('Use get case configuration hook', () => { targetConfiguration, ]); - const { result, waitForNextUpdate } = renderHook(() => useGetCaseConfiguration(), { + const { result } = renderHook(() => useGetCaseConfiguration(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - /** * The response after fetching */ - expect(result.current.data).toEqual(targetConfiguration); + await waitFor(() => expect(result.current.data).toEqual(targetConfiguration)); }); it('returns the initial configuration if none matches the owner', async () => { @@ -59,16 +57,14 @@ describe('Use get case configuration hook', () => { { ...initialConfiguration, id: 'my-new-configuration-2', owner: 'bar' }, ]); - const { result, waitForNextUpdate } = renderHook(() => useGetCaseConfiguration(), { + const { result } = renderHook(() => useGetCaseConfiguration(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - /** * The response after fetching */ - expect(result.current.data).toEqual(initialConfiguration); + await waitFor(() => expect(result.current.data).toEqual(initialConfiguration)); }); it('returns the initial configuration if none exists', async () => { @@ -76,16 +72,14 @@ describe('Use get case configuration hook', () => { spy.mockResolvedValue([]); - const { result, waitForNextUpdate } = renderHook(() => useGetCaseConfiguration(), { + const { result } = renderHook(() => useGetCaseConfiguration(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - /** * The response after fetching */ - expect(result.current.data).toEqual(initialConfiguration); + await waitFor(() => expect(result.current.data).toEqual(initialConfiguration)); }); it('returns the initial configuration if the owner is undefined', async () => { @@ -94,15 +88,13 @@ describe('Use get case configuration hook', () => { spy.mockResolvedValue([]); - const { result, waitForNextUpdate } = renderHook(() => useGetCaseConfiguration(), { + const { result } = renderHook(() => useGetCaseConfiguration(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - /** * The response after fetching */ - expect(result.current.data).toEqual(initialConfiguration); + await waitFor(() => expect(result.current.data).toEqual(initialConfiguration)); }); }); diff --git a/x-pack/plugins/cases/public/containers/configure/use_get_case_configurations_query.test.ts b/x-pack/plugins/cases/public/containers/configure/use_get_case_configurations_query.test.ts index adc06ad840d9..02cb83442144 100644 --- a/x-pack/plugins/cases/public/containers/configure/use_get_case_configurations_query.test.ts +++ b/x-pack/plugins/cases/public/containers/configure/use_get_case_configurations_query.test.ts @@ -5,10 +5,9 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; import { useGetCaseConfigurationsQuery } from './use_get_case_configurations_query'; import * as api from './api'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { useToasts } from '../../common/lib/kibana'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; diff --git a/x-pack/plugins/cases/public/containers/configure/use_get_supported_action_connectors.tsx.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_get_supported_action_connectors.tsx.test.tsx index a81d6ac46d18..c9dad2340f2b 100644 --- a/x-pack/plugins/cases/public/containers/configure/use_get_supported_action_connectors.tsx.test.tsx +++ b/x-pack/plugins/cases/public/containers/configure/use_get_supported_action_connectors.tsx.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import { noConnectorsCasePermission, TestProviders } from '../../common/mock'; import { useApplicationCapabilities, useToasts } from '../../common/lib/kibana'; @@ -26,15 +26,13 @@ describe('useConnectors', () => { it('fetches connectors', async () => { const spy = jest.spyOn(api, 'getSupportedActionConnectors'); - const { waitForNextUpdate } = renderHook(() => useGetSupportedActionConnectors(), { + renderHook(() => useGetSupportedActionConnectors(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ signal: expect.any(AbortSignal) }); + await waitFor(() => expect(spy).toHaveBeenCalledWith({ signal: expect.any(AbortSignal) })); }); it('shows a toast error when the API returns error', async () => { @@ -46,45 +44,44 @@ describe('useConnectors', () => { throw new Error('Something went wrong'); }); - const { waitForNextUpdate } = renderHook(() => useGetSupportedActionConnectors(), { + renderHook(() => useGetSupportedActionConnectors(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); it('does not fetch connectors when the user does not has access to actions', async () => { const spyOnFetchConnectors = jest.spyOn(api, 'getSupportedActionConnectors'); useApplicationCapabilitiesMock().actions = { crud: false, read: false }; - const { result, waitForNextUpdate } = renderHook(() => useGetSupportedActionConnectors(), { + const { result } = renderHook(() => useGetSupportedActionConnectors(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - - expect(spyOnFetchConnectors).not.toHaveBeenCalled(); - expect(result.current.data).toEqual([]); + await waitFor(() => { + expect(spyOnFetchConnectors).not.toHaveBeenCalled(); + expect(result.current.data).toEqual([]); + }); }); it('does not fetch connectors when the user does not has access to connectors', async () => { const spyOnFetchConnectors = jest.spyOn(api, 'getSupportedActionConnectors'); useApplicationCapabilitiesMock().actions = { crud: true, read: true }; - const { result, waitForNextUpdate } = renderHook(() => useGetSupportedActionConnectors(), { + const { result } = renderHook(() => useGetSupportedActionConnectors(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders permissions={noConnectorsCasePermission()}>{children}</TestProviders> ), }); - await waitForNextUpdate(); - - expect(spyOnFetchConnectors).not.toHaveBeenCalled(); - expect(result.current.data).toEqual([]); + await waitFor(() => { + expect(spyOnFetchConnectors).not.toHaveBeenCalled(); + expect(result.current.data).toEqual([]); + }); }); }); diff --git a/x-pack/plugins/cases/public/containers/configure/use_persist_configuration.test.tsx b/x-pack/plugins/cases/public/containers/configure/use_persist_configuration.test.tsx index 4fab35fd5ce5..04b266478f66 100644 --- a/x-pack/plugins/cases/public/containers/configure/use_persist_configuration.test.tsx +++ b/x-pack/plugins/cases/public/containers/configure/use_persist_configuration.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { usePersistConfiguration } from './use_persist_configuration'; import * as api from './api'; @@ -55,7 +55,7 @@ describe('usePersistConfiguration', () => { const spyPost = jest.spyOn(api, 'postCaseConfigure'); const spyPatch = jest.spyOn(api, 'patchCaseConfigure'); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -80,7 +80,7 @@ describe('usePersistConfiguration', () => { const spyPost = jest.spyOn(api, 'postCaseConfigure'); const spyPatch = jest.spyOn(api, 'patchCaseConfigure'); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -104,7 +104,7 @@ describe('usePersistConfiguration', () => { it('calls postCaseConfigure with correct data', async () => { const spyPost = jest.spyOn(api, 'postCaseConfigure'); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -133,7 +133,7 @@ describe('usePersistConfiguration', () => { const spyPost = jest.spyOn(api, 'postCaseConfigure'); const spyPatch = jest.spyOn(api, 'patchCaseConfigure'); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -157,7 +157,7 @@ describe('usePersistConfiguration', () => { it('calls patchCaseConfigure with correct data', async () => { const spyPatch = jest.spyOn(api, 'patchCaseConfigure'); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -184,7 +184,7 @@ describe('usePersistConfiguration', () => { it('invalidates the queries correctly', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -198,7 +198,7 @@ describe('usePersistConfiguration', () => { }); it('shows the success toaster', async () => { - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); @@ -216,7 +216,7 @@ describe('usePersistConfiguration', () => { .spyOn(api, 'postCaseConfigure') .mockRejectedValue(new Error('useCreateAttachments: Test error')); - const { waitFor, result } = renderHook(() => usePersistConfiguration(), { + const { result } = renderHook(() => usePersistConfiguration(), { wrapper: appMockRender.AppWrapper, }); diff --git a/x-pack/plugins/cases/public/containers/mock.ts b/x-pack/plugins/cases/public/containers/mock.ts index c3cee2d60d2b..1ed160cf1847 100644 --- a/x-pack/plugins/cases/public/containers/mock.ts +++ b/x-pack/plugins/cases/public/containers/mock.ts @@ -27,7 +27,7 @@ import { ExternalReferenceStorageType, CustomFieldTypes, } from '../../common/types/domain'; -import type { ActionLicense, CaseUI, CasesStatus, UserActionUI } from './types'; +import type { ActionLicense, CaseUI, UserActionUI } from './types'; import type { ResolvedCase, @@ -56,11 +56,7 @@ import type { AttachmentViewObject, PersistableStateAttachmentType, } from '../client/attachment_framework/types'; -import type { - CasesFindResponse, - CasesStatusResponse, - UserActionWithResponse, -} from '../../common/types/api'; +import type { CasesFindResponse, UserActionWithResponse } from '../../common/types/api'; export { connectorsMock } from '../common/mock/connectors'; export const basicCaseId = 'basic-case-id'; @@ -398,14 +394,13 @@ export const basicCaseCommentPatch = { comments: [basicCommentPatch], }; -export const casesStatus: CasesStatus = { - countOpenCases: 20, - countInProgressCases: 40, - countClosedCases: 130, -}; - export const casesMetrics: CasesMetrics = { mttr: 12, + status: { + open: 20, + inProgress: 40, + closed: 130, + }, }; export const basicPush = { @@ -461,7 +456,9 @@ export const allCases: CasesFindResponseUI = { page: 1, perPage: 5, total: 10, - ...casesStatus, + countOpenCases: 20, + countInProgressCases: 40, + countClosedCases: 130, }; export const actionLicenses: ActionLicense[] = [ @@ -572,12 +569,6 @@ export const caseWithRegisteredAttachmentsSnake = { comments: [externalReferenceAttachmentSnake, persistableStateAttachmentSnake], }; -export const casesStatusSnake: CasesStatusResponse = { - count_closed_cases: 130, - count_in_progress_cases: 40, - count_open_cases: 20, -}; - export const pushSnake = { connector_id: pushConnectorId, connector_name: 'My SN connector', @@ -626,7 +617,9 @@ export const allCasesSnake: CasesFindResponse = { page: 1, per_page: 5, total: 10, - ...casesStatusSnake, + count_closed_cases: 130, + count_in_progress_cases: 40, + count_open_cases: 20, }; export const getUserAction = ( diff --git a/x-pack/plugins/cases/public/containers/use_bulk_update_case.test.tsx b/x-pack/plugins/cases/public/containers/use_bulk_update_case.test.tsx index 17b4568cc9de..50d28921e1aa 100644 --- a/x-pack/plugins/cases/public/containers/use_bulk_update_case.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_bulk_update_case.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useUpdateCases } from './use_bulk_update_case'; import { allCases } from './mock'; import { useToasts } from '../common/lib/kibana'; @@ -32,7 +32,7 @@ describe('useUpdateCases', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'updateCases'); - const { waitForNextUpdate, result } = renderHook(() => useUpdateCases(), { + const { result } = renderHook(() => useUpdateCases(), { wrapper: appMockRender.AppWrapper, }); @@ -40,14 +40,12 @@ describe('useUpdateCases', () => { result.current.mutate({ cases: allCases.cases, successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ cases: allCases.cases }); + await waitFor(() => expect(spy).toHaveBeenCalledWith({ cases: allCases.cases })); }); it('invalidates the queries correctly', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => useUpdateCases(), { + const { result } = renderHook(() => useUpdateCases(), { wrapper: appMockRender.AppWrapper, }); @@ -55,15 +53,15 @@ describe('useUpdateCases', () => { result.current.mutate({ cases: allCases.cases, successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + }); }); it('shows a success toaster', async () => { - const { waitForNextUpdate, result } = renderHook(() => useUpdateCases(), { + const { result } = renderHook(() => useUpdateCases(), { wrapper: appMockRender.AppWrapper, }); @@ -71,18 +69,18 @@ describe('useUpdateCases', () => { result.current.mutate({ cases: allCases.cases, successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(addSuccess).toHaveBeenCalledWith({ - title: 'Success title', - className: 'eui-textBreakWord', - }); + await waitFor(() => + expect(addSuccess).toHaveBeenCalledWith({ + title: 'Success title', + className: 'eui-textBreakWord', + }) + ); }); it('shows a toast error when the api return an error', async () => { jest.spyOn(api, 'updateCases').mockRejectedValue(new Error('useUpdateCases: Test error')); - const { waitForNextUpdate, result } = renderHook(() => useUpdateCases(), { + const { result } = renderHook(() => useUpdateCases(), { wrapper: appMockRender.AppWrapper, }); @@ -90,8 +88,6 @@ describe('useUpdateCases', () => { result.current.mutate({ cases: allCases.cases, successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_create_attachments.test.tsx b/x-pack/plugins/cases/public/containers/use_create_attachments.test.tsx index 14d4477df62d..c7aa4b521bcd 100644 --- a/x-pack/plugins/cases/public/containers/use_create_attachments.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_create_attachments.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { AttachmentType } from '../../common/types/domain'; import { SECURITY_SOLUTION_OWNER } from '../../common/constants'; @@ -58,7 +58,7 @@ describe('useCreateAttachments', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'createAttachments'); - const { waitForNextUpdate, result } = renderHook(() => useCreateAttachments(), { + const { result } = renderHook(() => useCreateAttachments(), { wrapper: appMockRender.AppWrapper, }); @@ -66,13 +66,16 @@ describe('useCreateAttachments', () => { result.current.mutate(request); }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ attachments: attachmentsWithOwner, caseId: request.caseId }); + await waitFor(() => + expect(spy).toHaveBeenCalledWith({ + attachments: attachmentsWithOwner, + caseId: request.caseId, + }) + ); }); it('does not show a success toaster', async () => { - const { waitForNextUpdate, result } = renderHook(() => useCreateAttachments(), { + const { result } = renderHook(() => useCreateAttachments(), { wrapper: appMockRender.AppWrapper, }); @@ -80,9 +83,7 @@ describe('useCreateAttachments', () => { result.current.mutate(request); }); - await waitForNextUpdate(); - - expect(addSuccess).not.toHaveBeenCalled(); + await waitFor(() => expect(addSuccess).not.toHaveBeenCalled()); }); it('shows a toast error when the api return an error', async () => { @@ -90,7 +91,7 @@ describe('useCreateAttachments', () => { .spyOn(api, 'createAttachments') .mockRejectedValue(new Error('useCreateAttachments: Test error')); - const { waitForNextUpdate, result } = renderHook(() => useCreateAttachments(), { + const { result } = renderHook(() => useCreateAttachments(), { wrapper: appMockRender.AppWrapper, }); @@ -98,8 +99,6 @@ describe('useCreateAttachments', () => { result.current.mutate(request); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_delete_cases.test.tsx b/x-pack/plugins/cases/public/containers/use_delete_cases.test.tsx index f0ec4e9a43d8..405351c3f068 100644 --- a/x-pack/plugins/cases/public/containers/use_delete_cases.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_delete_cases.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useDeleteCases } from './use_delete_cases'; import * as api from './api'; @@ -32,7 +32,7 @@ describe('useDeleteCases', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'deleteCases'); - const { waitForNextUpdate, result } = renderHook(() => useDeleteCases(), { + const { result } = renderHook(() => useDeleteCases(), { wrapper: appMockRender.AppWrapper, }); @@ -40,14 +40,12 @@ describe('useDeleteCases', () => { result.current.mutate({ caseIds: ['1', '2'], successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ caseIds: ['1', '2'] }); + await waitFor(() => expect(spy).toHaveBeenCalledWith({ caseIds: ['1', '2'] })); }); it('invalidates the queries correctly', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => useDeleteCases(), { + const { result } = renderHook(() => useDeleteCases(), { wrapper: appMockRender.AppWrapper, }); @@ -55,15 +53,15 @@ describe('useDeleteCases', () => { result.current.mutate({ caseIds: ['1', '2'], successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + }); }); it('shows a success toaster', async () => { - const { waitForNextUpdate, result } = renderHook(() => useDeleteCases(), { + const { result } = renderHook(() => useDeleteCases(), { wrapper: appMockRender.AppWrapper, }); @@ -71,18 +69,18 @@ describe('useDeleteCases', () => { result.current.mutate({ caseIds: ['1', '2'], successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(addSuccess).toHaveBeenCalledWith({ - title: 'Success title', - className: 'eui-textBreakWord', - }); + await waitFor(() => + expect(addSuccess).toHaveBeenCalledWith({ + title: 'Success title', + className: 'eui-textBreakWord', + }) + ); }); it('shows a toast error when the api return an error', async () => { jest.spyOn(api, 'deleteCases').mockRejectedValue(new Error('useDeleteCases: Test error')); - const { waitForNextUpdate, result } = renderHook(() => useDeleteCases(), { + const { result } = renderHook(() => useDeleteCases(), { wrapper: appMockRender.AppWrapper, }); @@ -90,8 +88,6 @@ describe('useDeleteCases', () => { result.current.mutate({ caseIds: ['1', '2'], successToasterTitle: 'Success title' }); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_delete_comment.test.tsx b/x-pack/plugins/cases/public/containers/use_delete_comment.test.tsx index c185a7394c88..c3d0739cec37 100644 --- a/x-pack/plugins/cases/public/containers/use_delete_comment.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_delete_comment.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useDeleteComment } from './use_delete_comment'; import * as api from './api'; import { basicCaseId } from './mock'; @@ -45,7 +45,7 @@ describe('useDeleteComment', () => { it('calls deleteComment with correct arguments - case', async () => { const spyOnDeleteComment = jest.spyOn(api, 'deleteComment'); - const { waitForNextUpdate, result } = renderHook(() => useDeleteComment(), { + const { result } = renderHook(() => useDeleteComment(), { wrapper: appMockRender.AppWrapper, }); @@ -57,32 +57,32 @@ describe('useDeleteComment', () => { }); }); - await waitForNextUpdate(); - - expect(spyOnDeleteComment).toBeCalledWith({ - caseId: basicCaseId, - commentId, - }); + await waitFor(() => + expect(spyOnDeleteComment).toBeCalledWith({ + caseId: basicCaseId, + commentId, + }) + ); }); it('refreshes the case page view after delete', async () => { - const { waitForNextUpdate, result } = renderHook(() => useDeleteComment(), { + const { result } = renderHook(() => useDeleteComment(), { wrapper: appMockRender.AppWrapper, }); - result.current.mutate({ - caseId: basicCaseId, - commentId, - successToasterTitle, + act(() => { + result.current.mutate({ + caseId: basicCaseId, + commentId, + successToasterTitle, + }); }); - await waitForNextUpdate(); - - expect(useRefreshCaseViewPage()).toBeCalled(); + await waitFor(() => expect(useRefreshCaseViewPage()).toBeCalled()); }); it('shows a success toaster correctly', async () => { - const { waitForNextUpdate, result } = renderHook(() => useDeleteComment(), { + const { result } = renderHook(() => useDeleteComment(), { wrapper: appMockRender.AppWrapper, }); @@ -94,36 +94,38 @@ describe('useDeleteComment', () => { }); }); - await waitForNextUpdate(); - - expect(addSuccess).toHaveBeenCalledWith({ - title: 'Deleted', - className: 'eui-textBreakWord', - }); + await waitFor(() => + expect(addSuccess).toHaveBeenCalledWith({ + title: 'Deleted', + className: 'eui-textBreakWord', + }) + ); }); it('sets isError when fails to delete a case', async () => { const spyOnDeleteComment = jest.spyOn(api, 'deleteComment'); spyOnDeleteComment.mockRejectedValue(new Error('Error')); - const { waitForNextUpdate, result } = renderHook(() => useDeleteComment(), { + const { result } = renderHook(() => useDeleteComment(), { wrapper: appMockRender.AppWrapper, }); - result.current.mutate({ - caseId: basicCaseId, - commentId, - successToasterTitle, + act(() => { + result.current.mutate({ + caseId: basicCaseId, + commentId, + successToasterTitle, + }); }); - await waitForNextUpdate(); + await waitFor(() => { + expect(spyOnDeleteComment).toBeCalledWith({ + caseId: basicCaseId, + commentId, + }); - expect(spyOnDeleteComment).toBeCalledWith({ - caseId: basicCaseId, - commentId, + expect(addError).toHaveBeenCalled(); + expect(result.current.isError).toBe(true); }); - - expect(addError).toHaveBeenCalled(); - expect(result.current.isError).toBe(true); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_delete_file_attachment.test.tsx b/x-pack/plugins/cases/public/containers/use_delete_file_attachment.test.tsx index 51382a0f548d..329423e41dfa 100644 --- a/x-pack/plugins/cases/public/containers/use_delete_file_attachment.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_delete_file_attachment.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import { basicCaseId, basicFileMock } from './mock'; import { useRefreshCaseViewPage } from '../components/case_view/use_on_refresh_case_view_page'; @@ -34,7 +34,7 @@ describe('useDeleteFileAttachment', () => { it('calls deleteFileAttachment with correct arguments - case', async () => { const spyOnDeleteFileAttachments = jest.spyOn(api, 'deleteFileAttachments'); - const { waitForNextUpdate, result } = renderHook(() => useDeleteFileAttachment(), { + const { result } = renderHook(() => useDeleteFileAttachment(), { wrapper: appMockRender.AppWrapper, }); @@ -45,16 +45,16 @@ describe('useDeleteFileAttachment', () => { }); }); - await waitForNextUpdate(); - - expect(spyOnDeleteFileAttachments).toHaveBeenCalledWith({ - caseId: basicCaseId, - fileIds: [basicFileMock.id], - }); + await waitFor(() => + expect(spyOnDeleteFileAttachments).toHaveBeenCalledWith({ + caseId: basicCaseId, + fileIds: [basicFileMock.id], + }) + ); }); it('refreshes the case page view', async () => { - const { waitForNextUpdate, result } = renderHook(() => useDeleteFileAttachment(), { + const { result } = renderHook(() => useDeleteFileAttachment(), { wrapper: appMockRender.AppWrapper, }); @@ -65,13 +65,11 @@ describe('useDeleteFileAttachment', () => { }) ); - await waitForNextUpdate(); - - expect(useRefreshCaseViewPage()).toBeCalled(); + await waitFor(() => expect(useRefreshCaseViewPage()).toBeCalled()); }); it('shows a success toaster correctly', async () => { - const { waitForNextUpdate, result } = renderHook(() => useDeleteFileAttachment(), { + const { result } = renderHook(() => useDeleteFileAttachment(), { wrapper: appMockRender.AppWrapper, }); @@ -82,19 +80,19 @@ describe('useDeleteFileAttachment', () => { }) ); - await waitForNextUpdate(); - - expect(addSuccess).toHaveBeenCalledWith({ - title: 'File deleted successfully', - className: 'eui-textBreakWord', - }); + await waitFor(() => + expect(addSuccess).toHaveBeenCalledWith({ + title: 'File deleted successfully', + className: 'eui-textBreakWord', + }) + ); }); it('sets isError when fails to delete a file attachment', async () => { const spyOnDeleteFileAttachments = jest.spyOn(api, 'deleteFileAttachments'); spyOnDeleteFileAttachments.mockRejectedValue(new Error('Error')); - const { waitForNextUpdate, result } = renderHook(() => useDeleteFileAttachment(), { + const { result } = renderHook(() => useDeleteFileAttachment(), { wrapper: appMockRender.AppWrapper, }); @@ -105,7 +103,7 @@ describe('useDeleteFileAttachment', () => { }) ); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isError).toBe(true)); expect(spyOnDeleteFileAttachments).toBeCalledWith({ caseId: basicCaseId, @@ -113,6 +111,5 @@ describe('useDeleteFileAttachment', () => { }); expect(addError).toHaveBeenCalled(); - expect(result.current.isError).toBe(true); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_find_case_user_actions.test.tsx b/x-pack/plugins/cases/public/containers/use_find_case_user_actions.test.tsx index 67110c8ebc0b..7dfaa1ff146e 100644 --- a/x-pack/plugins/cases/public/containers/use_find_case_user_actions.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_find_case_user_actions.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useFindCaseUserActions } from './use_find_case_user_actions'; import type { CaseUserActionTypeWithAll } from '../../common/ui/types'; import { basicCase, findCaseUserActionsResponse } from './mock'; @@ -43,33 +43,32 @@ describe('UseFindCaseUserActions', () => { }); it('returns proper state on findCaseUserActions', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useFindCaseUserActions(basicCase.id, params, isEnabled), - { wrapper: appMockRender.AppWrapper } - ); - - await waitForNextUpdate(); - - expect(result.current).toEqual( - expect.objectContaining({ - ...initialData, - data: { - userActions: [...findCaseUserActionsResponse.userActions], - total: 30, - perPage: 10, - page: 1, - }, - isError: false, - isLoading: false, - isFetching: false, - }) + const { result } = renderHook(() => useFindCaseUserActions(basicCase.id, params, isEnabled), { + wrapper: appMockRender.AppWrapper, + }); + + await waitFor(() => + expect(result.current).toEqual( + expect.objectContaining({ + ...initialData, + data: { + userActions: [...findCaseUserActionsResponse.userActions], + total: 30, + perPage: 10, + page: 1, + }, + isError: false, + isLoading: false, + isFetching: false, + }) + ) ); }); it('calls the API with correct parameters', async () => { const spy = jest.spyOn(api, 'findCaseUserActions').mockRejectedValue(initialData); - const { waitForNextUpdate } = renderHook( + renderHook( () => useFindCaseUserActions( basicCase.id, @@ -84,12 +83,12 @@ describe('UseFindCaseUserActions', () => { { wrapper: appMockRender.AppWrapper } ); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith( - basicCase.id, - { type: 'user', sortOrder: 'desc', page: 1, perPage: 5 }, - expect.any(AbortSignal) + await waitFor(() => + expect(spy).toHaveBeenCalledWith( + basicCase.id, + { type: 'user', sortOrder: 'desc', page: 1, perPage: 5 }, + expect.any(AbortSignal) + ) ); }); @@ -120,20 +119,17 @@ describe('UseFindCaseUserActions', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addError }); - const { waitForNextUpdate } = renderHook( - () => useFindCaseUserActions(basicCase.id, params, isEnabled), - { - wrapper: appMockRender.AppWrapper, - } - ); - - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith( - basicCase.id, - { type: filterActionType, sortOrder, page: 1, perPage: 10 }, - expect.any(AbortSignal) - ); - expect(addError).toHaveBeenCalled(); + renderHook(() => useFindCaseUserActions(basicCase.id, params, isEnabled), { + wrapper: appMockRender.AppWrapper, + }); + + await waitFor(() => { + expect(spy).toHaveBeenCalledWith( + basicCase.id, + { type: filterActionType, sortOrder, page: 1, perPage: 10 }, + expect.any(AbortSignal) + ); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_action_license.test.tsx b/x-pack/plugins/cases/public/containers/use_get_action_license.test.tsx index 43e445fa39aa..33cba9ef7123 100644 --- a/x-pack/plugins/cases/public/containers/use_get_action_license.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_action_license.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import { useGetActionLicense } from './use_get_action_license'; import type { AppMockRenderer } from '../common/mock'; @@ -25,12 +25,11 @@ describe('useGetActionLicense', () => { it('calls getActionLicense with correct arguments', async () => { const spyOnGetActionLicense = jest.spyOn(api, 'getActionLicense'); - const { waitForNextUpdate } = renderHook(() => useGetActionLicense(), { + renderHook(() => useGetActionLicense(), { wrapper: appMockRenderer.AppWrapper, }); - await waitForNextUpdate(); - expect(spyOnGetActionLicense).toBeCalledWith(abortCtrl.signal); + await waitFor(() => expect(spyOnGetActionLicense).toBeCalledWith(abortCtrl.signal)); }); it('unhappy path', async () => { @@ -42,11 +41,9 @@ describe('useGetActionLicense', () => { throw new Error('Something went wrong'); }); - const { waitForNextUpdate } = renderHook(() => useGetActionLicense(), { + renderHook(() => useGetActionLicense(), { wrapper: appMockRenderer.AppWrapper, }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case.test.tsx index 1187c7de07d2..6f693e5d4dc1 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case.test.tsx @@ -5,10 +5,9 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; import { useGetCase } from './use_get_case'; import * as api from './api'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import type { FC, PropsWithChildren } from 'react'; import React from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; @@ -32,21 +31,21 @@ const wrapper: FC<PropsWithChildren<unknown>> = ({ children }) => { describe.skip('Use get case hook', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'resolveCase'); - const { waitForNextUpdate } = renderHook(() => useGetCase('case-1'), { wrapper }); - await waitForNextUpdate(); - expect(spy).toHaveBeenCalledWith({ - caseId: 'case-1', - includeComments: true, - signal: expect.any(AbortSignal), - }); + renderHook(() => useGetCase('case-1'), { wrapper }); + await waitFor(() => + expect(spy).toHaveBeenCalledWith({ + caseId: 'case-1', + includeComments: true, + signal: expect.any(AbortSignal), + }) + ); }); it('shows a toast error when the api return an error', async () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addError }); const spy = jest.spyOn(api, 'resolveCase').mockRejectedValue(new Error("C'est la vie")); - const { waitForNextUpdate } = renderHook(() => useGetCase('case-1'), { wrapper }); - await waitForNextUpdate(); + renderHook(() => useGetCase('case-1'), { wrapper }); await waitFor(() => { expect(spy).toHaveBeenCalledWith({ caseId: 'case-1', diff --git a/x-pack/plugins/cases/public/containers/use_get_case_connectors.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_connectors.test.tsx index e73012f83f72..713f8865cd02 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_connectors.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_connectors.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import type { AppMockRenderer } from '../common/mock'; import { createAppMockRenderer } from '../common/mock'; @@ -30,7 +30,7 @@ describe('useGetCaseConnectors', () => { it('calls getCaseConnectors with correct arguments', async () => { const spyOnGetCases = jest.spyOn(api, 'getCaseConnectors'); - const { waitFor } = renderHook(() => useGetCaseConnectors(caseId), { + renderHook(() => useGetCaseConnectors(caseId), { wrapper: appMockRender.AppWrapper, }); @@ -50,7 +50,7 @@ describe('useGetCaseConnectors', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - const { waitFor } = renderHook(() => useGetCaseConnectors(caseId), { + renderHook(() => useGetCaseConnectors(caseId), { wrapper: appMockRender.AppWrapper, }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_file_stats.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_file_stats.test.tsx index e7c55cd1fc0c..dbf800577e85 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_file_stats.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_file_stats.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { basicCase } from './mock'; @@ -37,12 +37,12 @@ describe('useGetCaseFileStats', () => { }); it('calls filesClient.list with correct arguments', async () => { - const { waitForNextUpdate } = renderHook(() => useGetCaseFileStats(hookParams), { + renderHook(() => useGetCaseFileStats(hookParams), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(appMockRender.getFilesClient().list).toHaveBeenCalledWith(expectedCallParams); + await waitFor(() => + expect(appMockRender.getFilesClient().list).toHaveBeenCalledWith(expectedCallParams) + ); }); it('shows an error toast when filesClient.list throws', async () => { @@ -53,12 +53,12 @@ describe('useGetCaseFileStats', () => { throw new Error('Something went wrong'); }); - const { waitForNextUpdate } = renderHook(() => useGetCaseFileStats(hookParams), { + renderHook(() => useGetCaseFileStats(hookParams), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(appMockRender.getFilesClient().list).toHaveBeenCalledWith(expectedCallParams); - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(appMockRender.getFilesClient().list).toHaveBeenCalledWith(expectedCallParams); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_files.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_files.test.tsx index 2be8dd605240..c95eaf15aefe 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_files.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_files.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { basicCase } from './mock'; @@ -48,22 +48,22 @@ describe('useGetCaseFiles', () => { throw new Error('Something went wrong'); }); - const { waitForNextUpdate } = renderHook(() => useGetCaseFiles(hookParams), { + renderHook(() => useGetCaseFiles(hookParams), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(appMockRender.getFilesClient().list).toBeCalledWith(expectedCallParams); - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(appMockRender.getFilesClient().list).toBeCalledWith(expectedCallParams); + expect(addError).toHaveBeenCalled(); + }); }); it('calls filesClient.list with correct arguments', async () => { - const { waitForNextUpdate } = renderHook(() => useGetCaseFiles(hookParams), { + renderHook(() => useGetCaseFiles(hookParams), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(appMockRender.getFilesClient().list).toBeCalledWith(expectedCallParams); + await waitFor(() => + expect(appMockRender.getFilesClient().list).toBeCalledWith(expectedCallParams) + ); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_metrics.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_metrics.test.tsx index 3cda384f1c63..0feb032649a6 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_metrics.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_metrics.test.tsx @@ -7,7 +7,7 @@ import type { FC, PropsWithChildren } from 'react'; import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import type { SingleCaseMetricsFeature } from '../../common/ui'; import { useGetCaseMetrics } from './use_get_case_metrics'; import { basicCase } from './mock'; @@ -34,12 +34,13 @@ describe('useGetCaseMetrics', () => { it('calls getSingleCaseMetrics with correct arguments', async () => { const spyOnGetCaseMetrics = jest.spyOn(api, 'getSingleCaseMetrics'); - const { waitForNextUpdate } = renderHook(() => useGetCaseMetrics(basicCase.id, features), { + renderHook(() => useGetCaseMetrics(basicCase.id, features), { wrapper, }); - await waitForNextUpdate(); - expect(spyOnGetCaseMetrics).toBeCalledWith(basicCase.id, features, abortCtrl.signal); + await waitFor(() => + expect(spyOnGetCaseMetrics).toBeCalledWith(basicCase.id, features, abortCtrl.signal) + ); }); it('shows an error toast when getSingleCaseMetrics throws', async () => { @@ -51,13 +52,13 @@ describe('useGetCaseMetrics', () => { throw new Error('Something went wrong'); }); - const { waitForNextUpdate } = renderHook(() => useGetCaseMetrics(basicCase.id, features), { + renderHook(() => useGetCaseMetrics(basicCase.id, features), { wrapper, }); - await waitForNextUpdate(); - - expect(spyOnGetCaseMetrics).toBeCalledWith(basicCase.id, features, abortCtrl.signal); - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(spyOnGetCaseMetrics).toBeCalledWith(basicCase.id, features, abortCtrl.signal); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx index b81f9d1448aa..bd8ecf7393b2 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_user_actions_stats.test.tsx @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; + +import { waitFor, renderHook } from '@testing-library/react'; import { useToasts } from '../common/lib/kibana'; import type { AppMockRenderer } from '../common/mock'; @@ -31,12 +32,11 @@ describe('useGetCaseUserActionsStats', () => { }); it('returns proper state on getCaseUserActionsStats', async () => { - const { result, waitForNextUpdate } = renderHook( - () => useGetCaseUserActionsStats(basicCase.id), - { wrapper: appMockRender.AppWrapper } - ); + const { result } = renderHook(() => useGetCaseUserActionsStats(basicCase.id), { + wrapper: appMockRender.AppWrapper, + }); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current).toEqual( expect.objectContaining({ @@ -61,25 +61,23 @@ describe('useGetCaseUserActionsStats', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addError }); - const { waitForNextUpdate } = renderHook(() => useGetCaseUserActionsStats(basicCase.id), { + renderHook(() => useGetCaseUserActionsStats(basicCase.id), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith(basicCase.id, expect.any(AbortSignal)); - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(spy).toHaveBeenCalledWith(basicCase.id, expect.any(AbortSignal)); + expect(addError).toHaveBeenCalled(); + }); }); it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getCaseUserActionsStats'); - const { waitForNextUpdate } = renderHook(() => useGetCaseUserActionsStats(basicCase.id), { + renderHook(() => useGetCaseUserActionsStats(basicCase.id), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith(basicCase.id, expect.any(AbortSignal)); + await waitFor(() => expect(spy).toHaveBeenCalledWith(basicCase.id, expect.any(AbortSignal))); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_case_users.test.tsx b/x-pack/plugins/cases/public/containers/use_get_case_users.test.tsx index e35e41c3d49f..7f425081989b 100644 --- a/x-pack/plugins/cases/public/containers/use_get_case_users.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_case_users.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useGetCaseUsers } from './use_get_case_users'; import * as api from './api'; import { useToasts } from '../common/lib/kibana'; @@ -26,13 +26,13 @@ describe('useGetCaseUsers', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getCaseUsers'); - const { waitForNextUpdate } = renderHook(() => useGetCaseUsers('case-1'), { + renderHook(() => useGetCaseUsers('case-1'), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ caseId: 'case-1', signal: expect.any(AbortSignal) }); + await waitFor(() => + expect(spy).toHaveBeenCalledWith({ caseId: 'case-1', signal: expect.any(AbortSignal) }) + ); }); it('shows a toast error when the api return an error', async () => { @@ -40,13 +40,13 @@ describe('useGetCaseUsers', () => { (useToasts as jest.Mock).mockReturnValue({ addError }); const spy = jest.spyOn(api, 'getCaseUsers').mockRejectedValue(new Error("C'est la vie")); - const { waitForNextUpdate } = renderHook(() => useGetCaseUsers('case-1'), { + renderHook(() => useGetCaseUsers('case-1'), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ caseId: 'case-1', signal: expect.any(AbortSignal) }); - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(spy).toHaveBeenCalledWith({ caseId: 'case-1', signal: expect.any(AbortSignal) }); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx index 92d7abde2f9d..0719c14e9fc4 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { DEFAULT_FILTER_OPTIONS, DEFAULT_QUERY_PARAMS } from './constants'; import { useGetCases } from './use_get_cases'; import * as api from './api'; @@ -31,7 +31,7 @@ describe('useGetCases', () => { it('calls getCases with correct arguments', async () => { const spyOnGetCases = jest.spyOn(api, 'getCases'); - const { waitFor } = renderHook(() => useGetCases(), { + renderHook(() => useGetCases(), { wrapper: appMockRender.AppWrapper, }); @@ -55,7 +55,7 @@ describe('useGetCases', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - const { waitFor } = renderHook(() => useGetCases(), { + renderHook(() => useGetCases(), { wrapper: appMockRender.AppWrapper, }); @@ -90,7 +90,7 @@ describe('useGetCases', () => { }; const spyOnGetCases = jest.spyOn(api, 'getCases'); - const { waitFor } = renderHook(() => useGetCases(), { + renderHook(() => useGetCases(), { wrapper: appMockRender.AppWrapper, }); @@ -109,7 +109,7 @@ describe('useGetCases', () => { appMockRender = createAppMockRenderer({ owner: [] }); const spyOnGetCases = jest.spyOn(api, 'getCases'); - const { waitFor } = renderHook(() => useGetCases(), { + renderHook(() => useGetCases(), { wrapper: appMockRender.AppWrapper, }); @@ -128,7 +128,7 @@ describe('useGetCases', () => { appMockRender = createAppMockRenderer({ owner: ['observability'] }); const spyOnGetCases = jest.spyOn(api, 'getCases'); - const { waitFor } = renderHook(() => useGetCases(), { + renderHook(() => useGetCases(), { wrapper: appMockRender.AppWrapper, }); @@ -147,7 +147,7 @@ describe('useGetCases', () => { appMockRender = createAppMockRenderer({ owner: ['observability'] }); const spyOnGetCases = jest.spyOn(api, 'getCases'); - const { waitFor } = renderHook(() => useGetCases({ filterOptions: { owner: ['my-owner'] } }), { + renderHook(() => useGetCases({ filterOptions: { owner: ['my-owner'] } }), { wrapper: appMockRender.AppWrapper, }); diff --git a/x-pack/plugins/cases/public/containers/use_get_cases_metrics.test.tsx b/x-pack/plugins/cases/public/containers/use_get_cases_metrics.test.tsx index 619e1ea4e1eb..e236ccef19bb 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases_metrics.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases_metrics.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from '../api'; import type { AppMockRenderer } from '../common/mock'; import { createAppMockRenderer } from '../common/mock'; @@ -33,17 +33,20 @@ describe('useGetCasesMetrics', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'getCasesMetrics'); - const { waitForNextUpdate } = renderHook(() => useGetCasesMetrics(), { + renderHook(() => useGetCasesMetrics(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ - http: expect.anything(), - signal: abortCtrl.signal, - query: { owner: [SECURITY_SOLUTION_OWNER], features: [CaseMetricsFeature.MTTR] }, - }); + await waitFor(() => + expect(spy).toHaveBeenCalledWith({ + http: expect.anything(), + signal: abortCtrl.signal, + query: { + owner: [SECURITY_SOLUTION_OWNER], + features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS], + }, + }) + ); }); it('shows a toast error when the api return an error', async () => { @@ -51,12 +54,12 @@ describe('useGetCasesMetrics', () => { .spyOn(api, 'getCasesMetrics') .mockRejectedValue(new Error('useGetCasesMetrics: Test error')); - const { waitForNextUpdate } = renderHook(() => useGetCasesMetrics(), { + renderHook(() => useGetCasesMetrics(), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_cases_metrics.tsx b/x-pack/plugins/cases/public/containers/use_get_cases_metrics.tsx index 1e91a182f63d..05df55ee3698 100644 --- a/x-pack/plugins/cases/public/containers/use_get_cases_metrics.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_cases_metrics.tsx @@ -26,7 +26,7 @@ export const useGetCasesMetrics = () => { ({ signal }) => getCasesMetrics({ http, - query: { owner, features: [CaseMetricsFeature.MTTR] }, + query: { owner, features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS] }, signal, }), { diff --git a/x-pack/plugins/cases/public/containers/use_get_cases_status.test.tsx b/x-pack/plugins/cases/public/containers/use_get_cases_status.test.tsx deleted file mode 100644 index fed7159ac15e..000000000000 --- a/x-pack/plugins/cases/public/containers/use_get_cases_status.test.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { renderHook } from '@testing-library/react-hooks'; -import { useGetCasesStatus } from './use_get_cases_status'; -import * as api from '../api'; -import type { AppMockRenderer } from '../common/mock'; -import { createAppMockRenderer } from '../common/mock'; -import { SECURITY_SOLUTION_OWNER } from '../../common/constants'; -import { useToasts } from '../common/lib/kibana'; - -jest.mock('../api'); -jest.mock('../common/lib/kibana'); - -describe('useGetCasesMetrics', () => { - const abortCtrl = new AbortController(); - const addSuccess = jest.fn(); - const addError = jest.fn(); - - (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - - let appMockRender: AppMockRenderer; - - beforeEach(() => { - appMockRender = createAppMockRenderer(); - jest.clearAllMocks(); - }); - - it('calls the api when invoked with the correct parameters', async () => { - const spy = jest.spyOn(api, 'getCasesStatus'); - const { waitForNextUpdate } = renderHook(() => useGetCasesStatus(), { - wrapper: appMockRender.AppWrapper, - }); - - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ - http: expect.anything(), - signal: abortCtrl.signal, - query: { owner: [SECURITY_SOLUTION_OWNER] }, - }); - }); - - it('shows a toast error when the api return an error', async () => { - jest - .spyOn(api, 'getCasesStatus') - .mockRejectedValue(new Error('useGetCasesMetrics: Test error')); - - const { waitForNextUpdate } = renderHook(() => useGetCasesStatus(), { - wrapper: appMockRender.AppWrapper, - }); - - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/cases/public/containers/use_get_cases_status.tsx b/x-pack/plugins/cases/public/containers/use_get_cases_status.tsx deleted file mode 100644 index 47733508d18c..000000000000 --- a/x-pack/plugins/cases/public/containers/use_get_cases_status.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { useQuery } from '@tanstack/react-query'; -import { useCasesContext } from '../components/cases_context/use_cases_context'; -import * as i18n from './translations'; -import type { CasesStatus } from './types'; -import { useHttp } from '../common/lib/kibana'; -import { getCasesStatus } from '../api'; -import { useCasesToast } from '../common/use_cases_toast'; -import type { ServerError } from '../types'; -import { casesQueriesKeys } from './constants'; - -export const useGetCasesStatus = () => { - const http = useHttp(); - const { owner } = useCasesContext(); - const { showErrorToast } = useCasesToast(); - - return useQuery<CasesStatus, ServerError>( - casesQueriesKeys.casesStatuses(), - ({ signal }) => - getCasesStatus({ - http, - query: { owner }, - signal, - }), - { - onError: (error: ServerError) => { - showErrorToast(error, { title: i18n.ERROR_TITLE }); - }, - } - ); -}; - -export type UseGetCasesStatus = ReturnType<typeof useGetCasesStatus>; diff --git a/x-pack/plugins/cases/public/containers/use_get_categories.test.tsx b/x-pack/plugins/cases/public/containers/use_get_categories.test.tsx index d80f03822ec7..11b242a3072d 100644 --- a/x-pack/plugins/cases/public/containers/use_get_categories.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_categories.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import { TestProviders } from '../common/mock'; import { SECURITY_SOLUTION_OWNER } from '../../common/constants'; @@ -24,18 +24,18 @@ describe('useGetCategories', () => { it('calls getCategories api', async () => { const spyOnGetCategories = jest.spyOn(api, 'getCategories'); - const { waitForNextUpdate } = renderHook(() => useGetCategories(), { + renderHook(() => useGetCategories(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - - expect(spyOnGetCategories).toBeCalledWith({ - signal: abortCtrl.signal, - owner: [SECURITY_SOLUTION_OWNER], - }); + await waitFor(() => + expect(spyOnGetCategories).toBeCalledWith({ + signal: abortCtrl.signal, + owner: [SECURITY_SOLUTION_OWNER], + }) + ); }); it('displays an error toast when an error occurs', async () => { @@ -47,14 +47,12 @@ describe('useGetCategories', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addError }); - const { waitForNextUpdate } = renderHook(() => useGetCategories(), { + renderHook(() => useGetCategories(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - - expect(addError).toBeCalled(); + await waitFor(() => expect(addError).toBeCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx b/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx index 9446007e367d..dee68dff0337 100644 --- a/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_feature_ids.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { useToasts } from '../common/lib/kibana'; import type { AppMockRenderer } from '../common/mock'; import { createAppMockRenderer } from '../common/mock'; @@ -32,12 +31,10 @@ describe('useGetFeaturesIds', () => { it('returns the features ids correctly', async () => { const spy = jest.spyOn(api, 'getFeatureIds').mockRejectedValue([]); - const { waitForNextUpdate } = renderHook(() => useGetFeatureIds(['alert-id-1'], true), { + renderHook(() => useGetFeatureIds(['alert-id-1'], true), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - await waitFor(() => { expect(spy).toHaveBeenCalledWith({ query: { @@ -67,12 +64,10 @@ describe('useGetFeaturesIds', () => { .spyOn(api, 'getFeatureIds') .mockRejectedValue(new Error('Something went wrong')); - const { waitForNextUpdate } = renderHook(() => useGetFeatureIds(['alert-id-1'], true), { + renderHook(() => useGetFeatureIds(['alert-id-1'], true), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - await waitFor(() => { expect(spy).toHaveBeenCalledWith({ query: { diff --git a/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx b/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx index a19074ff279e..315757f065d8 100644 --- a/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_get_tags.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import { TestProviders } from '../common/mock'; import { SECURITY_SOLUTION_OWNER } from '../../common/constants'; @@ -24,16 +24,17 @@ describe('useGetTags', () => { it('calls getTags api', async () => { const spyOnGetTags = jest.spyOn(api, 'getTags'); - const { waitForNextUpdate } = renderHook(() => useGetTags(), { + renderHook(() => useGetTags(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - expect(spyOnGetTags).toBeCalledWith({ - owner: [SECURITY_SOLUTION_OWNER], - signal: abortCtrl.signal, - }); + await waitFor(() => + expect(spyOnGetTags).toBeCalledWith({ + owner: [SECURITY_SOLUTION_OWNER], + signal: abortCtrl.signal, + }) + ); }); it('displays and error toast when an error occurs', async () => { @@ -43,12 +44,11 @@ describe('useGetTags', () => { spyOnGetTags.mockImplementation(() => { throw new Error('Something went wrong'); }); - const { waitForNextUpdate } = renderHook(() => useGetTags(), { + renderHook(() => useGetTags(), { wrapper: ({ children }: React.PropsWithChildren<{}>) => ( <TestProviders>{children}</TestProviders> ), }); - await waitForNextUpdate(); - expect(addError).toBeCalled(); + await waitFor(() => expect(addError).toBeCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_infinite_find_case_user_actions.test.tsx b/x-pack/plugins/cases/public/containers/use_infinite_find_case_user_actions.test.tsx index b3df805033ba..19a7f2b9edc3 100644 --- a/x-pack/plugins/cases/public/containers/use_infinite_find_case_user_actions.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_infinite_find_case_user_actions.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useInfiniteFindCaseUserActions } from './use_infinite_find_case_user_actions'; import type { CaseUserActionTypeWithAll } from '../../common/ui/types'; @@ -42,12 +42,12 @@ describe('UseInfiniteFindCaseUserActions', () => { }); it('returns proper state on findCaseUserActions', async () => { - const { result, waitForNextUpdate } = renderHook( + const { result } = renderHook( () => useInfiniteFindCaseUserActions(basicCase.id, params, isEnabled), { wrapper: appMockRender.AppWrapper } ); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current).toEqual( expect.objectContaining({ @@ -73,7 +73,7 @@ describe('UseInfiniteFindCaseUserActions', () => { it('calls the API with correct parameters', async () => { const spy = jest.spyOn(api, 'findCaseUserActions').mockRejectedValue(initialData); - const { waitForNextUpdate } = renderHook( + renderHook( () => useInfiniteFindCaseUserActions( basicCase.id, @@ -87,12 +87,12 @@ describe('UseInfiniteFindCaseUserActions', () => { { wrapper: appMockRender.AppWrapper } ); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith( - basicCase.id, - { type: 'user', sortOrder: 'desc', page: 1, perPage: 5 }, - expect.any(AbortSignal) + await waitFor(() => + expect(spy).toHaveBeenCalledWith( + basicCase.id, + { type: 'user', sortOrder: 'desc', page: 1, perPage: 5 }, + expect.any(AbortSignal) + ) ); }); @@ -122,33 +122,31 @@ describe('UseInfiniteFindCaseUserActions', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addError }); - const { waitForNextUpdate } = renderHook( - () => useInfiniteFindCaseUserActions(basicCase.id, params, isEnabled), - { - wrapper: appMockRender.AppWrapper, - } - ); + renderHook(() => useInfiniteFindCaseUserActions(basicCase.id, params, isEnabled), { + wrapper: appMockRender.AppWrapper, + }); - await waitForNextUpdate(); + await waitFor(() => { + expect(spy).toHaveBeenCalledWith( + basicCase.id, + { type: filterActionType, sortOrder, page: 1, perPage: 10 }, + expect.any(AbortSignal) + ); + expect(addError).toHaveBeenCalled(); + }); - expect(spy).toHaveBeenCalledWith( - basicCase.id, - { type: filterActionType, sortOrder, page: 1, perPage: 10 }, - expect.any(AbortSignal) - ); - expect(addError).toHaveBeenCalled(); spy.mockRestore(); }); it('fetches next page with correct params', async () => { const spy = jest.spyOn(api, 'findCaseUserActions'); - const { result, waitFor } = renderHook( + const { result } = renderHook( () => useInfiniteFindCaseUserActions(basicCase.id, params, isEnabled), { wrapper: appMockRender.AppWrapper } ); - await waitFor(() => result.current.isSuccess); + await waitFor(() => expect(result.current.isSuccess).toBe(true)); expect(result.current.data?.pages).toStrictEqual([findCaseUserActionsResponse]); @@ -165,7 +163,7 @@ describe('UseInfiniteFindCaseUserActions', () => { expect.any(AbortSignal) ); }); - await waitFor(() => result.current.data?.pages.length === 2); + await waitFor(() => expect(result.current.data?.pages).toHaveLength(2)); }); it('returns hasNextPage correctly', async () => { diff --git a/x-pack/plugins/cases/public/containers/use_messages_storage.test.tsx b/x-pack/plugins/cases/public/containers/use_messages_storage.test.tsx index ef4a164e759b..30254f02412f 100644 --- a/x-pack/plugins/cases/public/containers/use_messages_storage.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_messages_storage.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; -import type { UseMessagesStorage } from './use_messages_storage'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useMessagesStorage } from './use_messages_storage'; describe('useMessagesStorage', () => { @@ -18,35 +17,29 @@ describe('useMessagesStorage', () => { }); it('should return an empty array when there is no messages', async () => { + const { result } = renderHook(() => useMessagesStorage()); + await waitFor(() => new Promise((resolve) => resolve(null))); + const { getMessages } = result.current; await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() => - useMessagesStorage() - ); - await waitForNextUpdate(); - const { getMessages } = result.current; expect(getMessages('case')).toEqual([]); }); }); it('should add a message', async () => { + const { result } = renderHook(() => useMessagesStorage()); + await waitFor(() => new Promise((resolve) => resolve(null))); + const { getMessages, addMessage } = result.current; await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() => - useMessagesStorage() - ); - await waitForNextUpdate(); - const { getMessages, addMessage } = result.current; addMessage('case', 'id-1'); expect(getMessages('case')).toEqual(['id-1']); }); }); it('should add multiple messages', async () => { + const { result } = renderHook(() => useMessagesStorage()); + await waitFor(() => new Promise((resolve) => resolve(null))); + const { getMessages, addMessage } = result.current; await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() => - useMessagesStorage() - ); - await waitForNextUpdate(); - const { getMessages, addMessage } = result.current; addMessage('case', 'id-1'); addMessage('case', 'id-2'); expect(getMessages('case')).toEqual(['id-1', 'id-2']); @@ -54,12 +47,10 @@ describe('useMessagesStorage', () => { }); it('should remove a message', async () => { + const { result } = renderHook(() => useMessagesStorage()); + await waitFor(() => new Promise((resolve) => resolve(null))); + const { getMessages, addMessage, removeMessage } = result.current; await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() => - useMessagesStorage() - ); - await waitForNextUpdate(); - const { getMessages, addMessage, removeMessage } = result.current; addMessage('case', 'id-1'); addMessage('case', 'id-2'); removeMessage('case', 'id-2'); @@ -68,12 +59,10 @@ describe('useMessagesStorage', () => { }); it('should return presence of a message', async () => { + const { result } = renderHook(() => useMessagesStorage()); + await waitFor(() => new Promise((resolve) => resolve(null))); + const { hasMessage, addMessage, removeMessage } = result.current; await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() => - useMessagesStorage() - ); - await waitForNextUpdate(); - const { hasMessage, addMessage, removeMessage } = result.current; addMessage('case', 'id-1'); addMessage('case', 'id-2'); removeMessage('case', 'id-2'); @@ -83,16 +72,14 @@ describe('useMessagesStorage', () => { }); it('should clear all messages', async () => { + const { result } = renderHook(() => useMessagesStorage()); + await waitFor(() => new Promise((resolve) => resolve(null))); + const { getMessages, addMessage, clearAllMessages } = result.current; await act(async () => { - const { result, waitForNextUpdate } = renderHook<string, UseMessagesStorage>(() => - useMessagesStorage() - ); - await waitForNextUpdate(); - const { getMessages, addMessage, clearAllMessages } = result.current; addMessage('case', 'id-1'); addMessage('case', 'id-2'); clearAllMessages('case'); - expect(getMessages('case')).toEqual([]); }); + expect(getMessages('case')).toEqual([]); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_post_case.test.tsx b/x-pack/plugins/cases/public/containers/use_post_case.test.tsx index 58a878b32e57..d2c4cb65435c 100644 --- a/x-pack/plugins/cases/public/containers/use_post_case.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_post_case.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import * as api from './api'; import { ConnectorTypes } from '../../common/types/domain'; import { SECURITY_SOLUTION_OWNER } from '../../common/constants'; @@ -49,7 +49,7 @@ describe('usePostCase', () => { it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'postCase'); - const { waitForNextUpdate, result } = renderHook(() => usePostCase(), { + const { result } = renderHook(() => usePostCase(), { wrapper: appMockRender.AppWrapper, }); @@ -57,14 +57,12 @@ describe('usePostCase', () => { result.current.mutate({ request: samplePost }); }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ newCase: samplePost }); + await waitFor(() => expect(spy).toHaveBeenCalledWith({ newCase: samplePost })); }); it('invalidates the queries correctly', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => usePostCase(), { + const { result } = renderHook(() => usePostCase(), { wrapper: appMockRender.AppWrapper, }); @@ -72,15 +70,15 @@ describe('usePostCase', () => { result.current.mutate({ request: samplePost }); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.casesList()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.userProfiles()); + }); }); it('does not show a success toaster', async () => { - const { waitForNextUpdate, result } = renderHook(() => usePostCase(), { + const { result } = renderHook(() => usePostCase(), { wrapper: appMockRender.AppWrapper, }); @@ -88,15 +86,13 @@ describe('usePostCase', () => { result.current.mutate({ request: samplePost }); }); - await waitForNextUpdate(); - - expect(addSuccess).not.toHaveBeenCalled(); + await waitFor(() => expect(addSuccess).not.toHaveBeenCalled()); }); it('shows a toast error when the api return an error', async () => { jest.spyOn(api, 'postCase').mockRejectedValue(new Error('usePostCase: Test error')); - const { waitForNextUpdate, result } = renderHook(() => usePostCase(), { + const { result } = renderHook(() => usePostCase(), { wrapper: appMockRender.AppWrapper, }); @@ -104,8 +100,6 @@ describe('usePostCase', () => { result.current.mutate({ request: samplePost }); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx b/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx index 1d802b3737c9..0c7a76bc6ff3 100644 --- a/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_post_push_to_service.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useToasts } from '../common/lib/kibana'; import { usePostPushToService } from './use_post_push_to_service'; import { pushedCase } from './mock'; @@ -42,7 +42,7 @@ describe('usePostPushToService', () => { it('refresh the case after pushing', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => usePostPushToService(), { + const { result } = renderHook(() => usePostPushToService(), { wrapper: appMockRender.AppWrapper, }); @@ -50,15 +50,15 @@ describe('usePostPushToService', () => { result.current.mutate({ caseId, connector }); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + }); }); it('calls the api when invoked with the correct parameters', async () => { const spy = jest.spyOn(api, 'pushCase'); - const { waitForNextUpdate, result } = renderHook(() => usePostPushToService(), { + const { result } = renderHook(() => usePostPushToService(), { wrapper: appMockRender.AppWrapper, }); @@ -66,13 +66,11 @@ describe('usePostPushToService', () => { result.current.mutate({ caseId, connector }); }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith({ caseId, connectorId: connector.id }); + await waitFor(() => expect(spy).toHaveBeenCalledWith({ caseId, connectorId: connector.id })); }); it('shows a success toaster', async () => { - const { waitForNextUpdate, result } = renderHook(() => usePostPushToService(), { + const { result } = renderHook(() => usePostPushToService(), { wrapper: appMockRender.AppWrapper, }); @@ -80,18 +78,18 @@ describe('usePostPushToService', () => { result.current.mutate({ caseId, connector }); }); - await waitForNextUpdate(); - - expect(addSuccess).toHaveBeenCalledWith({ - title: 'Successfully sent to My connector', - className: 'eui-textBreakWord', - }); + await waitFor(() => + expect(addSuccess).toHaveBeenCalledWith({ + title: 'Successfully sent to My connector', + className: 'eui-textBreakWord', + }) + ); }); it('shows a toast error when the api return an error', async () => { jest.spyOn(api, 'pushCase').mockRejectedValue(new Error('usePostPushToService: Test error')); - const { waitForNextUpdate, result } = renderHook(() => usePostPushToService(), { + const { result } = renderHook(() => usePostPushToService(), { wrapper: appMockRender.AppWrapper, }); @@ -99,8 +97,6 @@ describe('usePostPushToService', () => { result.current.mutate({ caseId, connector }); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_replace_custom_field.test.tsx b/x-pack/plugins/cases/public/containers/use_replace_custom_field.test.tsx index 366d946af1d9..4b17c874339d 100644 --- a/x-pack/plugins/cases/public/containers/use_replace_custom_field.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_replace_custom_field.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { basicCase } from './mock'; import * as api from './api'; import type { AppMockRenderer } from '../common/mock'; @@ -39,7 +39,7 @@ describe('useReplaceCustomField', () => { it('replace a customField and refresh the case page', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => useReplaceCustomField(), { + const { result } = renderHook(() => useReplaceCustomField(), { wrapper: appMockRender.AppWrapper, }); @@ -47,15 +47,15 @@ describe('useReplaceCustomField', () => { result.current.mutate(sampleData); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + }); }); it('calls the api when invoked with the correct parameters', async () => { const patchCustomFieldSpy = jest.spyOn(api, 'replaceCustomField'); - const { waitForNextUpdate, result } = renderHook(() => useReplaceCustomField(), { + const { result } = renderHook(() => useReplaceCustomField(), { wrapper: appMockRender.AppWrapper, }); @@ -63,16 +63,16 @@ describe('useReplaceCustomField', () => { result.current.mutate(sampleData); }); - await waitForNextUpdate(); - - expect(patchCustomFieldSpy).toHaveBeenCalledWith({ - caseId: sampleData.caseId, - customFieldId: sampleData.customFieldId, - request: { - value: sampleData.customFieldValue, - caseVersion: sampleData.caseVersion, - }, - }); + await waitFor(() => + expect(patchCustomFieldSpy).toHaveBeenCalledWith({ + caseId: sampleData.caseId, + customFieldId: sampleData.customFieldId, + request: { + value: sampleData.customFieldValue, + caseVersion: sampleData.caseVersion, + }, + }) + ); }); it('calls the api when invoked with the correct parameters of toggle field', async () => { @@ -83,7 +83,7 @@ describe('useReplaceCustomField', () => { caseVersion: basicCase.version, }; const patchCustomFieldSpy = jest.spyOn(api, 'replaceCustomField'); - const { waitForNextUpdate, result } = renderHook(() => useReplaceCustomField(), { + const { result } = renderHook(() => useReplaceCustomField(), { wrapper: appMockRender.AppWrapper, }); @@ -91,16 +91,16 @@ describe('useReplaceCustomField', () => { result.current.mutate(newData); }); - await waitForNextUpdate(); - - expect(patchCustomFieldSpy).toHaveBeenCalledWith({ - caseId: newData.caseId, - customFieldId: newData.customFieldId, - request: { - value: newData.customFieldValue, - caseVersion: newData.caseVersion, - }, - }); + await waitFor(() => + expect(patchCustomFieldSpy).toHaveBeenCalledWith({ + caseId: newData.caseId, + customFieldId: newData.customFieldId, + request: { + value: newData.customFieldValue, + caseVersion: newData.caseVersion, + }, + }) + ); }); it('calls the api when invoked with the correct parameters with null value', async () => { @@ -111,7 +111,7 @@ describe('useReplaceCustomField', () => { caseVersion: basicCase.version, }; const patchCustomFieldSpy = jest.spyOn(api, 'replaceCustomField'); - const { waitForNextUpdate, result } = renderHook(() => useReplaceCustomField(), { + const { result } = renderHook(() => useReplaceCustomField(), { wrapper: appMockRender.AppWrapper, }); @@ -119,16 +119,16 @@ describe('useReplaceCustomField', () => { result.current.mutate(newData); }); - await waitForNextUpdate(); - - expect(patchCustomFieldSpy).toHaveBeenCalledWith({ - caseId: newData.caseId, - customFieldId: newData.customFieldId, - request: { - value: newData.customFieldValue, - caseVersion: newData.caseVersion, - }, - }); + await waitFor(() => + expect(patchCustomFieldSpy).toHaveBeenCalledWith({ + caseId: newData.caseId, + customFieldId: newData.customFieldId, + request: { + value: newData.customFieldValue, + caseVersion: newData.caseVersion, + }, + }) + ); }); it('shows a toast error when the api return an error', async () => { @@ -136,7 +136,7 @@ describe('useReplaceCustomField', () => { .spyOn(api, 'replaceCustomField') .mockRejectedValue(new Error('useUpdateComment: Test error')); - const { waitForNextUpdate, result } = renderHook(() => useReplaceCustomField(), { + const { result } = renderHook(() => useReplaceCustomField(), { wrapper: appMockRender.AppWrapper, }); @@ -144,8 +144,6 @@ describe('useReplaceCustomField', () => { result.current.mutate(sampleData); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_update_case.test.tsx b/x-pack/plugins/cases/public/containers/use_update_case.test.tsx index f8d4ff82078c..4b1454446079 100644 --- a/x-pack/plugins/cases/public/containers/use_update_case.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_update_case.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useUpdateCase } from './use_update_case'; import { basicCase } from './mock'; import * as api from './api'; @@ -41,7 +41,7 @@ describe('useUpdateCase', () => { it('patch case and refresh the case page', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => useUpdateCase(), { + const { result } = renderHook(() => useUpdateCase(), { wrapper: appMockRender.AppWrapper, }); @@ -49,15 +49,15 @@ describe('useUpdateCase', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + }); }); it('calls the api when invoked with the correct parameters', async () => { const patchCaseSpy = jest.spyOn(api, 'patchCase'); - const { waitForNextUpdate, result } = renderHook(() => useUpdateCase(), { + const { result } = renderHook(() => useUpdateCase(), { wrapper: appMockRender.AppWrapper, }); @@ -65,17 +65,17 @@ describe('useUpdateCase', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(patchCaseSpy).toHaveBeenCalledWith({ - caseId: basicCase.id, - updatedCase: { description: 'updated description' }, - version: basicCase.version, - }); + await waitFor(() => + expect(patchCaseSpy).toHaveBeenCalledWith({ + caseId: basicCase.id, + updatedCase: { description: 'updated description' }, + version: basicCase.version, + }) + ); }); it('shows a success toaster', async () => { - const { waitForNextUpdate, result } = renderHook(() => useUpdateCase(), { + const { result } = renderHook(() => useUpdateCase(), { wrapper: appMockRender.AppWrapper, }); @@ -83,18 +83,18 @@ describe('useUpdateCase', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(addSuccess).toHaveBeenCalledWith({ - title: 'Updated "Another horrible breach!!"', - className: 'eui-textBreakWord', - }); + await waitFor(() => + expect(addSuccess).toHaveBeenCalledWith({ + title: 'Updated "Another horrible breach!!"', + className: 'eui-textBreakWord', + }) + ); }); it('shows a toast error when the api return an error', async () => { jest.spyOn(api, 'patchCase').mockRejectedValue(new Error('useUpdateCase: Test error')); - const { waitForNextUpdate, result } = renderHook(() => useUpdateCase(), { + const { result } = renderHook(() => useUpdateCase(), { wrapper: appMockRender.AppWrapper, }); @@ -102,8 +102,6 @@ describe('useUpdateCase', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/use_update_comment.test.tsx b/x-pack/plugins/cases/public/containers/use_update_comment.test.tsx index 59c06bd545c8..7a2522d6ac8c 100644 --- a/x-pack/plugins/cases/public/containers/use_update_comment.test.tsx +++ b/x-pack/plugins/cases/public/containers/use_update_comment.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { basicCase } from './mock'; import * as api from './api'; import type { AppMockRenderer } from '../common/mock'; @@ -39,7 +39,7 @@ describe('useUpdateComment', () => { it('patch case and refresh the case page', async () => { const queryClientSpy = jest.spyOn(appMockRender.queryClient, 'invalidateQueries'); - const { waitForNextUpdate, result } = renderHook(() => useUpdateComment(), { + const { result } = renderHook(() => useUpdateComment(), { wrapper: appMockRender.AppWrapper, }); @@ -47,15 +47,15 @@ describe('useUpdateComment', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); - expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + await waitFor(() => { + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.caseView()); + expect(queryClientSpy).toHaveBeenCalledWith(casesQueriesKeys.tags()); + }); }); it('calls the api when invoked with the correct parameters', async () => { const patchCommentSpy = jest.spyOn(api, 'patchComment'); - const { waitForNextUpdate, result } = renderHook(() => useUpdateComment(), { + const { result } = renderHook(() => useUpdateComment(), { wrapper: appMockRender.AppWrapper, }); @@ -63,18 +63,18 @@ describe('useUpdateComment', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(patchCommentSpy).toHaveBeenCalledWith({ - ...sampleUpdate, - owner: 'securitySolution', - }); + await waitFor(() => + expect(patchCommentSpy).toHaveBeenCalledWith({ + ...sampleUpdate, + owner: 'securitySolution', + }) + ); }); it('shows a toast error when the api return an error', async () => { jest.spyOn(api, 'patchComment').mockRejectedValue(new Error('useUpdateComment: Test error')); - const { waitForNextUpdate, result } = renderHook(() => useUpdateComment(), { + const { result } = renderHook(() => useUpdateComment(), { wrapper: appMockRender.AppWrapper, }); @@ -82,8 +82,6 @@ describe('useUpdateComment', () => { result.current.mutate(sampleUpdate); }); - await waitForNextUpdate(); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); }); diff --git a/x-pack/plugins/cases/public/containers/user_profiles/use_assignees.test.ts b/x-pack/plugins/cases/public/containers/user_profiles/use_assignees.test.ts index 3622b66aef00..f808d8d7dd93 100644 --- a/x-pack/plugins/cases/public/containers/user_profiles/use_assignees.test.ts +++ b/x-pack/plugins/cases/public/containers/user_profiles/use_assignees.test.ts @@ -6,7 +6,7 @@ */ import type { UserProfileWithAvatar } from '@kbn/user-profile-components'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { userProfiles, userProfilesMap } from './api.mock'; import { useAssignees } from './use_assignees'; diff --git a/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts b/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts index 4edc105b8d34..4558c7cdd2d3 100644 --- a/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts +++ b/x-pack/plugins/cases/public/containers/user_profiles/use_bulk_get_user_profiles.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useToasts, useKibana } from '../../common/lib/kibana'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; @@ -41,26 +41,25 @@ describe.skip('useBulkGetUserProfiles', () => { it('calls bulkGetUserProfiles with correct arguments', async () => { const spyOnBulkGetUserProfiles = jest.spyOn(api, 'bulkGetUserProfiles'); - const { result, waitFor } = renderHook(() => useBulkGetUserProfiles(props), { + renderHook(() => useBulkGetUserProfiles(props), { wrapper: appMockRender.AppWrapper, }); - await waitFor(() => result.current.isSuccess); - - expect(spyOnBulkGetUserProfiles).toBeCalledWith({ - ...props, - security: expect.anything(), - }); + await waitFor(() => + expect(spyOnBulkGetUserProfiles).toBeCalledWith({ + ...props, + security: expect.anything(), + }) + ); }); it('returns a mapping with user profiles', async () => { - const { result, waitFor } = renderHook(() => useBulkGetUserProfiles(props), { + const { result } = renderHook(() => useBulkGetUserProfiles(props), { wrapper: appMockRender.AppWrapper, }); - await waitFor(() => result.current.isSuccess); - - expect(result.current.data).toMatchInlineSnapshot(` + await waitFor(() => + expect(result.current.data).toMatchInlineSnapshot(` Map { "u_J41Oh6L9ki-Vo2tOogS8WRTENzhHurGtRc87NgEAlkc_0" => Object { "data": Object {}, @@ -93,7 +92,8 @@ describe.skip('useBulkGetUserProfiles', () => { }, }, } - `); + `) + ); }); it('shows a toast error message when an error occurs in the response', async () => { @@ -106,13 +106,11 @@ describe.skip('useBulkGetUserProfiles', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - const { result, waitFor } = renderHook(() => useBulkGetUserProfiles(props), { + renderHook(() => useBulkGetUserProfiles(props), { wrapper: appMockRender.AppWrapper, }); - await waitFor(() => result.current.isError); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => expect(addError).toHaveBeenCalled()); }); it('does not call the bulkGetUserProfiles if the array of uids is empty', async () => { diff --git a/x-pack/plugins/cases/public/containers/user_profiles/use_get_current_user_profile.test.ts b/x-pack/plugins/cases/public/containers/user_profiles/use_get_current_user_profile.test.ts index c26a6af82654..918771d5b218 100644 --- a/x-pack/plugins/cases/public/containers/user_profiles/use_get_current_user_profile.test.ts +++ b/x-pack/plugins/cases/public/containers/user_profiles/use_get_current_user_profile.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useToasts, useKibana } from '../../common/lib/kibana'; import { createStartServicesMock } from '../../common/lib/kibana/kibana_react.mock'; import type { AppMockRenderer } from '../../common/mock'; @@ -36,7 +36,7 @@ describe('useGetCurrentUserProfile', () => { it('calls getCurrentUserProfile with correct arguments', async () => { const spyOnGetCurrentUserProfile = jest.spyOn(api, 'getCurrentUserProfile'); - const { waitFor } = renderHook(() => useGetCurrentUserProfile(), { + renderHook(() => useGetCurrentUserProfile(), { wrapper: appMockRender.AppWrapper, }); @@ -59,7 +59,7 @@ describe('useGetCurrentUserProfile', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - const { waitFor } = renderHook(() => useGetCurrentUserProfile(), { + renderHook(() => useGetCurrentUserProfile(), { wrapper: appMockRender.AppWrapper, }); @@ -78,7 +78,7 @@ describe('useGetCurrentUserProfile', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - const { waitFor } = renderHook(() => useGetCurrentUserProfile(), { + renderHook(() => useGetCurrentUserProfile(), { wrapper: appMockRender.AppWrapper, }); diff --git a/x-pack/plugins/cases/public/containers/user_profiles/use_suggest_user_profiles.test.ts b/x-pack/plugins/cases/public/containers/user_profiles/use_suggest_user_profiles.test.ts index 7daf1d1d5cf6..67907d649464 100644 --- a/x-pack/plugins/cases/public/containers/user_profiles/use_suggest_user_profiles.test.ts +++ b/x-pack/plugins/cases/public/containers/user_profiles/use_suggest_user_profiles.test.ts @@ -6,7 +6,7 @@ */ import { GENERAL_CASES_OWNER } from '../../../common/constants'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useToasts } from '../../common/lib/kibana'; import type { AppMockRenderer } from '../../common/mock'; import { createAppMockRenderer } from '../../common/mock'; @@ -34,17 +34,18 @@ describe('useSuggestUserProfiles', () => { it('calls suggestUserProfiles with correct arguments', async () => { const spyOnSuggestUserProfiles = jest.spyOn(api, 'suggestUserProfiles'); - const { result, waitFor } = renderHook(() => useSuggestUserProfiles(props), { + const { result } = renderHook(() => useSuggestUserProfiles(props), { wrapper: appMockRender.AppWrapper, }); - await waitFor(() => result.current.isSuccess); - - expect(spyOnSuggestUserProfiles).toBeCalledWith({ - ...props, - size: 10, - http: expect.anything(), - signal: expect.anything(), + await waitFor(() => { + expect(result.current.isSuccess).toBeDefined(); + expect(spyOnSuggestUserProfiles).toBeCalledWith({ + ...props, + size: 10, + http: expect.anything(), + signal: expect.anything(), + }); }); }); @@ -58,12 +59,13 @@ describe('useSuggestUserProfiles', () => { const addError = jest.fn(); (useToasts as jest.Mock).mockReturnValue({ addSuccess, addError }); - const { result, waitFor } = renderHook(() => useSuggestUserProfiles(props), { + const { result } = renderHook(() => useSuggestUserProfiles(props), { wrapper: appMockRender.AppWrapper, }); - await waitFor(() => result.current.isError); - - expect(addError).toHaveBeenCalled(); + await waitFor(() => { + expect(result.current.isError).toBeDefined(); + expect(addError).toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/cases/public/mocks.ts b/x-pack/plugins/cases/public/mocks.ts index 3de6a9697906..a4f1150b7e1e 100644 --- a/x-pack/plugins/cases/public/mocks.ts +++ b/x-pack/plugins/cases/public/mocks.ts @@ -13,7 +13,6 @@ const apiMock: jest.Mocked<CasesPublicStart['api']> = { cases: { find: jest.fn(), getCasesMetrics: jest.fn(), - getCasesStatus: jest.fn(), bulkGet: jest.fn(), }, }; diff --git a/x-pack/plugins/cases/public/plugin.test.ts b/x-pack/plugins/cases/public/plugin.test.ts index 54f9cf070df4..0d519f038e3b 100644 --- a/x-pack/plugins/cases/public/plugin.test.ts +++ b/x-pack/plugins/cases/public/plugin.test.ts @@ -129,7 +129,6 @@ describe('Cases Ui Plugin', () => { bulkGet: expect.any(Function), find: expect.any(Function), getCasesMetrics: expect.any(Function), - getCasesStatus: expect.any(Function), }, getRelatedCases: expect.any(Function), }, diff --git a/x-pack/plugins/cases/public/types.ts b/x-pack/plugins/cases/public/types.ts index 7f1d4863eac7..b61991952576 100644 --- a/x-pack/plugins/cases/public/types.ts +++ b/x-pack/plugins/cases/public/types.ts @@ -40,7 +40,7 @@ import type { GetCasesContextProps } from './client/ui/get_cases_context'; import type { GetCasesProps } from './client/ui/get_cases'; import type { GetAllCasesSelectorModalProps } from './client/ui/get_all_cases_selector_modal'; import type { GetRecentCasesProps } from './client/ui/get_recent_cases'; -import type { CasesStatus, CasesMetrics, CasesFindResponseUI } from '../common/ui'; +import type { CasesMetrics, CasesFindResponseUI } from '../common/ui'; import type { GroupAlertsByRule } from './client/helpers/group_alerts_by_rule'; import type { getUICapabilities } from './client/helpers/capabilities'; import type { AttachmentFramework } from './client/attachment_framework/types'; @@ -50,7 +50,6 @@ import type { CasesByAlertIDRequest, GetRelatedCasesByAlertResponse, CasesFindRequest, - CasesStatusRequest, CasesBulkGetRequest, CasesBulkGetResponse, CasesMetricsRequest, @@ -125,7 +124,6 @@ export interface CasesPublicStart { ) => Promise<GetRelatedCasesByAlertResponse>; cases: { find: (query: CasesFindRequest, signal?: AbortSignal) => Promise<CasesFindResponseUI>; - getCasesStatus: (query: CasesStatusRequest, signal?: AbortSignal) => Promise<CasesStatus>; getCasesMetrics: (query: CasesMetricsRequest, signal?: AbortSignal) => Promise<CasesMetrics>; bulkGet: (params: CasesBulkGetRequest, signal?: AbortSignal) => Promise<CasesBulkGetResponse>; }; diff --git a/x-pack/plugins/cases/server/client/cases/bulk_update.test.ts b/x-pack/plugins/cases/server/client/cases/bulk_update.test.ts index 755084d624b9..5cdd4c943b94 100644 --- a/x-pack/plugins/cases/server/client/cases/bulk_update.test.ts +++ b/x-pack/plugins/cases/server/client/cases/bulk_update.test.ts @@ -1512,6 +1512,59 @@ describe('update', () => { ); }); + it('throws an error if the case is not found', async () => { + clientArgsMock.services.caseService.getCases.mockResolvedValue({ saved_objects: [] }); + + await expect( + bulkUpdate( + { + cases: [ + { + id: mockCases[0].id, + version: mockCases[0].version ?? '', + status: CaseStatuses.open, + }, + ], + }, + clientArgsMock, + casesClientMock + ) + ).rejects.toThrow( + 'Failed to update case, ids: [{"id":"mock-id-1","version":"WzAsMV0="}]: Error: These cases mock-id-1 do not exist. Please check you have the correct ids.' + ); + }); + + it('throws an error if the case is not found and the SO clients returns an SO object', async () => { + clientArgsMock.services.caseService.getCases.mockResolvedValue({ + saved_objects: [ + { + type: 'cases', + id: 'mock-id-1', + references: [], + error: { error: 'Non found', message: 'Non found', statusCode: 404 }, + }, + ], + }); + + await expect( + bulkUpdate( + { + cases: [ + { + id: mockCases[0].id, + version: mockCases[0].version ?? '', + status: CaseStatuses.open, + }, + ], + }, + clientArgsMock, + casesClientMock + ) + ).rejects.toThrow( + 'Failed to update case, ids: [{"id":"mock-id-1","version":"WzAsMV0="}]: Error: These cases mock-id-1 do not exist. Please check you have the correct ids.' + ); + }); + describe('Validate max user actions per page', () => { beforeEach(() => { jest.clearAllMocks(); @@ -1681,6 +1734,7 @@ describe('update', () => { status: CaseStatuses.closed, }, }; + clientArgs.services.caseService.getCases.mockResolvedValue({ saved_objects: [closedCase] }); clientArgs.services.caseService.patchCases.mockResolvedValue({ @@ -1701,7 +1755,10 @@ describe('update', () => { casesClientMock ); - expect(clientArgs.authorization.ensureAuthorized).not.toThrow(); + expect(clientArgs.authorization.ensureAuthorized).toHaveBeenCalledWith({ + entities: [{ id: closedCase.id, owner: closedCase.attributes.owner }], + operation: [Operations.reopenCase, Operations.updateCase], + }); }); it('throws when user is not authorized to update case', async () => { @@ -1726,38 +1783,6 @@ describe('update', () => { `"Failed to update case, ids: [{\\"id\\":\\"mock-id-1\\",\\"version\\":\\"WzAsMV0=\\"}]: Error: Unauthorized"` ); }); - - it('throws when user is not authorized to reopen case', async () => { - const closedCase = { - ...mockCases[0], - attributes: { - ...mockCases[0].attributes, - status: CaseStatuses.closed, - }, - }; - clientArgs.services.caseService.getCases.mockResolvedValue({ saved_objects: [closedCase] }); - - const error = new Error('Unauthorized to reopen case'); - clientArgs.authorization.ensureAuthorized.mockRejectedValueOnce(error); // Reject reopenCase - - await expect( - bulkUpdate( - { - cases: [ - { - id: closedCase.id, - version: closedCase.version ?? '', - status: CaseStatuses.open, - }, - ], - }, - clientArgs, - casesClientMock - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Failed to update case, ids: [{\\"id\\":\\"mock-id-1\\",\\"version\\":\\"WzAsMV0=\\"}]: Error: Unauthorized to reopen case"` - ); - }); }); }); }); diff --git a/x-pack/plugins/cases/server/client/cases/bulk_update.ts b/x-pack/plugins/cases/server/client/cases/bulk_update.ts index 9a90168b858d..1f9dd5a7cb28 100644 --- a/x-pack/plugins/cases/server/client/cases/bulk_update.ts +++ b/x-pack/plugins/cases/server/client/cases/bulk_update.ts @@ -295,6 +295,7 @@ function partitionPatchRequest( ) { // Track cases that are closed and a user is attempting to reopen reopenedCases.push(reqCase); + casesToAuthorize.set(foundCase.id, { id: foundCase.id, owner: foundCase.attributes.owner }); } else { casesToAuthorize.set(foundCase.id, { id: foundCase.id, owner: foundCase.attributes.owner }); } diff --git a/x-pack/plugins/cases/server/client/metrics/all_cases/aggregations/status_counts.test.ts b/x-pack/plugins/cases/server/client/metrics/all_cases/aggregations/status_counts.test.ts new file mode 100644 index 000000000000..51d41eac1db4 --- /dev/null +++ b/x-pack/plugins/cases/server/client/metrics/all_cases/aggregations/status_counts.test.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CasePersistedStatus } from '../../../../common/types/case'; +import { StatusCounts } from './status_counts'; + +describe('StatusCounts', () => { + it('returns the correct aggregation', () => { + const agg = new StatusCounts(); + + expect(agg.build()).toEqual({ + status: { + terms: { + field: 'cases.attributes.status', + size: 3, + }, + }, + }); + }); + + it('formats the response correctly', async () => { + const agg = new StatusCounts(); + const res = agg.formatResponse({ + status: { + buckets: [ + { key: CasePersistedStatus.OPEN, doc_count: 2 }, + { key: CasePersistedStatus.IN_PROGRESS, doc_count: 1 }, + { key: CasePersistedStatus.CLOSED, doc_count: 3 }, + ], + }, + }); + expect(res).toEqual({ status: { open: 2, inProgress: 1, closed: 3 } }); + }); + + it('formats the response correctly if the res is undefined', () => { + const agg = new StatusCounts(); + // @ts-expect-error: testing for undefined response + const res = agg.formatResponse(); + expect(res).toEqual({ status: { open: 0, inProgress: 0, closed: 0 } }); + }); + + it('formats the response correctly if the mttr is not defined', () => { + const agg = new StatusCounts(); + const res = agg.formatResponse({}); + expect(res).toEqual({ status: { open: 0, inProgress: 0, closed: 0 } }); + }); + + it('formats the response correctly if the value is not defined', () => { + const agg = new StatusCounts(); + const res = agg.formatResponse({ status: {} }); + expect(res).toEqual({ status: { open: 0, inProgress: 0, closed: 0 } }); + }); + + it('gets the name correctly', () => { + const agg = new StatusCounts(); + expect(agg.getName()).toBe('status'); + }); +}); diff --git a/x-pack/plugins/cases/server/client/metrics/all_cases/aggregations/status_counts.ts b/x-pack/plugins/cases/server/client/metrics/all_cases/aggregations/status_counts.ts new file mode 100644 index 000000000000..f08bf8ac7750 --- /dev/null +++ b/x-pack/plugins/cases/server/client/metrics/all_cases/aggregations/status_counts.ts @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CasePersistedStatus } from '../../../../common/types/case'; +import { caseStatuses } from '../../../../../common/types/domain'; +import { CASE_SAVED_OBJECT } from '../../../../../common/constants'; +import type { CasesMetricsResponse } from '../../../../../common/types/api'; +import type { AggregationBuilder, AggregationResponse } from '../../types'; + +export class StatusCounts implements AggregationBuilder<CasesMetricsResponse> { + build() { + return { + status: { + terms: { + field: `${CASE_SAVED_OBJECT}.attributes.status`, + size: caseStatuses.length, + }, + }, + }; + } + + formatResponse(aggregations: AggregationResponse) { + const aggs = aggregations as StatusAggregate; + const buckets = aggs?.status?.buckets ?? []; + const status: Partial<Record<CasePersistedStatus, number>> = {}; + + for (const bucket of buckets) { + status[bucket.key] = bucket.doc_count; + } + + return { + status: { + open: status[CasePersistedStatus.OPEN] ?? 0, + inProgress: status[CasePersistedStatus.IN_PROGRESS] ?? 0, + closed: status[CasePersistedStatus.CLOSED] ?? 0, + }, + }; + } + + getName() { + return 'status'; + } +} + +type StatusAggregate = StatusAggregateResponse | undefined; + +interface StatusAggregateResponse { + status: { + buckets: Array<{ + key: CasePersistedStatus; + doc_count: number; + }>; + }; +} diff --git a/x-pack/plugins/cases/server/client/metrics/all_cases/status.test.ts b/x-pack/plugins/cases/server/client/metrics/all_cases/status.test.ts new file mode 100644 index 000000000000..ea49af2efee8 --- /dev/null +++ b/x-pack/plugins/cases/server/client/metrics/all_cases/status.test.ts @@ -0,0 +1,181 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Case } from '../../../../common/types/domain'; +import { CaseMetricsFeature } from '../../../../common/types/api'; +import { createCasesClientMock } from '../../mocks'; +import type { CasesClientArgs } from '../../types'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { createCaseServiceMock } from '../../../services/mocks'; +import { Status } from './status'; +import { CasePersistedStatus } from '../../../common/types/case'; + +const clientMock = createCasesClientMock(); +const caseService = createCaseServiceMock(); + +const logger = loggingSystemMock.createLogger(); +const getAuthorizationFilter = jest.fn().mockResolvedValue({}); + +const clientArgs = { + logger, + services: { + caseService, + }, + authorization: { getAuthorizationFilter }, +} as unknown as CasesClientArgs; + +const constructorOptions = { casesClient: clientMock, clientArgs }; + +describe('Status', () => { + beforeAll(() => { + getAuthorizationFilter.mockResolvedValue({}); + clientMock.cases.get.mockResolvedValue({ id: '' } as unknown as Case); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('returns empty values when no features set up', async () => { + caseService.executeAggregations.mockResolvedValue(undefined); + const handler = new Status(constructorOptions); + expect(await handler.compute()).toEqual({}); + }); + + it('returns null when aggregation returns undefined', async () => { + caseService.executeAggregations.mockResolvedValue(undefined); + const handler = new Status(constructorOptions); + handler.setupFeature(CaseMetricsFeature.STATUS); + + expect(await handler.compute()).toEqual({ status: { open: 0, inProgress: 0, closed: 0 } }); + }); + + it('returns null when aggregation returns empty object', async () => { + caseService.executeAggregations.mockResolvedValue({}); + const handler = new Status(constructorOptions); + handler.setupFeature(CaseMetricsFeature.STATUS); + + expect(await handler.compute()).toEqual({ status: { open: 0, inProgress: 0, closed: 0 } }); + }); + + it('returns null when aggregation returns empty status object', async () => { + caseService.executeAggregations.mockResolvedValue({ status: {} }); + const handler = new Status(constructorOptions); + handler.setupFeature(CaseMetricsFeature.STATUS); + + expect(await handler.compute()).toEqual({ status: { open: 0, inProgress: 0, closed: 0 } }); + }); + + it('returns values when there is a status value', async () => { + caseService.executeAggregations.mockResolvedValue({ + status: { + buckets: [ + { key: CasePersistedStatus.OPEN, doc_count: 2 }, + { key: CasePersistedStatus.IN_PROGRESS, doc_count: 1 }, + { key: CasePersistedStatus.CLOSED, doc_count: 3 }, + ], + }, + }); + const handler = new Status(constructorOptions); + handler.setupFeature(CaseMetricsFeature.STATUS); + + expect(await handler.compute()).toEqual({ status: { open: 2, inProgress: 1, closed: 3 } }); + }); + + it('passes the query options correctly', async () => { + caseService.executeAggregations.mockResolvedValue({ + status: { + buckets: [ + { key: CasePersistedStatus.OPEN, doc_count: 2 }, + { key: CasePersistedStatus.IN_PROGRESS, doc_count: 1 }, + { key: CasePersistedStatus.CLOSED, doc_count: 3 }, + ], + }, + }); + const handler = new Status({ + ...constructorOptions, + from: '2022-04-28T15:18:00.000Z', + to: '2022-04-28T15:22:00.000Z', + owner: 'cases', + }); + + handler.setupFeature(CaseMetricsFeature.STATUS); + await handler.compute(); + + expect(caseService.executeAggregations.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "aggregationBuilders": Array [ + StatusCounts {}, + ], + "options": Object { + "filter": Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.created_at", + }, + "gte", + Object { + "isQuoted": false, + "type": "literal", + "value": "2022-04-28T15:18:00.000Z", + }, + ], + "function": "range", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.created_at", + }, + "lte", + Object { + "isQuoted": false, + "type": "literal", + "value": "2022-04-28T15:22:00.000Z", + }, + ], + "function": "range", + "type": "function", + }, + ], + "function": "and", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "cases.attributes.owner", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "cases", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + }, + }, + } + `); + }); +}); diff --git a/x-pack/plugins/cases/server/client/metrics/all_cases/status.ts b/x-pack/plugins/cases/server/client/metrics/all_cases/status.ts new file mode 100644 index 000000000000..0a9b9ce403d3 --- /dev/null +++ b/x-pack/plugins/cases/server/client/metrics/all_cases/status.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CasesMetricsResponse } from '../../../../common/types/api'; +import { Operations } from '../../../authorization'; +import { createCaseError } from '../../../common/error'; +import { constructQueryOptions } from '../../utils'; +import { AllCasesAggregationHandler } from '../all_cases_aggregation_handler'; +import type { AggregationBuilder, AllCasesBaseHandlerCommonOptions } from '../types'; +import { StatusCounts } from './aggregations/status_counts'; + +export class Status extends AllCasesAggregationHandler { + constructor(options: AllCasesBaseHandlerCommonOptions) { + super( + options, + new Map<string, AggregationBuilder<CasesMetricsResponse>>([['status', new StatusCounts()]]) + ); + } + + public async compute(): Promise<CasesMetricsResponse> { + const { + authorization, + services: { caseService }, + logger, + } = this.options.clientArgs; + + try { + const { filter: authorizationFilter } = await authorization.getAuthorizationFilter( + Operations.getCasesMetrics + ); + + const caseQueryOptions = constructQueryOptions({ + from: this.from, + to: this.to, + owner: this.owner, + authorizationFilter, + }); + + const aggregationsResponse = await caseService.executeAggregations({ + aggregationBuilders: this.aggregationBuilders, + options: { filter: caseQueryOptions.filter }, + }); + + return this.formatResponse<CasesMetricsResponse>(aggregationsResponse); + } catch (error) { + throw createCaseError({ + message: `Failed to calculate cases status counts: ${error}`, + error, + logger, + }); + } + } +} diff --git a/x-pack/plugins/cases/server/client/metrics/utils.test.ts b/x-pack/plugins/cases/server/client/metrics/utils.test.ts index 1cdf7e59e95e..3248fd9b1e16 100644 --- a/x-pack/plugins/cases/server/client/metrics/utils.test.ts +++ b/x-pack/plugins/cases/server/client/metrics/utils.test.ts @@ -81,7 +81,7 @@ describe('utils', () => { ], [ { caseId: null }, - 'invalid features: [not-exists], please only provide valid features: [mttr]', + 'invalid features: [not-exists], please only provide valid features: [mttr, status]', ], ])('throws if the feature is not supported: %s', async (opts, msg) => { expect(() => diff --git a/x-pack/plugins/cases/server/client/metrics/utils.ts b/x-pack/plugins/cases/server/client/metrics/utils.ts index d20f64a2ff09..b2d9918a00de 100644 --- a/x-pack/plugins/cases/server/client/metrics/utils.ts +++ b/x-pack/plugins/cases/server/client/metrics/utils.ts @@ -16,6 +16,7 @@ import { Connectors } from './connectors'; import { Lifespan } from './lifespan'; import type { GetCaseMetricsParams, MetricsHandler } from './types'; import { MTTR } from './all_cases/mttr'; +import { Status } from './all_cases/status'; const isSingleCaseMetrics = ( params: GetCaseMetricsParams | CasesMetricsRequest @@ -33,7 +34,7 @@ export const buildHandlers = ( (ClassName) => new ClassName({ caseId: params.caseId, casesClient, clientArgs }) ); } else { - handlers = [MTTR].map( + handlers = [MTTR, Status].map( (ClassName) => new ClassName({ owner: params.owner, diff --git a/x-pack/plugins/cases/server/connectors/cases/index.test.ts b/x-pack/plugins/cases/server/connectors/cases/index.test.ts index 7b6d244d165b..c0480d694184 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.test.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.test.ts @@ -366,7 +366,7 @@ describe('getCasesConnectorType', () => { expect( adapter.getKibanaPrivileges?.({ - consumer: 'alerting', + consumer: 'not-exist', producer: AlertConsumers.LOGS, }) ).toEqual([ @@ -387,7 +387,7 @@ describe('getCasesConnectorType', () => { expect( adapter.getKibanaPrivileges?.({ - consumer: 'alerting', + consumer: 'alerts', producer: AlertConsumers.LOGS, }) ).toEqual([ diff --git a/x-pack/plugins/cases/server/connectors/cases/index.ts b/x-pack/plugins/cases/server/connectors/cases/index.ts index 07b4ab5e2955..b630de5209e2 100644 --- a/x-pack/plugins/cases/server/connectors/cases/index.ts +++ b/x-pack/plugins/cases/server/connectors/cases/index.ts @@ -95,7 +95,7 @@ export const getCasesConnectorAdapter = ({ return { connectorTypeId: CASES_CONNECTOR_ID, ruleActionParamsSchema: CasesConnectorRuleActionParamsSchema, - buildActionParams: ({ alerts, rule, params, spaceId, ruleUrl }) => { + buildActionParams: ({ alerts, rule, params, ruleUrl }) => { const caseAlerts = [...alerts.new.data, ...alerts.ongoing.data]; const owner = getOwnerFromRuleConsumerProducer({ diff --git a/x-pack/plugins/cases/server/connectors/index.ts b/x-pack/plugins/cases/server/connectors/index.ts index 0b0f201b46d4..56dcddfbee76 100644 --- a/x-pack/plugins/cases/server/connectors/index.ts +++ b/x-pack/plugins/cases/server/connectors/index.ts @@ -9,7 +9,7 @@ import type { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/act import type { KibanaRequest } from '@kbn/core-http-server'; import type { CoreSetup, SavedObjectsClientContract } from '@kbn/core/server'; import { SECURITY_EXTENSION_ID } from '@kbn/core/server'; -import type { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import type { CasesClient } from '../client'; import { getCasesConnectorAdapter, getCasesConnectorType } from './cases'; @@ -25,7 +25,7 @@ export function registerConnectorTypes({ isServerlessSecurity, }: { actions: ActionsPluginSetupContract; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; core: CoreSetup; getCasesClient: (request: KibanaRequest) => Promise<CasesClient>; getSpaceId: (request?: KibanaRequest) => string; diff --git a/x-pack/plugins/cases/server/plugin.ts b/x-pack/plugins/cases/server/plugin.ts index dfd4c013f0d5..5a4bd7b20b9d 100644 --- a/x-pack/plugins/cases/server/plugin.ts +++ b/x-pack/plugins/cases/server/plugin.ts @@ -131,7 +131,7 @@ export class CasePlugin registerRoutes({ router, routes: [ - ...getExternalRoutes({ isServerless }), + ...getExternalRoutes({ isServerless, docLinks: core.docLinks }), ...getInternalRoutes(this.userProfileService), ], logger: this.logger, diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts index 9687e73d1f7c..fcc1dbc3592a 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.test.ts @@ -6,17 +6,40 @@ */ import { getAllCommentsRoute } from './get_all_comment'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; describe('getAllCommentsRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('marks the endpoint internal in serverless', async () => { - const router = getAllCommentsRoute({ isServerless: true }); + const router = getAllCommentsRoute({ isServerless: true, docLinks }); expect(router.routerOptions?.access).toBe('internal'); }); it('marks the endpoint public in non-serverless', async () => { - const router = getAllCommentsRoute({ isServerless: false }); + const router = getAllCommentsRoute({ isServerless: false, docLinks }); expect(router.routerOptions?.access).toBe('public'); }); + + it('should be deprecated', () => { + const router = getAllCommentsRoute({ docLinks }); + expect(router.routerOptions?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201004$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201004\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/cases/{case_id}/comments/_find", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); + }); }); diff --git a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts index 0f84ed29dce2..f62a11caae77 100644 --- a/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts +++ b/x-pack/plugins/cases/server/routes/api/comments/get_all_comment.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; +import type { DocLinksServiceSetup } from '@kbn/core/server'; import { CASE_COMMENTS_URL } from '../../../../common/constants'; import { createCaseError } from '../../../common/error'; import { createCasesRoute } from '../create_cases_route'; @@ -15,7 +16,13 @@ import type { attachmentDomainV1 } from '../../../../common/types/domain'; /** * @deprecated since version 8.1.0 */ -export const getAllCommentsRoute = ({ isServerless }: { isServerless?: boolean }) => +export const getAllCommentsRoute = ({ + isServerless, + docLinks, +}: { + isServerless?: boolean; + docLinks: DocLinksServiceSetup; +}) => createCasesRoute({ method: 'get', path: CASE_COMMENTS_URL, @@ -32,8 +39,15 @@ export const getAllCommentsRoute = ({ isServerless }: { isServerless?: boolean } summary: `Gets all case comments`, tags: ['oas-tag:cases'], // 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.', - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.cases.legacyApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/cases/{case_id}/comments/_find', + }, + }, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/get_external_routes.ts b/x-pack/plugins/cases/server/routes/api/get_external_routes.ts index b68a1c32a93f..1f372c3964b1 100644 --- a/x-pack/plugins/cases/server/routes/api/get_external_routes.ts +++ b/x-pack/plugins/cases/server/routes/api/get_external_routes.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { DocLinksServiceSetup } from '@kbn/core/server'; import { getCasesByAlertIdRoute } from './cases/alerts/get_cases'; import { deleteCaseRoute } from './cases/delete_cases'; import { findCaseRoute } from './cases/find_cases'; @@ -32,7 +33,13 @@ import { getAllAlertsAttachedToCaseRoute } from './comments/get_alerts'; import { findUserActionsRoute } from './user_actions/find_user_actions'; import { postFileRoute } from './files/post_file'; -export const getExternalRoutes = ({ isServerless }: { isServerless?: boolean }) => +export const getExternalRoutes = ({ + isServerless, + docLinks, +}: { + isServerless?: boolean; + docLinks: DocLinksServiceSetup; +}) => [ deleteCaseRoute, findCaseRoute, @@ -42,8 +49,8 @@ export const getExternalRoutes = ({ isServerless }: { isServerless?: boolean }) postCaseRoute, pushCaseRoute, findUserActionsRoute, - getUserActionsRoute({ isServerless }), - getStatusRoute({ isServerless }), + getUserActionsRoute({ isServerless, docLinks }), + getStatusRoute({ isServerless, docLinks }), getCasesByAlertIdRoute, getReportersRoute, getTagsRoute, @@ -51,7 +58,7 @@ export const getExternalRoutes = ({ isServerless }: { isServerless?: boolean }) deleteAllCommentsRoute, findCommentsRoute, getCommentRoute, - getAllCommentsRoute({ isServerless }), + getAllCommentsRoute({ isServerless, docLinks }), patchCommentRoute, postCommentRoute, getCaseConfigureRoute, diff --git a/x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts b/x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts index 9376a46b7680..18cdbb90f0bd 100644 --- a/x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts +++ b/x-pack/plugins/cases/server/routes/api/stats/get_status.test.ts @@ -6,16 +6,33 @@ */ import { getStatusRoute } from './get_status'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; describe('getStatusRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('marks the endpoint internal in serverless', async () => { - const router = getStatusRoute({ isServerless: true }); + const router = getStatusRoute({ isServerless: true, docLinks }); expect(router.routerOptions?.access).toBe('internal'); + expect(router.routerOptions?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201004$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201004\\$/, + "reason": Object { + "type": "remove", + }, + "severity": "warning", + } + ` + ); }); it('marks the endpoint public in non-serverless', async () => { - const router = getStatusRoute({ isServerless: false }); + const router = getStatusRoute({ isServerless: false, docLinks }); expect(router.routerOptions?.access).toBe('public'); }); diff --git a/x-pack/plugins/cases/server/routes/api/stats/get_status.ts b/x-pack/plugins/cases/server/routes/api/stats/get_status.ts index 0889644f6a80..da8eb5750713 100644 --- a/x-pack/plugins/cases/server/routes/api/stats/get_status.ts +++ b/x-pack/plugins/cases/server/routes/api/stats/get_status.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { DocLinksServiceSetup } from '@kbn/core/server'; import type { CaseRoute } from '../types'; import { CASE_STATUS_URL } from '../../../../common/constants'; @@ -15,7 +16,13 @@ import type { statsApiV1 } from '../../../../common/types/api'; /** * @deprecated since version 8.1.0 */ -export const getStatusRoute = ({ isServerless }: { isServerless?: boolean }): CaseRoute => +export const getStatusRoute = ({ + isServerless, + docLinks, +}: { + isServerless?: boolean; + docLinks: DocLinksServiceSetup; +}): CaseRoute => createCasesRoute({ method: 'get', path: CASE_STATUS_URL, @@ -27,8 +34,13 @@ export const getStatusRoute = ({ isServerless }: { isServerless?: boolean }): Ca description: 'Returns the number of cases that are open, closed, and in progress in the default space.', // 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 you're seeking. - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.cases.legacyApiDeprecations, + severity: 'warning', + reason: { + type: 'remove', + }, + }, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts index d99b90c29bbb..cfc6531e8297 100644 --- a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts +++ b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.test.ts @@ -6,16 +6,35 @@ */ import { getUserActionsRoute } from './get_all_user_actions'; +import { docLinksServiceMock } from '@kbn/core/server/mocks'; describe('getUserActionsRoute', () => { + const docLinks = docLinksServiceMock.createSetupContract(); + it('marks the endpoint internal in serverless', async () => { - const router = getUserActionsRoute({ isServerless: true }); + const router = getUserActionsRoute({ isServerless: true, docLinks }); expect(router.routerOptions?.access).toBe('internal'); + expect(router.routerOptions?.deprecated).toMatchInlineSnapshot( + { + documentationUrl: expect.stringMatching(/#breaking-201004$/), + }, + ` + Object { + "documentationUrl": StringMatching /#breaking-201004\\$/, + "reason": Object { + "newApiMethod": "GET", + "newApiPath": "/api/cases/<case_id>/user_actions/_find", + "type": "migrate", + }, + "severity": "warning", + } + ` + ); }); it('marks the endpoint public in non-serverless', async () => { - const router = getUserActionsRoute({ isServerless: false }); + const router = getUserActionsRoute({ isServerless: false, docLinks }); expect(router.routerOptions?.access).toBe('public'); }); diff --git a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts index 19d7f1f8956a..c926a608868e 100644 --- a/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts +++ b/x-pack/plugins/cases/server/routes/api/user_actions/get_all_user_actions.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; +import type { DocLinksServiceSetup } from '@kbn/core/server'; import type { userActionApiV1 } from '../../../../common/types/api'; import { CASE_USER_ACTIONS_URL } from '../../../../common/constants'; import { createCaseError } from '../../../common/error'; @@ -15,7 +16,13 @@ import { createCasesRoute } from '../create_cases_route'; /** * @deprecated since version 8.1.0 */ -export const getUserActionsRoute = ({ isServerless }: { isServerless?: boolean }) => +export const getUserActionsRoute = ({ + isServerless, + docLinks, +}: { + isServerless?: boolean; + docLinks: DocLinksServiceSetup; +}) => createCasesRoute({ method: 'get', path: CASE_USER_ACTIONS_URL, @@ -31,8 +38,15 @@ export const getUserActionsRoute = ({ isServerless }: { isServerless?: boolean } description: `Returns all user activity for a case.`, // 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 case you're seeking. tags: ['oas-tag:cases'], - // @ts-expect-error TODO(https://github.com/elastic/kibana/issues/196095): Replace {RouteDeprecationInfo} - deprecated: true, + deprecated: { + documentationUrl: docLinks.links.cases.legacyApiDeprecations, + severity: 'warning', + reason: { + type: 'migrate', + newApiMethod: 'GET', + newApiPath: '/api/cases/<case_id>/user_actions/_find', + }, + }, }, handler: async ({ context, request, response }) => { try { diff --git a/x-pack/plugins/cases/server/types.ts b/x-pack/plugins/cases/server/types.ts index a51817c9d7e5..8606808e1c18 100644 --- a/x-pack/plugins/cases/server/types.ts +++ b/x-pack/plugins/cases/server/types.ts @@ -29,7 +29,7 @@ import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; import type { NotificationsPluginStart } from '@kbn/notifications-plugin/server'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; -import type { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { CasesClient } from './client'; import type { AttachmentFramework } from './attachment_framework/types'; @@ -37,7 +37,7 @@ import type { ExternalReferenceAttachmentTypeRegistry } from './attachment_frame import type { PersistableStateAttachmentTypeRegistry } from './attachment_framework/persistable_state_registry'; export interface CasesServerSetupDependencies { - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; actions: ActionsPluginSetup; lens: LensServerPluginSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/cases/tsconfig.json b/x-pack/plugins/cases/tsconfig.json index 48ca36a02b2b..2a77cb0e7b5a 100644 --- a/x-pack/plugins/cases/tsconfig.json +++ b/x-pack/plugins/cases/tsconfig.json @@ -74,6 +74,7 @@ "@kbn/core-logging-server-mocks", "@kbn/core-logging-browser-mocks", "@kbn/presentation-publishing", + "@kbn/securitysolution-rules", "@kbn/alerts-ui-shared", "@kbn/cloud-plugin", "@kbn/core-http-server-mocks", diff --git a/x-pack/plugins/cloud_security_posture/public/common/constants.ts b/x-pack/plugins/cloud_security_posture/public/common/constants.ts index ea3866cbe125..6c1761dd1a31 100644 --- a/x-pack/plugins/cloud_security_posture/public/common/constants.ts +++ b/x-pack/plugins/cloud_security_posture/public/common/constants.ts @@ -16,15 +16,11 @@ import { CLOUDBEAT_AZURE, CLOUDBEAT_VULN_MGMT_AWS, VULN_MGMT_POLICY_TEMPLATE, - CLOUDBEAT_VULN_MGMT_GCP, - CLOUDBEAT_VULN_MGMT_AZURE, CLOUDBEAT_AKS, CLOUDBEAT_GKE, } from '../../common/constants'; import eksLogo from '../assets/icons/cis_eks_logo.svg'; -import aksLogo from '../assets/icons/cis_aks_logo.svg'; -import gkeLogo from '../assets/icons/cis_gke_logo.svg'; import googleCloudLogo from '../assets/icons/google_cloud_logo.svg'; export const CSP_MOMENT_FORMAT = 'MMMM D, YYYY @ HH:mm:ss.SSS'; @@ -145,34 +141,6 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { }), testId: 'cisEksTestId', }, - { - type: CLOUDBEAT_AKS, - name: i18n.translate('xpack.csp.kspmIntegration.aksOption.nameTitle', { - defaultMessage: 'AKS', - }), - benchmark: i18n.translate('xpack.csp.kspmIntegration.aksOption.benchmarkTitle', { - defaultMessage: 'CIS AKS', - }), - disabled: true, - icon: aksLogo, - tooltip: i18n.translate('xpack.csp.kspmIntegration.aksOption.tooltipContent', { - defaultMessage: 'Azure Kubernetes Service - Coming soon', - }), - }, - { - type: CLOUDBEAT_GKE, - name: i18n.translate('xpack.csp.kspmIntegration.gkeOption.nameTitle', { - defaultMessage: 'GKE', - }), - benchmark: i18n.translate('xpack.csp.kspmIntegration.gkeOption.benchmarkTitle', { - defaultMessage: 'CIS GKE', - }), - disabled: true, - icon: gkeLogo, - tooltip: i18n.translate('xpack.csp.kspmIntegration.gkeOption.tooltipContent', { - defaultMessage: 'Google Kubernetes Engine - Coming soon', - }), - }, ], }, vuln_mgmt: { @@ -188,30 +156,6 @@ export const cloudPostureIntegrations: CloudPostureIntegrations = { icon: 'logoAWS', benchmark: 'N/A', // TODO: change benchmark to be optional }, - { - type: CLOUDBEAT_VULN_MGMT_GCP, - name: i18n.translate('xpack.csp.vulnMgmtIntegration.gcpOption.nameTitle', { - defaultMessage: 'GCP', - }), - disabled: true, - icon: googleCloudLogo, - tooltip: i18n.translate('xpack.csp.vulnMgmtIntegration.gcpOption.tooltipContent', { - defaultMessage: 'Coming soon', - }), - benchmark: 'N/A', // TODO: change benchmark to be optional - }, - { - type: CLOUDBEAT_VULN_MGMT_AZURE, - name: i18n.translate('xpack.csp.vulnMgmtIntegration.azureOption.nameTitle', { - defaultMessage: 'Azure', - }), - disabled: true, - icon: 'logoAzure', - tooltip: i18n.translate('xpack.csp.vulnMgmtIntegration.azureOption.tooltipContent', { - defaultMessage: 'Coming soon', - }), - benchmark: 'N/A', // TODO: change benchmark to be optional - }, ], }, }; diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx index 9d8deb5b9892..8d6f7292928e 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_form.tsx @@ -915,12 +915,16 @@ export const CspPolicyTemplateForm = memo<PackagePolicyReplaceDefineStepExtensio <PolicyTemplateInfo postureType={input.policy_template} /> <EuiSpacer size="l" /> {/* Defines the single enabled input of the active policy template */} - <PolicyTemplateInputSelector - input={input} - setInput={setEnabledPolicyInput} - disabled={isEditPage} - /> - <EuiSpacer size="l" /> + {input.type === 'cloudbeat/vuln_mgmt_aws' ? null : ( + <> + <PolicyTemplateInputSelector + input={input} + setInput={setEnabledPolicyInput} + disabled={isEditPage} + /> + <EuiSpacer size="l" /> + </> + )} {/* AWS account type selection box */} {input.type === 'cloudbeat/cis_aws' && ( @@ -954,8 +958,11 @@ export const CspPolicyTemplateForm = memo<PackagePolicyReplaceDefineStepExtensio /> )} - {/* Defines the name/description */} - <EuiSpacer size="l" /> + {input.type === 'cloudbeat/vuln_mgmt_aws' ? null : ( + <> + <EuiSpacer size="l" /> + </> + )} <IntegrationSettings fields={integrationFields} onChange={(field, value) => updatePolicy({ ...newPolicy, [field]: value })} diff --git a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx index 786f5526f496..c479b3250fb7 100644 --- a/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx +++ b/x-pack/plugins/cloud_security_posture/public/components/fleet_extensions/policy_template_selectors.tsx @@ -157,8 +157,16 @@ export const PolicyTemplateInfo = ({ postureType }: PolicyTemplateInfoProps) => </EuiCallOut> <EuiSpacer size="m" /> <FormattedMessage - id="xpack.csp.fleetIntegration.cnvm.configureIntegrationDescription" - defaultMessage="Select the cloud service provider (CSP) you want to monitor and then fill in the name and description to help identify this integration" + id="xpack.csp.fleetIntegration.cnvm.awsSupportText" + defaultMessage="We currently support <b>AWS(Amazon Web Services)</b> cloud provider" + values={{ + b: (chunks) => <b>{chunks}</b>, + }} + /> + <EuiSpacer size="s" /> + <FormattedMessage + id="xpack.csp.fleetIntegration.cnvm.chooseNameAndDescriptionText" + defaultMessage="Choose a name and description to help identify this integration" /> </> )} diff --git a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts index b72cb27088ed..52a7c8b55509 100644 --- a/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts +++ b/x-pack/plugins/cloud_security_posture/server/routes/benchmark_rules/bulk_action/bulk_action.ts @@ -31,7 +31,7 @@ import { bulkActionBenchmarkRulesHandler } from './v1'; // ... (additional benchmark rules) ]; } - + Response: { updated_benchmark_rules: CspBenchmarkRulesStates; Benchmark rules object that were affected @@ -67,7 +67,7 @@ export const defineBulkActionCspBenchmarkRulesRoute = (router: CspRouter) => const benchmarkRulesToUpdate = requestBody.rules; - const detectionRulesClient = (await context.alerting).getRulesClient(); + const detectionRulesClient = await (await context.alerting).getRulesClient(); const handlerResponse = await bulkActionBenchmarkRulesHandler( cspContext.soClient, diff --git a/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx b/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx index 462cbbbd9288..5f710c445471 100644 --- a/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx +++ b/x-pack/plugins/data_quality/public/routes/dataset_quality_details/context.tsx @@ -74,7 +74,10 @@ export function DatasetQualityDetailsContextProvider({ urlStateStorageContainer, datasetQualityDetailsState: state, }); - const breadcrumbValue = getBreadcrumbValue(state.dataStream, state.integration); + const breadcrumbValue = getBreadcrumbValue( + state.dataStream, + state.integration?.integration + ); setBreadcrumbs([{ text: breadcrumbValue }]); } ); diff --git a/x-pack/plugins/data_usage/common/constants.ts b/x-pack/plugins/data_usage/common/constants.ts new file mode 100644 index 000000000000..bf8b801cbf92 --- /dev/null +++ b/x-pack/plugins/data_usage/common/constants.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PLUGIN_ID = 'data_usage'; + +export const DEFAULT_SELECTED_OPTIONS = 50 as const; + +export const DATA_USAGE_API_ROUTE_PREFIX = '/api/data_usage/'; +export const DATA_USAGE_METRICS_API_ROUTE = `/internal${DATA_USAGE_API_ROUTE_PREFIX}metrics`; +export const DATA_USAGE_DATA_STREAMS_API_ROUTE = `/internal${DATA_USAGE_API_ROUTE_PREFIX}data_streams`; diff --git a/x-pack/plugins/data_usage/common/experimental_features.ts b/x-pack/plugins/data_usage/common/experimental_features.ts new file mode 100644 index 000000000000..bf01916bfff3 --- /dev/null +++ b/x-pack/plugins/data_usage/common/experimental_features.ts @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export type ServerlessExperimentalFeatures = Record< + keyof typeof allowedExperimentalValues, + boolean +>; + +/** + * A list of allowed values that can be used in `xpack.dataUsage.enableExperimental`. + * This object is then used to validate and parse the value entered. + */ +export const allowedExperimentalValues = Object.freeze({ + /** + * <Add a description of the feature here> + * + * [This is a fake feature key to showcase how to add a new serverless-specific experimental flag. + * It also prevents `allowedExperimentalValues` from being empty. It should be removed once a real feature is added.] + */ + dataUsageDisabled: false, +}); + +type ServerlessExperimentalConfigKeys = Array<keyof ServerlessExperimentalFeatures>; +type Mutable<T> = { -readonly [P in keyof T]: T[P] }; + +const allowedKeys = Object.keys( + allowedExperimentalValues +) as Readonly<ServerlessExperimentalConfigKeys>; + +export type ExperimentalFeatures = ServerlessExperimentalFeatures; +/** + * Parses the string value used in `xpack.dataUsage.enableExperimental` kibana configuration, + * which should be a string of values delimited by a comma (`,`) + * The generic experimental features are merged with the serverless values to ensure they are available + * + * @param configValue + * @throws DataUsagenvalidExperimentalValue + */ +export const parseExperimentalConfigValue = ( + configValue: string[] +): { features: ExperimentalFeatures; invalid: string[] } => { + const enabledFeatures: Mutable<Partial<ExperimentalFeatures>> = {}; + const invalidKeys: string[] = []; + + for (const value of configValue) { + if (!allowedKeys.includes(value as keyof ServerlessExperimentalFeatures)) { + invalidKeys.push(value); + } else { + enabledFeatures[value as keyof ServerlessExperimentalFeatures] = true; + } + } + + return { + features: { + ...allowedExperimentalValues, + ...enabledFeatures, + }, + invalid: invalidKeys, + }; +}; + +export const getExperimentalAllowedValues = (): string[] => [...allowedKeys]; diff --git a/x-pack/plugins/data_usage/common/index.ts b/x-pack/plugins/data_usage/common/index.ts index 8b952b13d4cc..63e34f872108 100644 --- a/x-pack/plugins/data_usage/common/index.ts +++ b/x-pack/plugins/data_usage/common/index.ts @@ -5,15 +5,10 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; - -export const PLUGIN_ID = 'data_usage'; -export const PLUGIN_NAME = i18n.translate('xpack.dataUsage.name', { - defaultMessage: 'Data Usage', -}); - -export const DEFAULT_SELECTED_OPTIONS = 50 as const; - -export const DATA_USAGE_API_ROUTE_PREFIX = '/api/data_usage/'; -export const DATA_USAGE_METRICS_API_ROUTE = `/internal${DATA_USAGE_API_ROUTE_PREFIX}metrics`; -export const DATA_USAGE_DATA_STREAMS_API_ROUTE = `/internal${DATA_USAGE_API_ROUTE_PREFIX}data_streams`; +export { + PLUGIN_ID, + DEFAULT_SELECTED_OPTIONS, + DATA_USAGE_API_ROUTE_PREFIX, + DATA_USAGE_METRICS_API_ROUTE, + DATA_USAGE_DATA_STREAMS_API_ROUTE, +} from './constants'; diff --git a/x-pack/plugins/data_usage/common/rest_types/data_streams.ts b/x-pack/plugins/data_usage/common/rest_types/data_streams.ts index 87af7e29eccb..17fc5fa5de05 100644 --- a/x-pack/plugins/data_usage/common/rest_types/data_streams.ts +++ b/x-pack/plugins/data_usage/common/rest_types/data_streams.ts @@ -7,6 +7,14 @@ import { schema, TypeOf } from '@kbn/config-schema'; +export const DataStreamsRequestSchema = { + query: schema.object({ + includeZeroStorage: schema.boolean({ defaultValue: false }), + }), +}; + +export type DataStreamsRequestQuery = TypeOf<typeof DataStreamsRequestSchema.query>; + export const DataStreamsResponseSchema = { body: () => schema.arrayOf( diff --git a/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts b/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts index ccc8158ecace..07130c84b6fd 100644 --- a/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts +++ b/x-pack/plugins/data_usage/common/rest_types/usage_metrics.ts @@ -39,6 +39,18 @@ export const METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP = Object.freeze<Record<Met search_rate: 'Search Rate', }); +export const METRIC_TYPE_UI_OPTIONS_VALUES_TO_API_MAP = Object.freeze<Record<string, MetricTypes>>({ + 'Data Retained in Storage': 'storage_retained', + 'Data Ingested': 'ingest_rate', + 'Search VCU': 'search_vcu', + 'Ingest VCU': 'ingest_vcu', + 'ML VCU': 'ml_vcu', + 'Index Latency': 'index_latency', + 'Index Rate': 'index_rate', + 'Search Latency': 'search_latency', + 'Search Rate': 'search_rate', +}); + // type guard for MetricTypes export const isMetricType = (type: string): type is MetricTypes => METRIC_TYPE_VALUES.includes(type as MetricTypes); diff --git a/x-pack/plugins/data_usage/common/test_utils/index.ts b/x-pack/plugins/data_usage/common/test_utils/index.ts new file mode 100644 index 000000000000..4e13a4048ee2 --- /dev/null +++ b/x-pack/plugins/data_usage/common/test_utils/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { TestProvider } from './test_provider'; +export { dataUsageTestQueryClientOptions } from './test_query_client_options'; diff --git a/x-pack/plugins/data_usage/common/test_utils/test_provider.tsx b/x-pack/plugins/data_usage/common/test_utils/test_provider.tsx new file mode 100644 index 000000000000..a3d154ba911e --- /dev/null +++ b/x-pack/plugins/data_usage/common/test_utils/test_provider.tsx @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo } from 'react'; +import { I18nProvider } from '@kbn/i18n-react'; + +export const TestProvider = memo(({ children }: { children?: React.ReactNode }) => { + return <I18nProvider>{children}</I18nProvider>; +}); diff --git a/x-pack/plugins/data_usage/common/utils.test.ts b/x-pack/plugins/data_usage/common/utils.test.ts new file mode 100644 index 000000000000..fc6b158c1caa --- /dev/null +++ b/x-pack/plugins/data_usage/common/utils.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { isDateRangeValid } from './utils'; + +describe('isDateRangeValid', () => { + describe('Valid ranges', () => { + it.each([ + ['both start and end date is `now`', { start: 'now', end: 'now' }], + ['start date is `now-10s` and end date is `now`', { start: 'now-10s', end: 'now' }], + ['bounded within the min and max date range', { start: 'now-8d', end: 'now-4s' }], + ])('should return true if %s', (_, { start, end }) => { + expect(isDateRangeValid({ start, end })).toBe(true); + }); + }); + + describe('Invalid ranges', () => { + it.each([ + ['starts before the min date', { start: 'now-11d', end: 'now-5s' }], + ['ends after the max date', { start: 'now-9d', end: 'now+2s' }], + [ + 'end date is before the start date even when both are within min and max date range', + { start: 'now-3s', end: 'now-10s' }, + ], + ])('should return false if the date range %s', (_, { start, end }) => { + expect(isDateRangeValid({ start, end })).toBe(false); + }); + }); +}); diff --git a/x-pack/plugins/data_usage/common/utils.ts b/x-pack/plugins/data_usage/common/utils.ts new file mode 100644 index 000000000000..3fd7240153d4 --- /dev/null +++ b/x-pack/plugins/data_usage/common/utils.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import dateMath from '@kbn/datemath'; + +export const DEFAULT_DATE_RANGE_OPTIONS = Object.freeze({ + autoRefreshOptions: { + enabled: false, + duration: 10000, + }, + startDate: 'now-24h/h', + endDate: 'now', + maxDate: 'now+1s', + minDate: 'now-9d', + recentlyUsedDateRanges: [], +}); + +export const momentDateParser = (date: string) => dateMath.parse(date); +export const transformToUTCtime = ({ + start, + end, + isISOString = false, +}: { + start: string; + end: string; + isISOString?: boolean; +}) => { + const utcOffset = momentDateParser(start)?.utcOffset() ?? 0; + const utcStart = momentDateParser(start)?.utc().add(utcOffset, 'm'); + const utcEnd = momentDateParser(end)?.utc().add(utcOffset, 'm'); + return { + start: isISOString ? utcStart?.toISOString() : momentDateParser(start), + end: isISOString ? utcEnd?.toISOString() : momentDateParser(end), + }; +}; + +export const isDateRangeValid = ({ start, end }: { start: string; end: string }): boolean => { + const startDate = momentDateParser(start); + const endDate = momentDateParser(end); + + if (!startDate || !endDate) { + return false; + } + const minDate = momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.minDate); + const maxDate = momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.maxDate); + return ( + startDate.isSameOrAfter(minDate, 's') && + endDate.isSameOrBefore(maxDate, 's') && + startDate <= endDate + ); +}; diff --git a/x-pack/plugins/data_usage/public/app/components/assets/illustration_product_no_results_magnifying_glass.svg b/x-pack/plugins/data_usage/public/app/components/assets/illustration_product_no_results_magnifying_glass.svg new file mode 100644 index 000000000000..4329041f84a9 --- /dev/null +++ b/x-pack/plugins/data_usage/public/app/components/assets/illustration_product_no_results_magnifying_glass.svg @@ -0,0 +1,32 @@ +<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 200 148"> + <g fill="#e6ebf2"> + <path d="M66.493 121.253a.664.664 0 0 0 .373-.78.945.945 0 0 0-1.1-.386.686.686 0 0 0 .208 1.253c.178.041.364.01.519-.087zM46.666 68.12c.12-.113.373-.44.287-.6-.087-.16-.514-.046-.667 0-.153.047-.22.267-.073.454.146.186.3.293.453.146zm-1.26 13.006a.427.427 0 0 0-.58-.153c-.247.107-.46.253-.46.573 0 .947.173 1.16 1.1 1.334h.067a1.205 1.205 0 0 0-.367 0 .286.286 0 0 0-.2.426.34.34 0 0 0 .487.22.907.907 0 0 0 .273-.36.4.4 0 0 0 .54.147.474.474 0 0 0 .073-.767c-.226-.22-.146-.426-.12-.666.707.046 1-.267.88-.867a1.716 1.716 0 0 0-.053-.173c-.147-.394-.38-.487-.753-.3-.374.186-.6.326-.487.873-.2-.133-.333-.186-.4-.286zM45.42 80a.386.386 0 0 0 .166-.52.486.486 0 0 0-.507-.346.552.552 0 0 0-.46.666.58.58 0 0 0 .8.2zm59.546 54.133a.7.7 0 0 0 .2.914.71.71 0 0 0 .887-1.107 1.035 1.035 0 0 0-1.087.193zM47.08 69.04a.449.449 0 0 0-.22.666.5.5 0 0 0 .626.18.54.54 0 0 0 .167-.666.427.427 0 0 0-.574-.18zM46.987 64c.12-.086.346-.4.28-.507-.067-.106-.427-.126-.58-.1-.154.027-.247.26-.14.487a.266.266 0 0 0 .44.12zm4.486 44a.772.772 0 0 0-.107 1.033.892.892 0 0 0 1.2-.087.6.6 0 0 0 .203-.453.602.602 0 0 0-.203-.453.73.73 0 0 0-1.093-.04zm1.54-7.846a.177.177 0 0 0 .063-.048.17.17 0 0 0 .03-.15.168.168 0 0 0-.04-.069.16.16 0 0 0-.266-.053.166.166 0 0 0-.047.273.16.16 0 0 0 .119.087.16.16 0 0 0 .141-.04zm-3.28-8.374c.072.19.16.373.267.546-.05.084-.094.171-.133.26a.92.92 0 0 0 .173 1 1.02 1.02 0 0 0 .9.174 1.22 1.22 0 0 0 0 .5l.313.146a58.42 58.42 0 0 1-1.106-3.42.775.775 0 0 0-.18.094.607.607 0 0 0-.234.7zm2.807 10.347a.234.234 0 0 0 .28-.114.319.319 0 0 0-.113-.34c-.094-.06-.24.06-.287.154-.047.093.007.266.12.3zm.193 4.286a.664.664 0 0 0 .106-.713.354.354 0 0 0-.102-.104.34.34 0 0 0-.282-.043.35.35 0 0 0-.129.067c-.313.213-.453.447-.36.613a.776.776 0 0 0 .767.18zm.32-2.286a.795.795 0 0 0-.073-.947.801.801 0 0 0-.84.1.533.533 0 0 0 0 .667c.353.32.713.393.913.18zM44.5 73.374a.86.86 0 0 0-.394 1.08.873.873 0 0 0 1.033.5 1.12 1.12 0 0 0 .467-1.247.872.872 0 0 0-1.107-.333zm9.886 28.086c-.173-.326-.34-.666-.507-.986-.253.16-.353.393-.253.593a1.04 1.04 0 0 0 .76.393zm.794 4.713c-.12.26-.22.527.087.667.306.14.473-.034.6-.274a.51.51 0 0 0-.464-.427.512.512 0 0 0-.223.034zm-4.14-10.84c-.12.047-.167.12-.114.247.053.127.127.16.253.113a.174.174 0 0 0 .114-.24c-.047-.12-.12-.173-.254-.12zm4.147 12.867a.357.357 0 0 0-.052.42.357.357 0 0 0 .098.113.442.442 0 0 0 .516.11.435.435 0 0 0 .151-.11.4.4 0 0 0-.04-.587.463.463 0 0 0-.528-.065.462.462 0 0 0-.145.119zm.499 2.707a.482.482 0 0 0 .667 0 .442.442 0 0 0 0-.6.397.397 0 0 0-.444-.144.382.382 0 0 0-.143.084.434.434 0 0 0-.19.312.44.44 0 0 0 .11.348zm-1.353-6.241a.345.345 0 0 0-.058.282.34.34 0 0 0 .178.225c.313.213.586.253.666.107a.77.77 0 0 0-.12-.774.67.67 0 0 0-.666.16zM37.22 85.493c-.16-.3-.353-.293-.513-.207s-.3.26-.16.434c.14.173.34.22.446.166.107-.053.174-.286.227-.393zm1.087 7.047a.666.666 0 0 0-.347.747.74.74 0 0 0 .813.38c.26-.107.334-.527.16-.907a.52.52 0 0 0-.626-.22zm-.387-3.367c-.274-.106-.514-.273-.747 0a.4.4 0 0 0 0 .554.534.534 0 0 0 .406.18c.334-.087.38-.367.34-.734zM45 100.606c-.26 0-.48.56-.3.794.18.233.6.293.74.106.14-.186-.174-.84-.44-.9zm-1.786-5.046-.207.22a4.215 4.215 0 0 0-.407-.373.434.434 0 0 0-.666 0 .667.667 0 0 0-.174.78.6.6 0 0 0 .667.366c.201-.018.4-.059.593-.12.067.072.14.136.22.194a.913.913 0 0 0 1.013.073 1.061 1.061 0 0 0 .387-.96.534.534 0 0 0-.2-.347.833.833 0 0 0-1.227.167zm2.959 9.774a.352.352 0 0 0-.118.266.358.358 0 0 0 .118.267.32.32 0 0 0 .104.083.323.323 0 0 0 .261.018.311.311 0 0 0 .115-.068.35.35 0 0 0 .1-.513.398.398 0 0 0-.58-.053zm-5.84-19.148c0-.353-.213-.493-.567-.5-.193-.826-.666-.926-1.333-.313a.838.838 0 0 1-.167-.06.4.4 0 0 0-.533.113.433.433 0 0 0-.087.5c.154.467.36.567.82.38l1.04-.4c.287.62.367.64.827.28zm1 2.614a.787.787 0 1 0-1.334.747.874.874 0 0 0 1.187.147.614.614 0 0 0 .147-.894zm.614 3.2a.8.8 0 0 0-.94-.333.727.727 0 0 0-.26.9c.146.307.426.367.82.173.266-.133.473-.533.38-.74zm.893 5.94a.426.426 0 0 0-.467.273.387.387 0 0 0 .533.42.4.4 0 0 0-.067-.693zm1.5-31.093c.1-.047.093-.3.053-.367s-.187-.167-.287-.113a.26.26 0 0 0-.107.3c.047.073.247.233.34.18zm-1.294 8.893c.107.107.394.354.54.26.147-.093.04-.486 0-.6-.04-.113-.286-.086-.406-.04a.22.22 0 0 0-.134.38zm-.292-3.78a.76.76 0 0 0 .173-.98.713.713 0 0 0-1.18.78.726.726 0 0 0 1.007.2zM41.22 84.873c-.227.114-.307.3-.147.48s.313.46.56.327c.247-.133.113-.487.087-.667-.027-.18-.294-.246-.5-.14zm-.72-3.066a.926.926 0 0 0-.247 1.086.808.808 0 0 0 1.167.18.667.667 0 0 0 .293-.96.907.907 0 0 0-1.213-.306zm4.586-9.714a.76.76 0 0 0 .34-.88.52.52 0 0 0-.667-.246.667.667 0 0 0-.26.84.448.448 0 0 0 .587.286zm.5-2.367a.14.14 0 0 0 .033-.18c0-.04-.14-.046-.166 0a.123.123 0 0 0 .04.224.123.123 0 0 0 .093-.017zm-1.88 7.7a.667.667 0 0 0 .86.134c.387-.22.5-.467.34-.767a.774.774 0 0 0-.926-.333.847.847 0 0 0-.273.966zM40.8 74.787c.12-.113.386-.447.293-.587-.094-.14-.494-.086-.667-.046-.173.04-.213.346-.093.52.12.173.333.26.466.113zm-2.447-1.86c0 .04.18.133.22.106s.247-.14.2-.286c-.046-.147-.266-.12-.3-.087a.4.4 0 0 0-.12.267zm.247 3.553a.436.436 0 0 0 .8-.347.573.573 0 0 0-.627-.233.453.453 0 0 0-.173.58zm2.327-10.587c.073-.04.073-.207.053-.3s-.173-.193-.287-.133-.053.273 0 .36a.24.24 0 0 0 .234.073zM38 71.1a.466.466 0 0 0 .513-.333.346.346 0 0 0-.14-.467c-.293-.193-.52-.046-.767.16.06.3.047.607.394.64zm2.76 8.3a.7.7 0 0 0 .146-.827.667.667 0 0 0-.82.127.5.5 0 0 0 .667.666zm-2.387 1.266c.287-.16.367-.38.234-.666a.78.78 0 0 0-.954-.407.667.667 0 0 0-.126.873.627.627 0 0 0 .846.2zm7.233 27.268c-.133 0-.287.266-.413.433a.184.184 0 0 0-.047.061.184.184 0 0 0 0 .151.185.185 0 0 0 .047.061.56.56 0 0 0 .666-.1.404.404 0 0 0-.253-.606zm33.627 20.193c-.126-.254-.466-.32-.846-.154-.28.134-.487.507-.394.72a.847.847 0 0 0 .914.42.548.548 0 0 0 .12-.066.763.763 0 0 0 0 .386c.1.329.31.614.593.807.1.077.177.181.22.3a.584.584 0 0 0 .887.433.28.28 0 0 0 .033.167.523.523 0 0 0 .667.113.531.531 0 0 0 .313-.666.46.46 0 0 0-.277-.219.468.468 0 0 0-.35.045.86.86 0 0 0-.173-.42.832.832 0 0 1-.227-.586c0-.36-.253-.58-.5-.78a.827.827 0 0 0-.88.04l-.066.06a.786.786 0 0 0-.034-.6zm9.973 5.979c.1.2.414.14.554.114a.305.305 0 0 0 .225-.134.3.3 0 0 0 .035-.26c-.06-.213-.34-.4-.5-.28s-.414.36-.314.56zm4.247-1.332a.605.605 0 0 0-.287.866c.173.354.513.52.773.374a.893.893 0 0 0 .367-1.054.667.667 0 0 0-.853-.186zm.16 2.966c-.12.193.093.427.193.533a.292.292 0 0 0 .364.085.292.292 0 0 0 .103-.085c.146-.166.16-.5 0-.573s-.54-.147-.66.04zm-3.42-4.167a.447.447 0 0 0-.477-.299.459.459 0 0 0-.19.066.472.472 0 0 0 0 .833.269.269 0 0 0 .18.28c.142.02.285.02.427 0a.465.465 0 0 0 .033-.426.49.49 0 0 0 .027-.454zM76 127.926c.34-.167.486-.467.353-.72a.91.91 0 0 0-1.053-.373.668.668 0 0 0-.154.82.575.575 0 0 0 .853.273zm-9.22-3.706a.757.757 0 0 0 .32.14c.28-.146.373-.406.233-.546a.544.544 0 0 0-.406-.147c-.194.033-.26.4-.147.553zm4.733-.807c.3-.106.553-.446.48-.666-.147-.46-.667-.454-.92-.44-.254.013-.38.613-.14.96a.439.439 0 0 0 .58.146zm42.58 9.307c-.3.113-.22.366-.167.606.26.12.494.14.667-.126a.384.384 0 0 0-.053-.36.504.504 0 0 0-.447-.12zm-.533 1.873c.113.073.206.167.353.147s.2-.234.087-.4a.723.723 0 0 0-.474-.28.197.197 0 0 0-.096.012.211.211 0 0 0-.137.234.459.459 0 0 0 .267.287zm2.513-4.133c.353.047.493-.187.626-.487-.093-.113-.173-.233-.26-.32l-.666.147a.62.62 0 0 0-.054.3.355.355 0 0 0 .354.36zm5.14-1.587c.033 0 .14 0 .16-.053.02-.054 0-.127 0-.16a.14.14 0 0 0-.194 0c-.023.033-.033.073-.027.113s.028.076.061.1zm-6.633 3.247a.815.815 0 0 0 .754-.786.843.843 0 0 0-.898-.657.84.84 0 0 0-.762.81c-.034.347.44.6.906.633zm2.98 2.966a.256.256 0 0 0 0 .354c.133.126.28-.06.347-.127.066-.067 0-.227-.034-.24a.342.342 0 0 0-.313.013zm.473-4.626c0-.147 0-.433-.114-.473a.475.475 0 0 0-.407.146c-.06.087-.053.44.054.507.106.067.433-.113.467-.18zm-10.32 3.86a.421.421 0 0 0-.031.346.44.44 0 0 0 .237.254c.194.093.407.2.534 0 .206-.334.186-.62 0-.76a.483.483 0 0 0-.408-.093.498.498 0 0 0-.332.253zm-.38-2.113a.663.663 0 0 0-.007.433.66.66 0 0 0 .26.347.396.396 0 0 0 .318.035.393.393 0 0 0 .236-.215c.233-.354.253-.627.073-.767a.759.759 0 0 0-.88.167zm-3.44 4.06a.38.38 0 0 0 .14.56.517.517 0 0 0 .667-.134.502.502 0 0 0-.167-.633.452.452 0 0 0-.364-.036.464.464 0 0 0-.276.243zM112 131.2a.724.724 0 0 0 .967-.187.945.945 0 0 0 .046-.666l-1.4.213a.888.888 0 0 0 .387.64zm-1.747 1.993a.424.424 0 0 0 .506-.035.403.403 0 0 0 .107-.145c.267-.413.254-.7-.046-.893a.75.75 0 0 0-.854.213.857.857 0 0 0 .287.86zM50.88 97.454a.18.18 0 0 1 0 .113.899.899 0 0 0-.16.08c-.074-.1-.227-.12-.487.04a.466.466 0 0 0-.233.666.667.667 0 0 0 .666.367c.05.056.115.097.187.12.247.074.487.254.667.154a.447.447 0 0 0 .246-.314.666.666 0 0 0 .087-.426 1.094 1.094 0 0 0-.173-.38 1.134 1.134 0 0 0 0-.214c-.034-.266-.094-.666-.46-.613-.367.053-.367.287-.34.407zm-4.054-24.248c-.3 0-.613 0-.613.434a.48.48 0 0 0 .346.5.348.348 0 0 0 .287 0c.147-.167.267-.36.413-.56.235-.005.464-.07.667-.187v-.887a.92.92 0 0 0-.6-.26c-.4-.02-.5.18-.5.96zm1.08 11.214a.56.56 0 0 0 .667.174l.04-.047a35.31 35.31 0 0 1-.154-.84.667.667 0 0 0-.426 0 .489.489 0 0 0-.127.713zm-.866-7.933a.394.394 0 0 0 .306-.2c.094-.28-.066-.454-.346-.56-.2.126-.447.246-.334.546a.507.507 0 0 0 .374.214zm2.206 17.407c.087.153.207.3.427.213a.493.493 0 0 0 .186-.667 1.467 1.467 0 0 0-.486 0c-.2.074-.227.274-.127.454zm-.179-7.061a.587.587 0 0 0 .147.667c-.047-.24-.107-.454-.147-.667zm-.401 3.38a.833.833 0 0 0 1.047-.227.667.667 0 0 0 .053-.313c-.04-.14-.087-.273-.12-.413a.72.72 0 0 0-.4-.354.847.847 0 0 0-.993.267c-.22.267.026.747.413 1.04zm-1.14-12.593c-.406.093-.873.247-.973.74a1.14 1.14 0 0 0 1.14 1.267.386.386 0 0 1 .353.166 56.95 56.95 0 0 1-.166-3.213 6.074 6.074 0 0 0-.354 1.04zm3.407 24.806a.15.15 0 0 0 .055-.043.156.156 0 0 0 .034-.132.159.159 0 0 0-.029-.065c-.06-.073-.187-.213-.333-.153-.147.06-.06.287 0 .32s.153.147.273.073zm-.267-7.093a.42.42 0 0 0-.38-.38c-.233 0-.3.14-.28.62a.407.407 0 0 0 .66-.24zm-1.066 5.82a.242.242 0 0 0 .046.093.443.443 0 0 0 .36.174c.127 0 .254.066.434 0a.955.955 0 0 0 .52-.667.719.719 0 0 0-.287-.667.614.614 0 0 0-.62-.033.725.725 0 0 0-.427.533.28.28 0 0 0-.193 0c-.307.074-.667.067-.907.38l.04.454c-.313.28-.466.666-.326.86a.42.42 0 0 0 .5.16c.366-.12.446-.26.413-.72.18-.24.313-.387.447-.567zm-.76 3.514c.246-.24.22-.527-.08-.82a.454.454 0 0 0-.312-.195.456.456 0 0 0-.355.095.971.971 0 0 0-.12.987c.273.28.567.253.867-.067zm13.9 14.6c0-.134-.247-.174-.32-.154a.308.308 0 0 0-.2.24c0 .107.18.174.266.174s.267-.134.254-.26zM48.287 95.7a.16.16 0 0 0-.043.191.16.16 0 0 0 .043.055c.06.067.233.22.333.134s0-.28 0-.314c0-.033-.213-.16-.333-.066z"/> + <path d="M48.147 96.866c.113 0 .28.167.16.207s-.187.187-.094.493a.476.476 0 0 0 .587.387.7.7 0 0 0 .52-.833c-.08-.38-.306-.4-.333-.667s-.18-.313-.447-.353-.667-.074-.707.3c-.04.373.2.466.314.466zm.173-10.7c.266-.153.273-.553 0-.966a.606.606 0 0 0-.707-.14.872.872 0 0 0-.273.806.847.847 0 0 0 .98.3zm-1.327 2.187a1.333 1.333 0 0 0-1.333-.42.854.854 0 0 0-.267 1.12.993.993 0 0 0 1.167.373.833.833 0 0 0 .433-1.073zM42.96 78.92a1.494 1.494 0 0 0 0-.527c-.073-.247-.433-.293-.667-.14a.413.413 0 0 0-.093.587.553.553 0 0 0 .76.08zm2.62 17.88c-.06.227.066.327.533.42a.4.4 0 0 0-.067-.666.42.42 0 0 0-.467.246zm-3.513-16.387a.5.5 0 0 0 .666.14.48.48 0 0 0 .134-.626.507.507 0 0 0-.667-.134.46.46 0 0 0-.133.62zm3.966 12.541a.408.408 0 0 0-.52.3.533.533 0 0 0 .113.466c.26.207.52.074.747-.146-.007-.24-.04-.54-.34-.62zm-.7-1.887c.24-.207.12-.467 0-.747-.293 0-.6-.1-.726.247a.259.259 0 0 0 0 .1 1.067 1.067 0 0 0-.827.046.444.444 0 0 0-.113.627.667.667 0 0 0 .846.333.74.74 0 0 0 .36-.513.427.427 0 0 0 .46-.093zm2.141 2.306c.666.72 1.253.347 1.653-.16a.966.966 0 0 0 .213-.593 1 1 0 0 0-.38-.74c-.247-.227-.253-.567-.567-.667a1.373 1.373 0 0 0-1.593.467 1.106 1.106 0 0 0-.213 1.04c.127.36.62.347.887.653zm-3.947-10.6c.28-.16.32-.466.106-.846-.213-.38-.46-.434-.666-.294a1.172 1.172 0 0 0-.36.947.667.667 0 0 0 .92.193zm1.926 4.22a.666.666 0 0 0 .206-.666.46.46 0 0 0-.666-.2.512.512 0 0 0-.227.62.726.726 0 0 0 .687.246zm-1.62 5.674a.807.807 0 0 0-.38.98.82.82 0 0 0 1.067.273.567.567 0 0 0 .193-.78c-.153-.32-.633-.573-.88-.473zm-.693-6.634c.113.213.78.287 1.047.113a.667.667 0 0 0 .16-.706.667.667 0 0 0-.847-.327.76.76 0 0 0-.36.92zm1.026 3.014a.806.806 0 0 0 .373-1.22.9.9 0 0 0-1.213-.3 1.073 1.073 0 0 0-.207 1.273.732.732 0 0 0 1.047.247zm49.127 45.106c.033-.234-.38-.667-.667-.707-.287-.04-.527-.08-.667.253-.14.334-.226.474-.346.714a.392.392 0 0 0-.156.31.386.386 0 0 0 .156.31.497.497 0 0 0 .666-.047c.12-.118.26-.213.414-.28a.67.67 0 0 0 .6-.553zm5.013.147v.033c-.067.267.18.353.373.433.267-.113.414-.293.294-.56-.04-.093-.227-.206-.307-.18l-.153.08a.368.368 0 0 0 .04-.133.404.404 0 0 0-.374-.321.408.408 0 0 0-.173.028.387.387 0 0 0-.187.306.472.472 0 0 0 .22.36.31.31 0 0 0 .267-.046zm-2.026 2.88a.449.449 0 0 0 .042-.529.444.444 0 0 0-.129-.137.552.552 0 0 0-.666.073.456.456 0 0 0 .113.667.432.432 0 0 0 .337.109.427.427 0 0 0 .303-.183zm1.393-5.314a.406.406 0 0 0-.468-.029.407.407 0 0 0-.119.116.441.441 0 0 0 .04.667.468.468 0 0 0 .35.098.476.476 0 0 0 .317-.178.508.508 0 0 0-.12-.674zm-.713 6.801a.674.674 0 0 0-.94.126.672.672 0 0 0 .127.94.91.91 0 0 0 1.1-.24c.16-.206.006-.64-.287-.826zm-1.287-3.22a.452.452 0 0 0 .344.045.446.446 0 0 0 .27-.218.46.46 0 0 0 .086-.362.46.46 0 0 0-.214-.305.55.55 0 0 0-.666.213.493.493 0 0 0 .18.627zm-1.806 4.46c-.06.173-.14.606 0 .713s.493-.187.5-.253c0-.2.08-.46-.1-.607s-.367.06-.4.147z"/> + <path d="M95.72 132.54a.7.7 0 0 0 .48-.286.919.919 0 0 0 .153-.74c1.378.16 2.76.278 4.146.353-.033.113-.053.227-.08.347-.284.05-.549.177-.766.366l-.187-.1a.846.846 0 0 0-.947.5.853.853 0 0 0 .747.914.886.886 0 0 0 .667-.207l.093.08c.38.3.713.14 1.033-.127.194.18.32.474.667.287a.433.433 0 0 0 .22-.513c-.1-.367-.407-.3-.667-.267-.06-.16-.113-.307-.173-.453l.58-.254c.031-.162.047-.327.047-.493l1.62.04h.066a.67.67 0 0 0 .2 0h1.467a.667.667 0 0 0 .32.627.823.823 0 0 0 1.2-.287.663.663 0 0 0 .093-.387l1.147-.053a.505.505 0 0 0 .507-.507.507.507 0 0 0-.507-.506c-12.3.12-24.54-2.667-34.913-9.414a57.165 57.165 0 0 1-15.814-15.646 30.06 30.06 0 0 1-2.213-3.62.197.197 0 0 0-.074-.153c-.023-.019-.05-.032-.079-.039s-.058-.007-.087-.002l-.18-.313a.816.816 0 0 0-.6.087.59.59 0 0 0-.136.659.59.59 0 0 0 .136.194.441.441 0 0 0 .667.107l.06.14a.383.383 0 0 0 .086.587c.06.032.127.046.194.039a30.134 30.134 0 0 0 1.58 2.967.491.491 0 0 0 .126.413.406.406 0 0 0 .214.12c.133.22.273.447.413.667-.167.267-.133.507.153.787a.806.806 0 0 0 .54.233c.12.167.234.347.36.513a.872.872 0 0 0-.533.207c-.413.327-.353 1.013 0 1.127.353.113.533-.074.6.053.067.127.08.447.333.5s.46-.28.614-.513c.333.444.673.889 1.02 1.333a.6.6 0 0 0 .073.5.717.717 0 0 0 .527.227c.067.073.127.153.193.233.42.5.86 1 1.333 1.487a.579.579 0 0 0-.34.153.667.667 0 0 0 .12.827.58.58 0 0 0 .9 0 .592.592 0 0 0 .094-.134c.8.84 1.633 1.647 2.486 2.434a.477.477 0 0 0 0 .413.66.66 0 0 0 .487.247.327.327 0 0 0 .14-.06c.514.453 1.04.893 1.567 1.333a1.101 1.101 0 0 0 0 .947.763.763 0 0 0 .98.44.958.958 0 0 0 .4-.314c.36.28.733.554 1.1.82.055.07.13.123.213.154a41.756 41.756 0 0 0 3.74 2.446.5.5 0 0 0 0 .28.797.797 0 0 0 .967.407.21.21 0 0 0 .08-.073c.493.28.986.553 1.486.813a.513.513 0 0 0 .047.267c.213.473.753.78 1.113.626a.71.71 0 0 0 .234-.173 34.4 34.4 0 0 0 2.073.96.491.491 0 0 0 .567.247c.726.313 1.46.613 2.2.893 0 .253.273.3.52.26v-.053l.98.353a.62.62 0 0 0 0 .213.445.445 0 0 0 .587.254l.08-.04a.853.853 0 0 0 .727.52h.06a.785.785 0 0 0-.06.873c.052.12.124.23.213.327a.377.377 0 0 0-.267.186.602.602 0 0 0 .313.8.763.763 0 0 0 .814-.16.604.604 0 0 0 0-.726.86.86 0 0 0 .38-1.014.95.95 0 0 0-.394-.44c1.273.374 2.56.667 3.853.974a.277.277 0 0 0 0 .227.283.283 0 0 0 .167.153c.142.02.285.02.427 0a.598.598 0 0 0 .066-.247c.56.116 1.12.222 1.68.32a.435.435 0 0 0 .094.1.394.394 0 0 0 .546 0c.314.053.627.107.94.147a1.32 1.32 0 0 0-.16.34.369.369 0 0 0-.293-.134.586.586 0 0 0-.4.225.59.59 0 0 0-.12.442.754.754 0 0 0 .553.613.613.613 0 0 0 .634-.366.951.951 0 0 0 .433.086.145.145 0 0 0 .2.054.144.144 0 0 0 .054-.054zm7.167 5.613a.448.448 0 0 0-.387.127c-.073.093-.153.407-.04.507s.413-.047.513-.127a.319.319 0 0 0-.086-.507zm-2.22 4.093a.494.494 0 0 0 .153.667.46.46 0 0 0 .541-.002.488.488 0 0 0-.014-.778.467.467 0 0 0-.68.113zm1.08-7.066a.61.61 0 0 0-.88.22.718.718 0 0 0 .073.927.891.891 0 0 0 .98-.214.604.604 0 0 0 .134-.507.624.624 0 0 0-.307-.426zm-3.467 5.134a.153.153 0 0 0 .053.18c.034 0 .14 0 .16-.054.02-.053 0-.126 0-.16a.14.14 0 0 0-.213.034zm-51.867-38.808c.054-.073.16-.226.06-.353s-.293 0-.313.053a.255.255 0 0 0 0 .307.173.173 0 0 0 .058.042.169.169 0 0 0 .195-.049zm54.254 36.094a.669.669 0 0 0-.114-.22.582.582 0 0 0-.57-.252.58.58 0 0 0-.47.412 3.65 3.65 0 0 0-.206.94.907.907 0 0 0 .666.813c.207.04.667-.033.667-.46-.347-.62.153-.707.027-1.233zm-2.487 5.426a.5.5 0 0 0-.187.38c.067.294.44.314.58.24a.395.395 0 0 0 .127-.314.396.396 0 0 0-.16-.299.368.368 0 0 0-.36-.007zm1.313-7.313c-.113-.16-.667-.126-.72.12a.424.424 0 0 0 .273.473c.24.047.567-.433.447-.593zM84 135.147c-.187.106-.147.26-.08.406.066.147.313.3.473.16.095-.108.173-.229.233-.36a.452.452 0 0 0-.626-.206zm1.333 3.726a.24.24 0 0 0-.1.24c.04.08.207.1.3.087.094-.013.2-.153.154-.273s-.254-.08-.354-.054zm2.347-5.319a.9.9 0 0 0-.933.186c-.167.2-.347.407-.127.667s.286.44.433.667a.377.377 0 0 0 .338.355.498.498 0 0 0 .502-.635 1.158 1.158 0 0 1 0-.5.668.668 0 0 0-.213-.74zm4.24 4.692c-.054.047-.114.287 0 .36.113.074.28-.066.346-.126.067-.06.054-.194 0-.24a.333.333 0 0 0-.346.006z"/> + <path d="M85.466 131.287a.194.194 0 0 1-.271-.217.196.196 0 0 1 .078-.117.865.865 0 0 0-.287-1.166.955.955 0 0 0-.773-.06v-.04a.523.523 0 0 0-.544-.306.535.535 0 0 0-.21.072.582.582 0 0 0-.378.357.572.572 0 0 0 .065.517.772.772 0 0 0 .54.446c.03.169.123.319.26.42.209.096.443.122.667.074a.546.546 0 0 0 0 .353.43.43 0 0 0 .547.24.405.405 0 0 0 .306-.573zM103.767 134a.61.61 0 0 0-.054-.813.498.498 0 0 0-.666.053.713.713 0 0 0 .173.873.398.398 0 0 0 .547-.113zm-21.101 2.334c-.08 0-.26.2-.22.3s.294.12.367.086a.266.266 0 0 0 .14-.28.262.262 0 0 0-.287-.106zm1.427-3.001a.453.453 0 0 0-.446-.259.43.43 0 0 0-.175.053c-.186.106-.146.26-.08.406a.3.3 0 0 0 .474.16 1.25 1.25 0 0 0 .226-.36zm6.013 1.934a1.085 1.085 0 0 0-1.333.567c-.113.36.333.566.593.493s.187 0 .387.187a.477.477 0 0 0 .66.097.47.47 0 0 0 .153-.191.933.933 0 0 0-.46-1.153zm.507 1.326a.31.31 0 0 0-.14.26c0 .067.18.247.293.2s.087-.267.067-.36a.185.185 0 0 0-.092-.09.183.183 0 0 0-.128-.01zm1.207-4.019a.449.449 0 0 0-.413-.291.453.453 0 0 0-.174.031.541.541 0 0 0-.28.6.443.443 0 0 0 .421.274.446.446 0 0 0 .172-.041.426.426 0 0 0 .273-.573zm-3.874-1.28c-.067.093.047.313.113.353a.2.2 0 0 0 .073.037.203.203 0 0 0 .159-.018.209.209 0 0 0 .106-.206.207.207 0 0 0-.078-.14c-.06-.053-.32-.113-.373-.026zm-.973 5.559a1.1 1.1 0 0 0-.214 1.453c.247.28.667 0 .727-.253s.087-.167.36-.233a.473.473 0 0 0 .392-.268.467.467 0 0 0-.045-.472.947.947 0 0 0-1.22-.227zm26.62 4.327a.139.139 0 0 0-.009.098.145.145 0 0 0 .055.082c.04 0 .147 0 .16-.054.014-.053.034-.126 0-.16a.14.14 0 0 0-.052-.029.13.13 0 0 0-.114.018.123.123 0 0 0-.04.045zm3.773-1.747a.459.459 0 0 0 .114.667.356.356 0 0 0 .456.049.357.357 0 0 0 .11-.122.437.437 0 0 0 .041-.503.467.467 0 0 0-.428-.218.474.474 0 0 0-.293.127zm-2.1-5.807a.757.757 0 0 0-.048.872.743.743 0 0 0 .214.222.947.947 0 0 0 1.24-.2.994.994 0 0 0-.22-1.2.816.816 0 0 0-.661-.11.829.829 0 0 0-.525.416zm-.453 7.487c-.053.04-.08.307 0 .353.08.047.28-.06.347-.126.067-.067 0-.227 0-.24a.35.35 0 0 0-.347.013zm.98-4.193c-.093.133 0 .4.247.54a.247.247 0 0 0 .4-.08c.107-.18.153-.373-.047-.533a.477.477 0 0 0-.6.073zm-1.88-1.353a.386.386 0 0 0 .06.533c.133.14.62 0 .667-.153a.529.529 0 0 0-.147-.44.353.353 0 0 0-.305-.118c-.057.005-.111.025-.159.056s-.088.072-.116.122zm-.24 3.513a.302.302 0 0 0 .093.306c.087.047.267.134.32 0a.301.301 0 0 0-.04-.313c-.046-.02-.32-.093-.373.007zm9.874-8.354c-.067.094.046.314.113.354a.214.214 0 0 0 .154.044.211.211 0 0 0 .177-.15.22.22 0 0 0-.018-.159.227.227 0 0 0-.053-.062c-.06-.053-.307-.087-.373-.027zm-10.121 9.161a.735.735 0 0 0-.76.113.468.468 0 0 0 .18.62.442.442 0 0 0 .51-.037.428.428 0 0 0 .11-.143c.147-.22.14-.44-.04-.553zm-9.06-2.414c-.266-.186-.573-.086-.813.267a.5.5 0 0 0 .04.707.96.96 0 0 0 1-.1.584.584 0 0 0-.025-.717.584.584 0 0 0-.202-.157zm22.927-7.433a.226.226 0 0 0-.26.04c-.047.067 0 .22.087.293.086.074.233.094.313 0 .08-.093-.1-.28-.14-.333zm-4.867 4.4c-.066.134-.14.514 0 .58.14.067.447-.073.567-.166.12-.094.107-.34-.087-.5a.26.26 0 0 0-.268-.113.27.27 0 0 0-.212.199zm-2.393-5.153a.51.51 0 0 0-.666.12.533.533 0 0 0 .16.666.419.419 0 0 0 .58-.12.467.467 0 0 0-.074-.666zm1.3 1.246c-.18-.087-.38-.113-.46.087s-.133.56 0 .666c.134.107.474-.18.58-.306.107-.127.114-.314-.12-.447zm-1.093 8.607c-.054.107-.094.34 0 .413a.416.416 0 0 0 .413-.04c.073-.066.147-.413.047-.486-.1-.074-.42.04-.46.113zm-1.234-8.313a.8.8 0 0 0-.926.366c-.194.307-.08.607.306.84a.624.624 0 0 0 .754-.153 1.076 1.076 0 0 0-.134-1.053zm-11.6 5.733c-.4-.287-.84-.307-1.02-.047a.86.86 0 0 0 .234.967.782.782 0 0 0 .86-.213.57.57 0 0 0-.074-.707zm.947 3.326a.454.454 0 0 0 .098-.353.448.448 0 0 0-.191-.313.504.504 0 0 0-.667.113.53.53 0 0 0 .153.667c.047.033.1.057.157.07a.435.435 0 0 0 .45-.184zm-.507 4.248c-.093.093-.173.626 0 .766.174.14.627-.213.74-.373a.515.515 0 0 0-.106-.593c-.167-.134-.48.066-.634.2zm-2.9-3.754a.451.451 0 0 0-.348-.111.452.452 0 0 0-.319.177.352.352 0 0 0-.116.297.357.357 0 0 0 .17.27.43.43 0 0 0 .525.087.43.43 0 0 0 .141-.127.44.44 0 0 0-.053-.593zm3.647.76c-.18-.1-.373-.167-.533 0a.554.554 0 0 0 .187.666c.146 0 .3-.106.413-.226a.285.285 0 0 0 .069-.109.277.277 0 0 0-.136-.331zm-3.113-2.234a.57.57 0 0 0 .24.727.61.61 0 0 0 .9-.147.621.621 0 0 0-.054-.82.901.901 0 0 0-1.086.24zm-.62 4a.505.505 0 0 0 .087.667.49.49 0 0 0 .666-.14.532.532 0 0 0-.146-.667.413.413 0 0 0-.495.005.396.396 0 0 0-.112.135zm5.98-5.36a.544.544 0 0 0-.667.18.665.665 0 0 0 .107.82.81.81 0 0 0 .946-.12c.107-.193-.086-.673-.386-.88zm.533 5.454a.313.313 0 0 0 .1.347c.047.02.098.027.149.019a.277.277 0 0 0 .137-.059.292.292 0 0 0 0-.287c-.086-.053-.32-.14-.386-.02zm1.293-10.333a.67.67 0 0 0-.053-.873c-.227-.26-.507-.24-.787.18a7.979 7.979 0 0 0-.187.96.41.41 0 0 0 .387.46.429.429 0 0 0 .487-.354c.034-.13.085-.256.153-.373zm.361 4.206c.113-.093.053-.527-.147-.667s-.293 0-.393.147a.3.3 0 0 0 .113.487c.147.073.314.126.427.033zm-2.788-2.433c-.046-.533-.153-.72-.446-.747a.443.443 0 0 0-.48.274.515.515 0 0 0 .133.666c.313.16.553-.033.793-.193zm-.68-2.853a.716.716 0 0 0 .833.047.988.988 0 0 0 .074-.927c-.667.073-1.334.147-2 .2.046.167.16.313.313.3a.778.778 0 0 1 .78.38zm.741 4.013a.45.45 0 0 0-.393-.147.697.697 0 0 0-.367.407c-.067.353.26.38.527.5.246-.24.426-.474.233-.76zm-17.32.033c-.214.073-.14.347-.08.42s.446.433.606.373.1-.526.04-.566-.347-.3-.567-.227zM56.666 111.58c-.24.1-.153.667.18.947a.458.458 0 0 0 .607 0c.246-.2.38-.614.233-.807-.28-.387-.76-.247-1.02-.14zm-.086 4.04a.749.749 0 0 0-.134.98.806.806 0 0 0 1 .047c.2-.167.153-.667-.073-.933a.547.547 0 0 0-.598-.197.558.558 0 0 0-.196.103zm-.734-1.133c-.166-.12-.526 0-.666.1a.36.36 0 0 0 .046.54c.031.034.07.06.114.076a.282.282 0 0 0 .263-.034.28.28 0 0 0 .09-.102c.113-.12.307-.454.153-.58zm2.627 5.113c-.12-.167-.38 0-.454.053s-.173.24-.053.367a.29.29 0 0 0 .367 0c.08-.02.26-.247.14-.42zm-2.567 2.4a.27.27 0 0 0 0 .274.304.304 0 0 0 .3 0c.053-.054.166-.234 0-.36-.167-.127-.207.046-.3.086zm-.219-4.747a.321.321 0 0 0 0 .174c.04.015.086.015.126 0 0-.054.087-.127.047-.18-.04-.054-.113.006-.173.006zm4.866-.433a.569.569 0 0 0-.093.447c.053.12.466.26.613.12a.42.42 0 0 0 0-.593.32.32 0 0 0-.52.026zm1.34-.946a.404.404 0 0 0 .071-.536.403.403 0 0 0-.144-.131c-.127-.047-.36.16-.534.273a.184.184 0 0 0-.1.116.182.182 0 0 0 .02.151.551.551 0 0 0 .687.127zm-3.133 4.792c-.2.047-.447.507-.3.667.146.16.433.36.666 0 .234-.36-.166-.74-.366-.667zm2.873 2.754c-.087.093-.267.38-.067.573.2.194.427-.033.494-.113a.439.439 0 0 0 0-.407.286.286 0 0 0-.201-.126.291.291 0 0 0-.121.011.286.286 0 0 0-.105.062zm.167-1.807c.073 0 .18-.173.133-.28-.047-.107-.207-.133-.287-.107-.08.027-.253.2-.213.3s.293.12.366.087zm.74-1.113a.104.104 0 0 0-.053.054c-.207 0-.667.366-.534.6a.452.452 0 0 0 .554.22c.147-.074.187-.34.153-.547h.074c.053 0 .206-.16.16-.28-.047-.12-.267-.073-.354-.047zm-7.873-3.233c-.2.146-.054.513-.08.726l.126.074a.432.432 0 0 0 .474-.2.6.6 0 0 0 .16-.367c-.22-.067-.494-.373-.68-.233zm5.473.733c-.167.06-.16.44 0 .56.12.054.25.079.38.073.253-.22.3-.486.133-.573a.655.655 0 0 0-.513-.06zm-.047-2.667c-.16-.667-.786-.367-.733-.8s.427-.2.46-.82-.48-1.013-.86-.8-.353.607-.453.627-.567 0-.58.353c0 .733.666.587.666.807s-.1.666-.04.98c.087.466.42.84.9.666a.8.8 0 0 0 .546-.364.807.807 0 0 0 .094-.649zm-11.227-8a.339.339 0 0 0-.092.409.339.339 0 0 0 .092.118.622.622 0 0 0 .8.167.724.724 0 0 0 .107-.82c-.193-.2-.613-.134-.907.126zm6.52 5.827a.744.744 0 0 0-.06-.886.588.588 0 0 0-.667-.04c-.333.306-.433.733-.22.946a.81.81 0 0 0 .947-.02zm-7.646-7.513a.667.667 0 0 0 0 .773.453.453 0 0 0 .667 0 .518.518 0 0 0 .066-.666.662.662 0 0 0-.733-.107zm3.513-2.387a1.04 1.04 0 0 0-.593-.186c-.247-.087-.8.046-.887.26-.086.213.147.373.374.46a.867.867 0 0 0 .213.353c.26.253.573.213.887-.113a.669.669 0 0 0 .006-.774zm-3.22 9.44a.222.222 0 0 0 0 .254c.06.066.22 0 .307 0s.14-.214.06-.314-.293.027-.367.06zm-.393-13.113c-.154-.28-.234-.634-.594-.78l-.426.146a1.213 1.213 0 0 0-.354-.167.115.115 0 0 0 0-.046c-.053-.127-.266-.094-.306-.06l-.087.073a.32.32 0 0 0-.16.093.42.42 0 0 0 0 .527c.207.327.36.367.793.227.253.143.513.273.78.387a.3.3 0 0 0 .354-.4zm33.287 33.246a.63.63 0 0 0-.343.358.622.622 0 0 0 .03.495c.1.274.446.36.826.207a.437.437 0 0 0 .298-.23.45.45 0 0 0 .015-.377.967.967 0 0 0-.826-.453zM49.96 105.247c-.134-.147-.28-.12-.434.04 0 .06-.033.166 0 .213a.97.97 0 0 1 .167.607c0 .1.22.246.347.26a.575.575 0 0 0 .407-.194.456.456 0 0 0-.04-.38 4.377 4.377 0 0 0-.447-.546zm3.113 7.966c-.126-.166-.32-.073-.46.06-.14.134-.166.434 0 .514.167.08.427.253.574.04.146-.214-.014-.494-.114-.614zm.574 1.033a.563.563 0 0 0-.427 0c-.167.094-.14.467.047.567a.81.81 0 0 0 .346.033c.214-.233.214-.513.034-.6zm.679-4.579a1.026 1.026 0 0 0-1.273-.067c-.353.28-.32.833.067 1.287a.757.757 0 0 0 .513.272.755.755 0 0 0 .553-.179.994.994 0 0 0 .14-1.313zm-3.313 7.82a.415.415 0 0 0-.164.333.42.42 0 0 0 .164.333.387.387 0 0 0 .281.149.4.4 0 0 0 .3-.109c.206-.206.28-.62.132-.766a.662.662 0 0 0-.713.06zM51.16 114a.559.559 0 0 0-.067.713c.153.167.54.127.854-.153 0-.087 0-.274-.04-.387a.555.555 0 0 0-.747-.173zm-.213-2.754a.698.698 0 0 0-.148.504.686.686 0 0 0 1.214.356.624.624 0 0 0 .094-.853.92.92 0 0 0-1.16-.007zm-3.514 2.427c-.066.047-.18.28-.107.36.074.08.32 0 .374-.04a.206.206 0 0 0 .065-.222.206.206 0 0 0-.102-.122.195.195 0 0 0-.078-.023.2.2 0 0 0-.152.047zM74 131.293a.304.304 0 0 0-.267.16c-.04.1.107.227.194.253.086.027.293-.04.326-.166.034-.127-.166-.247-.253-.247zm2.113 1.127c-.066-.194-.513-.16-.753.1s.067.62.233.666c.167.047.587-.58.52-.766zm.04-2.8c-.1-.18-.246-.293-.44-.227a2.668 2.668 0 0 0-1.286.814.836.836 0 0 0-.087.226.573.573 0 0 0 .793.667c.308-.105.599-.25.867-.433a.916.916 0 0 0 .153-1.047zm-3.253 3.447a.468.468 0 0 0 .446.393c.273-.04.433-.667.273-.773-.16-.107-.746.113-.72.38zm-1.053 2.033c-.107.06-.374.273-.247.52s.413.107.507.053a.431.431 0 0 0 .16-.373.285.285 0 0 0-.29-.235.28.28 0 0 0-.13.035zm1.486-5.88a.43.43 0 0 0 .193-.56.326.326 0 0 0-.5-.154.57.57 0 0 0-.226.394c-.02.133.32.433.533.32zm-1.106.266c-.18 0-.3.367-.174.54.127.174.26.154.334.194.313-.127.446-.36.32-.5a.732.732 0 0 0-.48-.234zm3.513 8.887a.363.363 0 0 0 .066.34.41.41 0 0 0 .42 0c.087-.106-.073-.386-.153-.426a.358.358 0 0 0-.333.086zm3.766-3.746a.429.429 0 0 0 .32-.507.568.568 0 0 0-.267-.34c-.24-.113-.413 0-.666.447.146.213.246.513.613.4zm-7.359-6.907a.817.817 0 0 0 .337-.023.808.808 0 0 0 .583-.757c.06-.667-.627-.607-.434-1s.474-.047.707-.62c.233-.573-.12-1.113-.554-1.04-.433.073-.526.453-.626.447-.1-.007-.54-.187-.667.14-.266.666.407.76.394.986-.014.227-.314.587-.367.92-.074.467.126.927.626.947zm7.493 10.66a.968.968 0 0 0-.434 1.126.88.88 0 0 0 1.087.507 1.334 1.334 0 0 0 .493-1.273.879.879 0 0 0-1.147-.36zm-.307-5.906a.49.49 0 0 0 .21-.609.486.486 0 0 0-.577-.285.48.48 0 0 0-.273.587.525.525 0 0 0 .64.307zm-1.253-1.681a.461.461 0 0 0-.42.135.463.463 0 0 0-.12.425.622.622 0 0 0 .38.387.529.529 0 0 0 .453-.18.54.54 0 0 0 .033-.453.53.53 0 0 0-.327-.314zm-2.04 4.187a.678.678 0 0 0-.394.353.665.665 0 0 0-.013.527 1.06 1.06 0 0 0 1.2.56.773.773 0 0 0 .347-.986.835.835 0 0 0-.808-.533.83.83 0 0 0-.332.079zM63.773 126a.433.433 0 0 0-.236.255.421.421 0 0 0 .036.345.384.384 0 0 0 .216.234.393.393 0 0 0 .318-.007c.266-.12.473-.493.38-.667a.704.704 0 0 0-.714-.16zm3.127 5.9a.297.297 0 0 0-.067.267.316.316 0 0 0 .287.107c.066 0 .233-.167.14-.334-.094-.166-.28-.08-.36-.04zm.38-4.907c-.234.073-.22.46-.314.667.033.036.064.074.093.113a.431.431 0 0 0 .514 0 .578.578 0 0 0 .266-.3c-.16-.14-.32-.553-.56-.48zm-.333-1.627c.046-.126-.194-.333-.287-.346a.341.341 0 0 0-.28.206.366.366 0 0 0 .18.3.407.407 0 0 0 .386-.16zm-2.174-5.886c-.126-.153-.54 0-.666.347s.266.567.446.573c.18.007.347-.76.22-.92zm1.827 3.654c.12.113.28.246.44.133s.14-.467.086-.62a.195.195 0 0 0-.153-.14.777.777 0 0 0-.2-.527.848.848 0 0 0-.94-.238.847.847 0 0 0-.287.185.667.667 0 0 0-.14.887.424.424 0 0 0-.347-.047.559.559 0 0 0-.3.667c.094.2.467.293.86.133 0-.087.12-.253.087-.38a.46.46 0 0 0-.067-.14 1.153 1.153 0 0 0 .96.087zm-2.52-5.254a.912.912 0 0 0-.187-1.053.36.36 0 0 0-.493-.067c-.43.293-.76.709-.947 1.194a.743.743 0 0 0 0 .24.582.582 0 0 0 .69.536.574.574 0 0 0 .29-.15c.244-.205.461-.44.647-.7zm5.566 8.187a.766.766 0 0 0-.447.886.797.797 0 0 0 .927.374c.24-.094.367-.58.24-.907a.556.556 0 0 0-.5-.385.567.567 0 0 0-.22.032zm.407 5.459c-.207 0-.587.334-.514.56.074.227.294.487.667.254.373-.234.053-.787-.153-.814zm-1.86-4.052s.107.08.12.066c.014-.013.12-.093.1-.153-.02-.06-.093-.047-.146-.067a.445.445 0 0 0-.074.154zm1.654 3.346c.093 0 .333-.167.28-.367-.054-.2-.36-.14-.447-.1s-.24.167-.173.327a.282.282 0 0 0 .34.14zm1.419-6.907a.88.88 0 0 0-1.2.04.974.974 0 0 0-.04 1.207.884.884 0 0 0 .573.295.884.884 0 0 0 .62-.175 1.28 1.28 0 0 0 .047-1.367zm-1.933-.58a.739.739 0 0 0 .233-.86.575.575 0 0 0-.62-.26c-.413.18-.666.547-.513.827a.813.813 0 0 0 .9.293zm0 1.427c-.114-.173-.494-.167-.634-.113a.345.345 0 0 0-.192.38c.01.05.03.098.059.14.018.042.046.08.081.11a.287.287 0 0 0 .379-.01c.113-.087.413-.334.307-.507zm105.246-49.873h-8.253v8.253h8.253zm19.087 19.087h-8.253v8.253h8.253zm-19.087 0h-8.253v8.253h8.253zm-19.08-19.087h-8.253v8.253h8.253zm0 19.087h-8.253v8.253h8.253zm-21.106-19.087h-8.253v8.253h8.253z"/> + </g> + <path fill="#1ba9f5" d="M105.439 32.813a42.666 42.666 0 1 0 0 85.333 42.666 42.666 0 0 0 0-85.332zm0 69.394A26.751 26.751 0 0 1 79.2 70.232a26.753 26.753 0 1 1 50.956 15.465 26.744 26.744 0 0 1-24.717 16.51z"/> + <path fill="#0a89db" d="M133.935 93.105 123.47 103.57l27.143 27.144 10.465-10.465z"/> + <path fill="#0d90e0" d="M73.086 74.833a.48.48 0 0 0 .574-.393.58.58 0 0 0-.4-.6.754.754 0 0 0-.614.493c-.026.16.24.46.44.5zm10.287-15.347c.147.054.234-.18.227-.226-.007-.047-.033-.22-.173-.247a.153.153 0 0 0-.182.073.154.154 0 0 0-.018.067c-.007.094-.007.28.146.334zm1-.493c.154-.2.307-.407.474-.6a.433.433 0 0 0-.147-.107c-.28-.086-.667.087-.667.32-.033.12.147.274.34.387zM69.126 76.967a.465.465 0 0 0 .514-.427c.053-.28-.14-.666-.38-.666a.58.58 0 0 0-.667.433.549.549 0 0 0 .533.66zm.327-7.981.22-.226h-.707c.143.11.31.188.487.226zm-4.119 1.401a.426.426 0 0 0 .373-.053.9.9 0 0 0 .293-1 .433.433 0 0 0-.5-.327.74.74 0 0 0-.666.62c-.004.06-.004.12 0 .18v.04c.15.195.317.376.5.54zm1.852-1.627h-.407.054a.587.587 0 0 0 .353 0zm-3.633 8.44a1.114 1.114 0 0 0 .473.847c.28.08.613-.2.707-.6.093-.4-.06-.574-.5-.667a.559.559 0 0 0-.68.42zm5.294-3.427A.92.92 0 0 0 69 73.16c-.08-.207-.333-.34-.533-.533.106-.187.233-.42 0-.667-.62 0-.667.127-.387.667-.12.224-.2.468-.233.72.043.233.157.447.326.613.174.213.494.12.674-.187zm-4.474-1.347a1.273 1.273 0 0 0 1.294.44c.326-.146.253-.586.34-.666.086-.08.593.233.986 0a1.072 1.072 0 0 0 .38-1.187 1.04 1.04 0 0 0-.5-.6.866.866 0 0 0-.953.167c-.207.26-.213.766-.333.82-.12.053-.6-.287-.98-.054a.761.761 0 0 0-.234 1.08zm5.673 3.134a.592.592 0 0 0 .44-.213c.193-.34-.047-.553-.32-.753-.26.106-.553.206-.547.546a.406.406 0 0 0 .427.42zm7.2-19.266c.273.073.593-.22.667-.614a.347.347 0 0 0-.287-.44c-.32-.093-.707.073-.76.313a.728.728 0 0 0 .38.74zM75.24 58.62c-.08.16.1.547.306.667a.341.341 0 0 0 .473-.22c.14-.347.127-.62-.04-.707a.773.773 0 0 0-.74.26zm1.366 2.713h.52a.78.78 0 0 0 .36-.447.54.54 0 0 0-.386-.54c-.46-.073-.8.067-.847.354a.767.767 0 0 0 .353.633zm4.187-5.18a.407.407 0 0 0 .513-.28.367.367 0 0 0-.3-.44.334.334 0 0 0-.42.24.354.354 0 0 0 .207.48zm-.713 1.18c-.334-.073-.567.107-.667.52-.1.414.12.567.526.667a.473.473 0 0 0 .587-.273.974.974 0 0 0-.447-.914zm.22-3.953c.113-.074.086-.387.1-.594a.187.187 0 0 0-.167-.22.547.547 0 0 0-.52.467.406.406 0 0 0 .587.347zm-1.134 3.42a.666.666 0 0 0 .667-.34.666.666 0 0 0-.447-.666.46.46 0 0 0-.513.393.52.52 0 0 0 .293.613zm-1.673.36a.567.567 0 0 0-.226.38c0 .094.14.247.246.294.216.086.44.153.667.2.2.046.307-.054.34-.274-.033-.046-.06-.153-.12-.173a.974.974 0 0 1-.48-.413.466.466 0 0 0-.427-.014zm-4.16 3.02c-.047-.28-.114-.553-.454-.513s-.373.3-.34.567a.508.508 0 0 0 .794-.054zm3.613 14.947a.513.513 0 0 0 .58-.307.706.706 0 0 0-.326-.666.627.627 0 0 0-.614.373.467.467 0 0 0 .36.6zm.454 1.74a.767.767 0 0 0 .88-.447c.06-.233-.387-.733-.667-.787a.627.627 0 0 0-.18 1.234zm-2.8-7.713v.12c-.073.186-.187.26-.36.12-.06-.054-.1-.134-.167-.18a.806.806 0 0 0-.906 0 .666.666 0 0 0-.307.826 1.16 1.16 0 0 0 .78.827c-.055.18-.093.366-.113.553 0 .547.36.76.84.487a.613.613 0 0 0 .18-1.013 4.33 4.33 0 0 0-.42-.367c.186-.113.306-.253.426-.253a.58.58 0 0 0 .627-.594 1.09 1.09 0 0 1 .12-.273c.14-.307.107-.54-.093-.667h-.32a.606.606 0 0 0-.287.414zm-2.32 3.286c-.34 0-.714-.106-.987.26a.765.765 0 0 1-.594.347.726.726 0 0 0-.606.667 1.779 1.779 0 0 0 .986.986c.34-.153.794-.34 1.24-.546.054 0 .08-.187.067-.274a.86.86 0 0 1 .173-.666c.2-.294.027-.76-.28-.774zm2.233.42c-.293-.067-.573.227-.666.667a.593.593 0 0 0 .426.573.853.853 0 0 0 .74-.413.834.834 0 0 0-.5-.827zM78 71.593a.84.84 0 0 0-1.027.527 1.333 1.333 0 0 0 .667 1.186.853.853 0 0 0 .946-.666.987.987 0 0 0-.586-1.047zm-2.18 6.994c-.32-.067-.547.133-.667.56s.053.626.313.666a1.16 1.16 0 0 0 .9-.466.667.667 0 0 0-.546-.76zm2.886-3.64c0-.445.02-.89.06-1.334a.927.927 0 0 0-.327.54.84.84 0 0 0 .267.794zm.167 3.587c0-.214-.047-.434-.067-.667-.06.087-.106.187-.146.247-.04.06.006.34.213.42zM68.18 76a.667.667 0 0 0-.32-.44c-.374-.147-.488.207-.7.453.192.32.366.567.732.447a.374.374 0 0 0 .287-.46zm8.793-6.366a.813.813 0 0 0-.927-.534.847.847 0 0 0 .547 1.58c.326-.066.453-.586.38-1.046zm-11.94 6.626c-.06.22.093.58.293.593.314.071.643.026.927-.126.4-.287.426-.327.193-.84-.24 0-.433-.06-.627-.1a.727.727 0 0 0-.786.473zM79.16 59.893c.04-.3-.293-.667-.666-.727s-.594.147-.667.594a.667.667 0 0 0 .42.666c.266.034.88-.3.913-.533zM74.453 57.2a.74.74 0 0 0 .953-.594.786.786 0 0 0-.493-.92c-.354-.113-.827.26-.947.747a.606.606 0 0 0 .487.767zm.447 3.767a.347.347 0 0 0-.387-.353c-.373 0-.626.12-.666.306a.619.619 0 0 0 .246.407h.594a.666.666 0 0 0 .213-.36z"/> + <path fill="#0d90e0" d="M72.466 69.22a.62.62 0 0 0 .153-.46h-2.58c.094.373 0 .52-.42.393a.767.767 0 0 0-.933.373.78.78 0 0 0 0 .954.628.628 0 0 0 .9.213c.23-.135.425-.32.573-.54.127-.173.234-.3.454-.287.32 0 .426-.173.426-.466a.94.94 0 0 0 1.427-.18zm-1.92 2.614a.54.54 0 0 0 .6.293.467.467 0 0 0 .454-.407c.04-.34-.454-.873-.667-.84a.988.988 0 0 0-.387.954zm-.952-.048a.547.547 0 0 0-.614.354.706.706 0 0 0 .327.766.786.786 0 0 0 .9-.42c.06-.266-.207-.56-.613-.7zm2.619-13.272c0-.254-.12-.374-.34-.42a.447.447 0 0 0-.554.34.394.394 0 0 0 .36.46.473.473 0 0 0 .534-.38zm-4.46 18.399c-.32-.086-.54.227-.6.407s.287.533.667.433a.492.492 0 0 0 .287-.32.433.433 0 0 0-.354-.52zm-.42-2.539c-.446-1.147-1.12-1.247-1.88-.334a1.57 1.57 0 0 1-.233-.073.494.494 0 0 0-.667.2.613.613 0 0 0 0 .707c.314.666.614.766 1.187.466.433-.22.88-.426 1.333-.666.534.84.667.866 1.187.32a.74.74 0 0 0-.927-.62zm3.887-13.661a.38.38 0 0 0 .28.507.46.46 0 0 0 .58-.287.446.446 0 0 0-.36-.526.406.406 0 0 0-.5.306zm8.893.621h.76a.327.327 0 0 0-.186-.154.442.442 0 0 0-.394.067c-.053.027-.12.047-.18.087zm-12.587 24.16a.753.753 0 0 0-.847.426.52.52 0 0 0 .34.627.666.666 0 0 0 .747-.447.453.453 0 0 0-.24-.606zm3.734-2.514a.827.827 0 0 0 .846-.533c.067-.26-.213-.607-.546-.667-.434-.093-.667 0-.767.347a.78.78 0 0 0 .466.853zm.214 1.16c0-.147-.054-.527-.227-.554-.173-.026-.353.334-.38.467-.027.133.16.26.28.307s.347-.014.327-.22zm1.039 2.214c-.166 0-.586.073-.613.24-.027.166.313.393.46.473.147.08.393-.113.42-.327.027-.213-.053-.393-.267-.386zm-.98 4.52a.354.354 0 0 0-.207.44c.087.34.354.38.667.393.147-.266.36-.48.134-.74a.474.474 0 0 0-.594-.093zm-2.14-7.541a1.113 1.113 0 0 0-1.18.62.887.887 0 0 0 .6.987.86.86 0 0 0 .58-1.607zm1.219-5.186a.467.467 0 0 1-.133-.507.546.546 0 0 0-.513-.553c-.293 0-.373.153-.393.393.005.174-.03.348-.1.507-.2.32-.454.607-.667.927-.907-.254-1.18-.094-1.193.74a.62.62 0 0 0 .813.666 5.64 5.64 0 0 0 1-.546 1.1 1.1 0 0 0 1.22.1 1.147 1.147 0 0 0-.033-1.727zM67.56 82.82c-.225.033-.448.08-.667.14-.447-.347-.887-.407-1.093-.147a.92.92 0 0 0 .166 1.1c.3.247.507.173 1.02-.413.247.18.48.393.754.093a.48.48 0 0 0 .073-.607c-.067-.08-.18-.173-.253-.166zm1.606 4.327a.753.753 0 0 0-.78.62c-.073.386.16.666.607.74a.625.625 0 0 0 .793-.534.734.734 0 0 0-.62-.826zM73 89.14c-.087 0-.28-.054-.34.086s.113.26.16.26a.366.366 0 0 0 .267-.12s-.04-.213-.087-.226zm-3.86-7.806a.527.527 0 0 0-.14-.414.393.393 0 0 0-.354-.053c-.26.146-.253.38-.12.666.233.014.5.087.613-.2zm3.867-1.26a.587.587 0 0 0-.447-.667.386.386 0 0 0-.467.273.493.493 0 0 0 .147.6.547.547 0 0 0 .767-.206zm5.759 4.213a.666.666 0 0 0-.52-.667c-.32-.073-.533.04-.6.32a.787.787 0 0 0 .44.94.706.706 0 0 0 .68-.593zm-.433-3.62c.1-.414-.213-.794-.746-.914a.667.667 0 0 0-.86.52.9.9 0 0 0 .666 1.04.92.92 0 0 0 .94-.646zm-4.667 1.166c-.093.093-.293.207-.373.373-.08.167.126.514.406.554a.407.407 0 0 0 .46-.374.547.547 0 0 0-.493-.553zm-.613-27.573a.933.933 0 0 0 .967-.667.67.67 0 0 0-1.333-.113.626.626 0 0 0 .367.78zM76.82 88.7a.729.729 0 0 0-1.06 0 .667.667 0 0 0 .053.787.527.527 0 0 0 .707.16c.207-.1.667-.187.707-.527s-.287-.306-.407-.42zm.96-19.94a.48.48 0 0 0 .046.3 1.387 1.387 0 0 0 1.48.72c.075-.343.155-.683.24-1.02zm-2.994 12.906a.46.46 0 0 0 .547-.333.475.475 0 1 0-.934-.18.534.534 0 0 0 .387.513zM76 83.42a.44.44 0 0 0-.38-.473c-.367-.047-.667.373-.667.52a.667.667 0 0 0 .667.453.446.446 0 0 0 .38-.5zm-1.573-6.187-.04-.06c.083.093.183.17.293.227a.288.288 0 0 0 .433-.187.345.345 0 0 0-.22-.486.827.827 0 0 0-.44.086.413.413 0 0 0-.306-.473.473.473 0 0 0-.567.52c0 .32-.18.413-.373.593-.494-.506-.92-.473-1.227.06a.886.886 0 0 0-.08.16c-.153.394-.047.62.353.734.4.113.667.153.954-.327.055.157.091.32.106.487a.434.434 0 0 0 .327.506.667.667 0 0 0 .727-.12c.64-.713.653-.993.06-1.72zM74.98 86a.494.494 0 0 0-.528.306.566.566 0 0 0 .314.594.44.44 0 0 0 .513-.314.507.507 0 0 0-.3-.586zm3.84 1.06a.408.408 0 0 0-.52.273.46.46 0 0 0 .3.527.388.388 0 0 0 .52-.266.48.48 0 0 0-.3-.534zm-9.007-31.853a.56.56 0 0 0 .58-.34c.106-.44-.047-.847-.347-.907a.813.813 0 0 0-.78.547c-.06.24.26.653.547.7zm-3.2 37.873a.267.267 0 0 0-.073-.16zM66 60.3c.146 0 .413 0 .466-.173.053-.173-.127-.38-.253-.493s-.287 0-.387.12l-.067.18a.278.278 0 0 0 .122.327.28.28 0 0 0 .118.04zm1.166 1.033h.414c.093-.07.196-.127.306-.167a.587.587 0 0 0 .467-.62c0-.333-.227-.666-.18-.793.047-.127.153-.333.393-.24.24.093.627-.047.794-.547s-.274-1.04-.667-.926c-.393.113-.4.353-.533.293s-.314-.327-.554-.227-.253.874-.193.987c.06.113.347.347.153.533-.193.187-.526.234-.586.507-.06.273-.227.913.126 1.187zm1.007-4.313c.46.16.76-.254.906-.474.147-.22-.266-.667-.666-.667a.447.447 0 0 0-.487.36c-.107.287.013.7.247.78zm3.307-1.373a1 1 0 0 0 .62 1.167 1.033 1.033 0 0 0 1.1-.667c.127-.426-.2-.866-.78-1.026a.751.751 0 0 0-.94.526zm-1.2.9a.48.48 0 0 0-.554.346.446.446 0 0 0 .347.494.393.393 0 0 0 .52-.287.426.426 0 0 0-.313-.553zm.873-3.38c.207.073.313-.12.347-.307.033-.186-.1-.446-.294-.42-.193.027-.486 0-.493.287-.007.287.293.393.44.44zm-1.74 6.746a1 1 0 0 0 .727.973c.267.047.553-.226.613-.593.06-.367-.093-.667-.553-.753-.36-.067-.733.106-.787.373zm.687-7.247a.538.538 0 0 0 .36-.233c.086-.173-.147-.467-.354-.447a.74.74 0 0 0-.306.167c-.047.28.106.513.3.513zM66.413 80.38c.133-.048.262-.106.387-.174.413-.2.553-.46.44-.806a.72.72 0 0 0-.907-.467 7.66 7.66 0 0 1-1.333.26c-.367 0-.78.307-.754.56a.547.547 0 0 0 .534.367c.32-.107.413.12.606.233.194.09.407.13.62.12a.974.974 0 0 0 .407-.093zm-2.16 5.16a.433.433 0 0 0-.24 0l.22.874a.433.433 0 0 0 .366-.347.514.514 0 0 0-.346-.527zm.34-3.107a.993.993 0 0 0-.534-.727c-.253-.066-.44.094-.513.447-.073.353 0 .613.287.667.386.093.706-.074.76-.387zm2.467-1.98a.58.58 0 0 0-.667.3c-.134.447 0 .86.28.94a.773.773 0 0 0 .82-.48.667.667 0 0 0-.433-.76zm-1.487 6.467a.14.14 0 0 0-.146.114c0 .04.073.126.106.126a.134.134 0 0 0 .14-.08.132.132 0 0 0-.052-.138.134.134 0 0 0-.048-.022zm-2.106-11.1a.746.746 0 0 0-.214-.847.46.46 0 0 0-.446.054v1.293h.046a.8.8 0 0 0 .547-.107.294.294 0 0 0 .067-.393zm-.134-3.554a.726.726 0 0 0-.174-.973.771.771 0 0 0 .214-.227.532.532 0 0 0 0-.546c.068.006.138.006.206 0a1 1 0 0 0 .767-1.12.34.34 0 0 0 .2 0 .393.393 0 0 0 .127-.567h-.54a.447.447 0 0 0-.107.293.668.668 0 0 0-.727-.106 41.81 41.81 0 0 0-.4 3.806c.14-.1.294-.233.434-.56z"/> + <path fill="#294492" d="M33.566 123.433a1.635 1.635 0 0 1-1.433-.846 33.005 33.005 0 0 1-1.673-3.58 1.633 1.633 0 0 1 .92-2.114 1.633 1.633 0 0 1 1.77.385c.148.154.265.336.343.535a28.107 28.107 0 0 0 1.5 3.214 1.617 1.617 0 0 1-.619 2.196 1.61 1.61 0 0 1-.808.21zm-3.44-10.826a1.624 1.624 0 0 1-1.613-1.454 29.025 29.025 0 0 1-.18-3.233v-.733A1.633 1.633 0 0 1 30 105.6a1.632 1.632 0 0 1 1.136.509 1.62 1.62 0 0 1 .444 1.164v.667c0 .962.053 1.924.16 2.88a1.628 1.628 0 0 1-1.44 1.793zm1.127-11.274a1.622 1.622 0 0 1-1.623-1.503 1.64 1.64 0 0 1 .076-.63c.41-1.264.911-2.496 1.5-3.687a1.63 1.63 0 0 1 2.92 1.447 23.352 23.352 0 0 0-1.333 3.246 1.631 1.631 0 0 1-1.54 1.127zm5.8-9.733a1.627 1.627 0 0 1-1.173-2.753 28.727 28.727 0 0 1 2.933-2.667 1.626 1.626 0 1 1 2 2.547 25.898 25.898 0 0 0-2.6 2.373 1.605 1.605 0 0 1-1.16.48zm9.333-6.433a1.626 1.626 0 0 1-.666-3.12 34.99 34.99 0 0 1 3.686-1.334 1.628 1.628 0 1 1 .96 3.114 30.74 30.74 0 0 0-3.333 1.233 1.673 1.673 0 0 1-.627.086zm33.88-2.667a1.627 1.627 0 1 1-.033-3.254c1.233 0 2.48-.066 3.707-.12a1.629 1.629 0 0 1 .153 3.254c-1.26.053-2.533.1-3.793.12zm-7.68 0h-.046c-1.24-.031-2.5-.078-3.78-.14a1.628 1.628 0 1 1 .153-3.253c1.253.06 2.493.106 3.713.133a1.634 1.634 0 0 1-.04 3.26zm-15.173-.107a1.627 1.627 0 0 1-.173-3.247 48.211 48.211 0 0 1 3.866-.266 1.602 1.602 0 0 1 1.68 1.58 1.626 1.626 0 0 1-1.58 1.673c-1.226.04-2.446.12-3.613.247zm34.26-.553a1.627 1.627 0 0 1-.16-3.247c1.233-.127 2.473-.273 3.673-.433a1.628 1.628 0 0 1 .427 3.226c-1.233.167-2.5.314-3.773.447zm11.333-1.707a1.63 1.63 0 0 1-1.617-1.462 1.627 1.627 0 0 1 1.291-1.758 95.372 95.372 0 0 0 3.6-.813 1.63 1.63 0 0 1 .773 3.166c-1.213.294-2.467.574-3.72.834a1.816 1.816 0 0 1-.34-.027zM114 77.107a1.628 1.628 0 0 1-1.399-2.462c.198-.331.507-.581.872-.705a71.72 71.72 0 0 0 3.44-1.273 1.63 1.63 0 0 1 1.207 3.026c-1.167.46-2.38.907-3.594 1.333-.17.056-.348.083-.526.08zm10.473-4.547a1.634 1.634 0 0 1-.78-3.06 52.344 52.344 0 0 0 3.14-1.84 1.627 1.627 0 0 1 1.747 2.746 56.688 56.688 0 0 1-3.334 1.954 1.565 1.565 0 0 1-.746.2zm9.333-6.52a1.628 1.628 0 0 1-1.577-2.005 1.62 1.62 0 0 1 .491-.828c.9-.82 1.76-1.667 2.553-2.527a1.628 1.628 0 0 1 2.4 2.2c-.86.933-1.793 1.86-2.78 2.747a1.62 1.62 0 0 1-1.033.413zm7.167-8.834a1.628 1.628 0 0 1-1.427-2.413c.347-.667.667-1.28.967-1.92.193-.44.393-.88.593-1.333a1.638 1.638 0 0 1 1.536-.965 1.636 1.636 0 0 1 1.479 1.05 1.622 1.622 0 0 1-.035 1.248l-.606 1.333c-.334.727-.667 1.447-1.087 2.154a1.619 1.619 0 0 1-1.367.846zm-9.133-8.086a1.641 1.641 0 0 1-.607-.12 34.34 34.34 0 0 1-3.507-1.667 1.631 1.631 0 0 1-.895-1.61 1.632 1.632 0 0 1 1.182-1.413 1.627 1.627 0 0 1 1.26.163c1.048.57 2.127 1.08 3.233 1.527a1.628 1.628 0 0 1 .432 2.774 1.63 1.63 0 0 1-1.045.366zm13.586-2.453a1.621 1.621 0 0 1-1.619-1.509 1.628 1.628 0 0 1 .079-.632 53.13 53.13 0 0 0 1.027-3.493 1.629 1.629 0 0 1 2.977-.426c.22.371.283.815.176 1.233a52.294 52.294 0 0 1-1.093 3.713 1.63 1.63 0 0 1-1.547 1.114zm-23.086-3.694a1.612 1.612 0 0 1-1.167-.493 19.48 19.48 0 0 1-2.533-3.2 1.627 1.627 0 1 1 2.753-1.74 16.037 16.037 0 0 0 2.113 2.666 1.625 1.625 0 0 1-1.166 2.76zm25.333-7.487h-.04a1.63 1.63 0 0 1-1.478-1.04 1.63 1.63 0 0 1-.109-.626v-.627a19.053 19.053 0 0 0-.2-2.833 1.634 1.634 0 0 1 .772-1.636 1.638 1.638 0 0 1 1.233-.184 1.632 1.632 0 0 1 1.215 1.34c.165 1.103.245 2.218.24 3.333v.713a1.626 1.626 0 0 1-1.66 1.56zm-30-2.666A1.632 1.632 0 0 1 116 31.333c0-.42-.04-.853-.04-1.28v-.107c.006-.91.077-1.82.213-2.72a1.62 1.62 0 0 1 .651-1.064 1.63 1.63 0 0 1 2.569 1.571 15.184 15.184 0 0 0-.18 2.233V30c0 .36 0 .707.04 1.053a1.633 1.633 0 0 1-1.513 1.74zm26.893-8.093a1.62 1.62 0 0 1-1.286-.627 13.32 13.32 0 0 0-2.367-2.34 1.638 1.638 0 0 1-.29-2.29 1.63 1.63 0 0 1 2.29-.29 16.563 16.563 0 0 1 2.953 2.92 1.63 1.63 0 0 1 .18 1.712 1.631 1.631 0 0 1-1.46.915zm-23.533-2.5a1.628 1.628 0 0 1-1.2-2.727 13.671 13.671 0 0 1 3.333-2.667 1.629 1.629 0 0 1 1.614 2.827 10.443 10.443 0 0 0-2.527 2 1.605 1.605 0 0 1-1.24.567zm14-3.467c-.142 0-.283-.02-.42-.06a15.16 15.16 0 0 0-3.333-.513 1.627 1.627 0 0 1-1.56-1.694 1.653 1.653 0 0 1 1.693-1.56c1.37.057 2.73.267 4.053.627a1.627 1.627 0 0 1-.42 3.2z"/> + <path fill="#1ba9f5" d="M139.447 49.727c-.62.433-8.36 5.033-15.687 6.246a26.738 26.738 0 0 1-9.68 44.8c.42 5.374.98 10.74 1.58 16.1a42.667 42.667 0 0 0 23.787-67.146z"/> + <path fill="#0066b1" d="M133.333 107.814a.7.7 0 0 0 .047-.147c-.207.18-.4.36-.607.527a.605.605 0 0 0 .56-.38zm4.574-1.901a1.085 1.085 0 0 0 1-.353.667.667 0 0 0-.294-.667c0-.226-.18-.366-.52-.44a.574.574 0 0 0-.666.42.963.963 0 0 0 .166.52.667.667 0 0 0 .314.52zm1.28-1.393c.313.073.642.03.926-.12l.047-.04a.391.391 0 0 0 .38-.214.969.969 0 0 0-.307-.946.48.48 0 0 0-.39-.016.465.465 0 0 0-.167.109.465.465 0 0 0-.109.167.725.725 0 0 0-.667.473c-.073.213.087.573.287.587zm-.521-1.187c0-.053-.04-.167-.093-.187a.833.833 0 0 1-.353-.393c-.154.18-.3.367-.46.547.17.092.346.175.526.246.154.1.274.014.38-.213zm-1.293.38c-.067.08-.134.153-.207.227a.573.573 0 0 0 .107-.04.28.28 0 0 0 .07-.083.271.271 0 0 0 .03-.104zM137 107.7c.011.062.041.12.084.167a.334.334 0 0 0 .163.093c.106 0 .193-.154.186-.26-.006-.107-.113-.234-.226-.214a.221.221 0 0 0-.143.069.225.225 0 0 0-.064.145zm.653 4.34c.066-.167.106-.354-.1-.467a.482.482 0 0 0-.362.006.482.482 0 0 0-.258.254c.08.107.153.293.293.38s.353.02.427-.173zm-1.96-1.307c.16.105.35.154.54.14.111.032.225.05.34.053.06-.1.12-.193.167-.286.057-.039.11-.081.16-.127a2.78 2.78 0 0 0-.153-.56.666.666 0 0 0-.734-.387.738.738 0 0 0-.573.747.64.64 0 0 0 .083.236.636.636 0 0 0 .17.184zm5.093-10.786-.26-.254-.193.28a.868.868 0 0 0 .453-.026zm-10.653 10.28.106.113a.382.382 0 0 0 .074-.12.984.984 0 0 0 0-.133zm11.506-4.801a.497.497 0 0 0 .294-.326.421.421 0 0 0-.168-.445.428.428 0 0 0-.152-.069c-.32-.093-.54.22-.6.4s.28.534.626.44zm-11.285 4.994.32.32a.395.395 0 0 0-.32-.32zm8.099-.32a1.03 1.03 0 0 0-.54-.726.375.375 0 0 0-.194 0h-.04a.558.558 0 0 0-.273.426c-.087.394 0 .607.287.667.386.113.706-.053.76-.367zm-1.827 2.247c.147-.033.407-.16.393-.287a.47.47 0 0 0-.28-.32c-.106 0-.433.114-.453.24-.02.127.273.38.34.367zm7.034-1.014h-.08a.581.581 0 0 0-.327-.293 1.107 1.107 0 0 0-1.18.613.873.873 0 0 0 .6.987.858.858 0 0 0 1.013-.54.992.992 0 0 0 0-.447.138.138 0 0 0 .054-.053.169.169 0 0 0-.01-.225.169.169 0 0 0-.07-.042zm-.667-2.34a.477.477 0 0 0-.134-.407.386.386 0 0 0-.36-.06c-.253.147-.253.38-.113.667.233.02.493.093.607-.2zm-1.28 3.9a.416.416 0 0 0 .506.194c.207-.1.214-.254 0-.667a.393.393 0 0 0-.207-.007c-.068.015-.132.049-.183.097s-.089.109-.11.176a.404.404 0 0 0-.006.207zm2.953-8.007a.596.596 0 0 0-.5 0 .572.572 0 0 0-.313-.133c-.287 0-.367.153-.387.393a2.159 2.159 0 0 1-.06.374.164.164 0 0 0-.038-.082.17.17 0 0 0-.075-.052.169.169 0 0 0-.187.047.177.177 0 0 0-.033.06c0 .093-.053.28.087.353h.06c-.167.24-.36.48-.554.727-.9-.253-1.173-.093-1.186.747a.616.616 0 0 0 .222.558.617.617 0 0 0 .591.108c.161-.053.315-.124.46-.213.247.187.473.48.86.467l.327-.314c.42.067.806-.046.873-.28a.396.396 0 0 0-.067-.386 1.207 1.207 0 0 0-.24-1.427.568.568 0 0 1-.126-.18.48.48 0 0 0 .346.1c.22-.1.174-.733-.06-.867zm2.841 1.84h.08l-.4-.4a.4.4 0 0 0 .32.4zm-.661-.726-.94-.934-.066.094a1.234 1.234 0 0 0-.074.166c-.153.387-.046.614.354.727a.777.777 0 0 0 .726-.053zm.02 1.747a.589.589 0 0 0-.447-.7.374.374 0 0 0-.403.137.367.367 0 0 0-.063.136.48.48 0 0 0 .146.593c.061.041.13.069.202.082a.545.545 0 0 0 .565-.248zm-6.319 1.586a.766.766 0 0 0 .813-.48.667.667 0 0 0-.446-.76.554.554 0 0 0-.48.107c.048-.092.081-.191.1-.294l.12-.053c.42-.207.56-.467.446-.813a.72.72 0 0 0-.358-.419.72.72 0 0 0-.548-.048 8.425 8.425 0 0 1-1.334.267c-.36 0-.773.3-.746.553.026.253.42.407.533.367.287-.1.393.08.56.2a.482.482 0 0 0 0 .093.705.705 0 0 0 .553.507.593.593 0 0 0 .5-.147c-.126.467 0 .867.287.92zm1.173-6.08c-.374-.147-.494.213-.7.453.193.32.366.567.733.447a.361.361 0 0 0 .242-.169.38.38 0 0 0 .045-.291.72.72 0 0 0-.32-.44zm-.027-2.233c.043.233.157.447.327.613a.35.35 0 0 0 .48 0l-.794-.793a.421.421 0 0 0-.013.18zm1.42 2.547a.57.57 0 0 0-.626.433.558.558 0 0 0 .275.6.554.554 0 0 0 .225.067.482.482 0 0 0 .513-.434c.053-.306-.167-.66-.387-.666zm.786-.34a.547.547 0 0 0 .14 0l-.533-.534a.47.47 0 0 0 0 .14.405.405 0 0 0 .393.394z"/> + <path fill="#0066b1" d="M134.973 107.933c-.16.367-.086.667.18.78a.913.913 0 0 0 .514-.053.977.977 0 0 0 .4.6c.4.207.92.153.973-.247a1.561 1.561 0 0 0-.293-1.013c-.14-.26-.507-.167-.374-.487.114-.255.144-.54.087-.813a.828.828 0 0 0 .633-.44.541.541 0 0 0-.293-.593c-.44-.154-.8-.074-.893.206a.664.664 0 0 0 .08.467.793.793 0 0 0-.754.453.89.89 0 0 0-.446-.42c-.347.334-.7.66-1.06.98a.663.663 0 0 0 .506.5 1.139 1.139 0 0 0 .967-.526c.019.072.053.14.1.2a.66.66 0 0 0-.327.406zm3.42-5.393c.313.666.613.766 1.186.466.434-.22.874-.426 1.334-.633.533.84.666.867 1.18.327a.671.671 0 0 0-.494-.614.316.316 0 0 0 .107-.14.35.35 0 0 0-.005-.291.347.347 0 0 0-.222-.189.315.315 0 0 0-.128-.033.329.329 0 0 0-.318.2c-.44-.747-1.034-.72-1.687.067a1.397 1.397 0 0 1-.22-.067c-.233.3-.473.593-.713.887zm5.767 13.907a.61.61 0 0 0-.107-.727 2.728 2.728 0 0 0-.42-.353.52.52 0 0 0-.04-.094v-.233a.914.914 0 0 0-.58-.833 1.062 1.062 0 0 0-.534.019 1.063 1.063 0 0 0-.459.274.564.564 0 0 0-.14.38.814.814 0 0 0 .353.667c0 .326.2.573.607.633.047.003.093.003.14 0v.107c0 .346.127.473.46.513a.666.666 0 0 0 .72-.353zm2.213-2.447c-.167 0-.587.073-.614.24-.026.167.314.393.46.473.147.08.394-.113.414-.326.02-.214-.047-.387-.26-.387zm1.147-4.5c-.094.093-.294.207-.367.373-.073.167.127.514.407.554a.41.41 0 0 0 .308-.09.419.419 0 0 0 .152-.284.557.557 0 0 0-.5-.553zm-2.127 9.04c-.085.032-.154.096-.193.178s-.044.176-.013.262c.086.34.353.38.666.394.147-.26.36-.48.127-.74a.471.471 0 0 0-.587-.094zm1.467-1.733c-.087 0-.28-.053-.347.087-.066.14.12.26.167.26a.36.36 0 0 0 .267-.12s-.04-.214-.087-.227zM145.006 112c.153.06.347 0 .327-.22s-.06-.52-.227-.553c-.167-.034-.36.333-.38.466-.02.134.16.307.28.307zm.327 2.707a.386.386 0 0 0 0-.667c-.353-.12-.573.287-.5.487a.422.422 0 0 0 .5.18zm3.5-1.061a.485.485 0 0 0-.52.3.56.56 0 0 0 .307.594.436.436 0 0 0 .513-.314.486.486 0 0 0-.3-.58zm3.793-1.693a.508.508 0 0 0 0-.174l-.513-.52c-.32-.066-.527.04-.593.32-.1.4.119.88.433.94a.7.7 0 0 0 .673-.566zm.04 2.773a.413.413 0 0 0-.52.273.464.464 0 0 0 .456.555.404.404 0 0 0 .159-.042.385.385 0 0 0 .199-.253.476.476 0 0 0-.294-.533zm-1.999 1.641a.75.75 0 0 0-.53-.226.732.732 0 0 0-.53.226.672.672 0 0 0-.103.402c.01.142.065.276.156.385a.522.522 0 0 0 .7.16c.213-.1.667-.187.707-.527s-.274-.307-.4-.42zm-.801-5.28a.445.445 0 0 0-.387-.474.668.668 0 0 0-.667.52.67.67 0 0 0 .7.454.45.45 0 0 0 .274-.182.45.45 0 0 0 .08-.318zm-4.746-.42a.828.828 0 0 0 .847-.534c.066-.26-.214-.606-.547-.666-.433-.094-.667 0-.767.346a.783.783 0 0 0 .467.854zm3.546-1.334a.46.46 0 0 0 .54-.347.501.501 0 0 0-.413-.56.483.483 0 0 0-.52.38.52.52 0 0 0 .393.527zm-9.78 7.8a.75.75 0 0 0-.627.04.43.43 0 0 0-.353-.3c-.314-.06-.447.2-.594.453.06.087.121.187.181.267l.093.087a.359.359 0 0 0 .373.06l.087-.054a.804.804 0 0 0 .113.227.213.213 0 0 0 .107.147.73.73 0 0 0 .326.246.424.424 0 0 0 .177.019.422.422 0 0 0 .169-.052.427.427 0 0 0 .214-.273.665.665 0 0 0-.266-.867zm-1.093-1.679a.667.667 0 0 0 0-.167.999.999 0 0 0 .606-.433c.174-.267 0-.567-.04-.88a.56.56 0 0 0 .107-.207.478.478 0 0 0-.087-.353c-.033-.667-.613-.86-1.173-.86a.978.978 0 0 0-.593.206 1.261 1.261 0 0 0-.16.167.912.912 0 0 0-.487-.26c-.353-.067-.593.147-.667.593a.67.67 0 0 0 .427.667.916.916 0 0 0 .473-.107.785.785 0 0 0-.1.594 1.439 1.439 0 0 0 .874.886v.04c-.04.174.346.374.506.427s.3-.08.314-.313z"/> + <path fill="#0066b1" d="M135.86 112.5a1.065 1.065 0 0 0-.294-1.26.81.81 0 0 0-1.06.194.758.758 0 0 0 .12 1.173.894.894 0 0 0 1.234-.107zm-1.067-2.347a.842.842 0 0 0 .277-1.102.845.845 0 0 0-1.07-.384c-.313.113-.367.666-.227 1.093a.826.826 0 0 0 1.02.393zm-.467 3.98a.554.554 0 0 0-.2.093l.973.974c.035-.129.053-.261.054-.394a.822.822 0 0 0-.827-.673zm-1.306-4.993a.752.752 0 0 0-.582.024.735.735 0 0 0-.385.436c-.14.36.187.88.667 1.06a.657.657 0 0 0 .52-.038.658.658 0 0 0 .333-.402c.173-.64.013-.78-.553-1.08zM144 120.36c-.247-.14-.627.067-.813.44a.516.516 0 0 0 .22.627.668.668 0 0 0 .8-.2.748.748 0 0 0-.207-.867zm-11.334-9.4a.75.75 0 0 0-.833.277.755.755 0 0 0-.127.283.912.912 0 0 0 0 .266l1.054 1.047c.226-.033.32-.207.413-.387.066-.106.118-.22.153-.34a.705.705 0 0 0 .08-.166c.1-.427-.2-.84-.74-.98zm8.427 5.746a.832.832 0 0 0-.453-1 .58.58 0 0 0-.438.016.562.562 0 0 0-.295.324.847.847 0 0 0 .18.98.811.811 0 0 0 1.006-.32zm-9.807-7.326a.493.493 0 0 0-.166.354c0 .133-.074.253 0 .386.073.134.293.094.406-.073a.74.74 0 0 0 .087-.54.222.222 0 0 0-.13-.149.217.217 0 0 0-.197.022zm10.267 9.373a.7.7 0 0 0-.813.173.797.797 0 0 0 .326.94.724.724 0 0 0 .86-.36c.154-.306.027-.56-.373-.753zm-.173-5.593a.753.753 0 0 0-.84.433.512.512 0 0 0 .333.62.67.67 0 0 0 .754-.447.447.447 0 0 0 .006-.356.45.45 0 0 0-.253-.25zm-1.02-1.54a.418.418 0 0 0 .153-.054.426.426 0 0 0 .213-.286l.1-.114c.247.18.48.394.747.094a.475.475 0 0 0 .08-.607c-.053-.073-.16-.173-.233-.167l-.24.04a.475.475 0 0 0 .104-.348.455.455 0 0 0-.057-.177.443.443 0 0 0-.121-.141.68.68 0 0 0-.24-.135.674.674 0 0 0-.74.248.836.836 0 0 0-.173.373.44.44 0 0 0-.32.14.942.942 0 0 0 .167 1.1.398.398 0 0 0 .56.034zm-1.167 2.86c-.193.174-.393.367-.26.667a.405.405 0 0 0 .392.262.409.409 0 0 0 .161-.042.553.553 0 0 0 .294-.38c0-.32-.267-.467-.587-.507z"/> + <path fill="#294492" d="M175.172 25.74c1.935-2.095 2.189-5.01.566-6.509s-4.508-1.014-6.444 1.082c-1.936 2.097-2.189 5.011-.566 6.51 1.623 1.499 4.508 1.014 6.444-1.082z"/> + <path fill="#7de2d1" d="M155.779 18.4c.8 2.207 6.88 2.633 9.067 2.72a1.41 1.41 0 0 0 1.213-.607l.267-.387a1.395 1.395 0 0 0 .133-1.333c-.853-2-3.426-7.54-5.766-7.5-2.134.04-3.827 2.62-3.827 2.62s-1.813 2.487-1.087 4.487z"/> + <path fill="#7de2d1" d="M159.213 12.053c-.246 2.327 5.034 5.38 6.96 6.407a1.43 1.43 0 0 0 1.334 0l.406-.233a1.405 1.405 0 0 0 .754-1.167c.106-2.187.22-8.28-1.907-9.273-1.933-.9-4.587.666-4.587.666s-2.74 1.48-2.96 3.6z"/> + <path fill="#42d4c6" d="M160.666 11.274a3.212 3.212 0 0 0-1.406.38 2.713 2.713 0 0 0-.074.4c-.26 2.413 5.42 5.593 7.154 6.513-.907-2.167-3.38-7.333-5.674-7.293z"/> + <path fill="#7de2d1" d="M188.206 27.78c-.8-2.2-6.88-2.667-9.066-2.713a1.4 1.4 0 0 0-1.213.606l-.261.387a1.393 1.393 0 0 0-.14 1.333c.86 2 3.427 7.547 5.774 7.507 2.133-.04 3.826-2.62 3.826-2.62s1.807-2.493 1.08-4.5z"/> + <path fill="#7de2d1" d="M184.78 34.133c.247-2.333-5.04-5.38-6.967-6.413a1.406 1.406 0 0 0-1.333 0l-.407.226a1.394 1.394 0 0 0-.74 1.174c-.113 2.186-.22 8.286 1.907 9.273 1.933.9 4.587-.667 4.587-.667s2.726-1.473 2.953-3.593z"/> + <path fill="#42d4c6" d="M177.619 27.62c.933 2.16 3.413 7.333 5.68 7.293.492-.02.974-.151 1.407-.386.031-.13.056-.261.073-.394.253-2.413-5.447-5.6-7.16-6.513z"/> + <path fill="#00bfb3" d="M57.106 44.174H.333v7.433h56.773z"/> + <path fill="#ff957d" d="M85.16 61.326H25.147v7.433H85.16z"/> + <path fill="#fa744e" d="M63.333 68.76h21.833v-7.427h-19.96a42.007 42.007 0 0 0-1.873 7.427z"/> + <path fill="#294492" d="M153.753 43.7a1.624 1.624 0 0 1-1.59-2.016 1.62 1.62 0 0 1 .503-.831c.9-.787 1.833-1.627 2.767-2.487a1.632 1.632 0 0 1 2.206 2.4c-.96.88-1.906 1.734-2.826 2.534-.293.257-.67.4-1.06.4zm8.353-7.82a1.624 1.624 0 0 1-1.503-1.007 1.62 1.62 0 0 1 .356-1.773c1.6-1.594 2.594-2.667 2.6-2.667a1.628 1.628 0 0 1 2.36 2.233c-.04.04-1.033 1.087-2.666 2.714a1.64 1.64 0 0 1-1.147.5z"/> + <path fill="#f04e98" d="M54.22 21.241 41.506 33.955a3.807 3.807 0 0 0 0 5.383L54.22 52.052a3.807 3.807 0 0 0 5.383 0l12.714-12.714a3.807 3.807 0 0 0 0-5.383L59.603 21.24a3.807 3.807 0 0 0-5.383 0z"/> + <path fill="#01ada1" d="M31.247 47.473a.621.621 0 0 0-.367-.807c-.26-.126-.573.054-.74.42a.455.455 0 0 0 .193.667.974.974 0 0 0 .914-.28zm-10.027 3.76c-.053.107.12.254.2.307a.18.18 0 0 0 .227-.08.293.293 0 0 0-.074-.287c-.053-.04-.3-.046-.353.06zm2.36-4.853c.12.053.247-.133.293-.213a.234.234 0 0 0-.093-.24.446.446 0 0 0-.273.146c-.06.074-.04.254.073.307zm2.453 3.88c-.26-.04-.52-.12-.773-.18a.38.38 0 0 0-.607.113.5.5 0 0 0 .194.667c.143.089.266.207.36.347a.732.732 0 0 0 .446.393h.287a.968.968 0 0 0 .473-.767c-.02-.246-.026-.52-.38-.573zm1.18-2.694a.301.301 0 0 0-.453.214c.006.144.035.285.086.42a.46.46 0 0 0 .594-.28c.06-.207-.074-.294-.227-.354zm5.713-.366a.46.46 0 0 0 .62-.193.775.775 0 0 0 0-.12.42.42 0 0 0 .267-.273.407.407 0 0 0-.14-.34.506.506 0 0 0-.414 0 .366.366 0 0 0-.093.113.52.52 0 0 0-.527.26.46.46 0 0 0 .287.553zm-3.54 3.734a.426.426 0 0 0-.553.2.414.414 0 0 0 .04.473h.746a.377.377 0 0 0 .074-.107.452.452 0 0 0-.307-.566zM29.2 49.02c.06-.207-.074-.287-.227-.354-.153-.066-.433 0-.453.214.004.144.034.286.086.42a.447.447 0 0 0 .594-.28zM27.186 46a.26.26 0 0 0 .094.3c.1.046.24-.054.28-.12.04-.067.046-.327-.054-.367s-.293.093-.32.187zm-3.939 1.56c-.374-.04-.48.447-.354.667s.054.173-.093.413-.22.667.26.773a.934.934 0 0 0 1.033-.666 1.086 1.086 0 0 0-.846-1.187zm20.326-.86c-.287-.667-.827-.273-.973-.447-.147-.173-.18-.633-.374-.913a.733.733 0 0 0-1.106-.253.807.807 0 0 0-.134 1.18.398.398 0 0 0-.04.073.88.88 0 0 0 .567.82.786.786 0 0 0 .4 0 .52.52 0 0 0 0 .507c.227.573.86.726 1.113.366.254-.36.074-.666.154-.753.08-.087.52-.26.393-.58zm1.527.78a.555.555 0 0 0-.18 0 .48.48 0 0 0-.313-.374.72.72 0 0 0-.747.487.394.394 0 0 0 .32.493c.1.03.207.03.307 0a.533.533 0 0 0 .2.507c.426.233.786-.127.966-.32s-.146-.707-.553-.793zm.607-2.86a.667.667 0 0 0-.754-.353c-.12 0-.233.04-.36.06l-.12-.153h-1.7c0 .04.06.08.094.113a.84.84 0 0 0 .14.247c-.134.46.133.707.5.907-.094.24-.32.466 0 .706a.42.42 0 0 0 .553 0c.3-.226.127-.486 0-.74l.353-.326.447.44c.165-.03.325-.077.48-.14a.628.628 0 0 0 .22-.234.667.667 0 0 0 .207-.233.301.301 0 0 0-.06-.294zm-10.994 2.353a.46.46 0 0 0 0-.773.627.627 0 0 0-.546 0 .52.52 0 0 0-.194.446.534.534 0 0 0 .74.327zm6.267-2.206c.087-.14-.053-.487-.24-.593h-.22a.42.42 0 0 0-.253.393c.04.247.606.367.713.2zm-2.76 2.813c-.127.36 0 .666.246.766a.913.913 0 0 0 1.014-.453.667.667 0 0 0-.454-.667.574.574 0 0 0-.806.354zm-2.82-3.406h-.553c.046.133.1.24.16.267s.326-.067.393-.267zm3.12 2.833c.44-.567.707-.133 1.153-.433a.852.852 0 0 0 .16-.187.58.58 0 0 0-.533-.907c-.323.008-.644.06-.953.154a.9.9 0 0 0-.494.94c.034.206.274.606.667.433zm.98-1.674a.32.32 0 0 0 .46-.233.6.6 0 0 0-.107-.447c-.093-.087-.533-.047-.607.14a.426.426 0 0 0 .254.54zm-7.927.507c.26-.08.293-.294.18-.787-.253-.047-.54-.193-.727.14a.433.433 0 0 0 .12.587.506.506 0 0 0 .427.06zm16.58 4.413a.447.447 0 0 0-.6.247.4.4 0 0 0 .287.513.46.46 0 0 0 .58-.293.362.362 0 0 0-.13-.405.36.36 0 0 0-.137-.062zm-3.1-.573a.248.248 0 0 0-.1 0 .867.867 0 0 0-.467-.453.707.707 0 0 0-.773.533.43.43 0 0 0 0 .16 1.44 1.44 0 0 0-.094.56c.047.127.287.4.067.554-.22.153-.56.14-.667.406l-.04.094a.38.38 0 0 0-.173-.1.667.667 0 0 0-.487.146h1.914a.606.606 0 0 1 0-.326c.073-.154.213-.3.433-.167.22.133.62.053.867-.42.246-.473-.094-1.04-.48-.987zm2.1 1.047c-.227-.06-.58.233-.627.52a.333.333 0 0 0 .16.36h.873a.266.266 0 0 0 .074-.127.74.74 0 0 0-.48-.753zm-1.693.879h1.133a.947.947 0 0 0-.326-.2.666.666 0 0 0-.807.2zm2.253-2.213c.12-.453-.114-.787-.667-.913a1.168 1.168 0 0 0-.36 0 .48.48 0 0 0-.447.227.96.96 0 0 0-.173.34.818.818 0 0 0 .74.953.834.834 0 0 0 .907-.607zm3.9.321a.267.267 0 0 0 .227-.054l-1.073-1.073a1.08 1.08 0 0 0-.274.373.6.6 0 0 0 .354.834.714.714 0 0 0 .766-.08zm-2.533 1.48a.474.474 0 0 0-.454.413h.893a.367.367 0 0 0-.44-.413zm3.493-.794c-.4-.053-.893.033-1.04.267a.194.194 0 0 0-.04.113c.113.38-.187.52-.393.727a.48.48 0 0 0-.074.1h1.247a.43.43 0 0 1 .28-.2c.067.06.133.146.2.2h.58a.76.76 0 0 0 .113-.04.254.254 0 0 0 .1-.22z"/> + <path fill="#01ada1" d="M49.18 47.413a.83.83 0 0 0-.247-.08.666.666 0 0 0 .22 0 .56.56 0 0 0 .226-.113l-1.533-1.533c-.087.186-.16.346-.233.36-.074.013-.667-.487-1.187-.28a.94.94 0 0 0-.507 1.193 1.58 1.58 0 0 0 1.48.826c.427-.113.44-.666.56-.713s.474.253.887.287a.746.746 0 0 0-.667.427.907.907 0 0 0-.073.546.726.726 0 0 0-.113.24.975.975 0 0 0 .813 1.154.94.94 0 0 0 1.147-.714.748.748 0 0 0-.107-.666.986.986 0 0 0-.667-.934zM42.14 50a.087.087 0 0 1 0-.04.5.5 0 0 0 .38-.38.46.46 0 0 0-.42-.493.433.433 0 0 0-.247 0 .833.833 0 0 0-.927.34.827.827 0 0 0-.32-.134.494.494 0 0 0-.667.294.954.954 0 0 0 .467.893.566.566 0 0 0 .667-.453c.066.058.14.108.22.146a.591.591 0 0 0 .846-.173zm-6.06 1.606h.7a.808.808 0 0 0-.2-.147.374.374 0 0 0-.5.147zm.36-2.379c.113-.293 0-.707-.213-.793a.86.86 0 0 0-.6.04.433.433 0 0 0-.26-.167.473.473 0 0 0-.514.26 1.566 1.566 0 0 0-.853-.12.668.668 0 0 1-.367-.067.586.586 0 0 0-.966.287.339.339 0 0 0-.14-.1.526.526 0 0 0-.554.38.54.54 0 0 0 .247.72.454.454 0 0 0 .573-.307c.12.096.262.16.414.187a.88.88 0 0 1 .58.26.934.934 0 0 0 .893.22.813.813 0 0 0 .62-.667v-.086a.76.76 0 0 0 .407.406c.293.114.573-.073.733-.453zm1.227-4.56a.58.58 0 0 0-1.054.053c-.117.24-.204.492-.26.753a.114.114 0 0 0-.093-.093.14.14 0 0 0-.147.113c0 .04.074.12.107.127a.14.14 0 0 0 .1-.033.92.92 0 0 0 .607.927.36.36 0 0 0 .473-.147c.27-.443.397-.957.367-1.474a1.003 1.003 0 0 0-.1-.226zm-2.054 6.539a.507.507 0 0 0-.666.287.313.313 0 0 0 0 .113h.94a.453.453 0 0 0-.274-.4zm3.433-1.346A.813.813 0 0 0 38 51.074a.42.42 0 0 0-.094.18.526.526 0 0 0 0 .353h.76v-.04a.473.473 0 0 0 0-.193.948.948 0 0 0 .667-.534.76.76 0 0 0-.287-.98zm3.407 1.513c.08-.187-.06-.4-.167-.533-.107-.134-.387 0-.473.16s0 .42.153.466c.153.047.407.087.487-.093zm-11.067-.566c-.353-.133-.746 0-.84.22a.787.787 0 0 0 .107.58h1.127a.574.574 0 0 0-.394-.8zm8.527.8h.533a.554.554 0 0 0-.2-.094.406.406 0 0 0-.333.094zm.087-2.78a.454.454 0 0 0-.267-.313c-.113 0-.433 0-.487.146-.053.147.2.367.314.434.113.066.44-.08.44-.267z"/> + <path fill="#fff" d="M58.54 39.7h-3.66l-1.22-11.393h6.1zm.406 5.083a2.237 2.237 0 1 0-4.473 0 2.237 2.237 0 0 0 4.473 0z"/> +</svg> diff --git a/x-pack/plugins/data_usage/public/app/components/chart_panel.tsx b/x-pack/plugins/data_usage/public/app/components/chart_panel.tsx index 31ae68244e98..208b1e576c0d 100644 --- a/x-pack/plugins/data_usage/public/app/components/chart_panel.tsx +++ b/x-pack/plugins/data_usage/public/app/components/chart_panel.tsx @@ -20,7 +20,7 @@ import { } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; import { LegendAction } from './legend_action'; -import { MetricTypes, MetricSeries } from '../../../common/rest_types'; +import { type MetricTypes, type MetricSeries } from '../../../common/rest_types'; import { formatBytes } from '../../utils/format_bytes'; // TODO: Remove this when we have a title for each metric type @@ -74,6 +74,9 @@ export const ChartPanel: React.FC<ChartPanelProps> = ({ }, [series]); const renderLegendAction = useCallback( ({ label }: { label: string }) => { + if (label === 'Total') { + return null; + } return ( <LegendAction label={label} diff --git a/x-pack/plugins/data_usage/public/app/components/charts.tsx b/x-pack/plugins/data_usage/public/app/components/charts.tsx index 4a2b9b4fbc87..271cfe432402 100644 --- a/x-pack/plugins/data_usage/public/app/components/charts.tsx +++ b/x-pack/plugins/data_usage/public/app/components/charts.tsx @@ -6,9 +6,8 @@ */ import React, { useCallback, useState } from 'react'; import { EuiFlexGroup } from '@elastic/eui'; -import { MetricTypes } from '../../../common/rest_types'; import { ChartPanel } from './chart_panel'; -import { UsageMetricsResponseSchemaBody } from '../../../common/rest_types'; +import type { UsageMetricsResponseSchemaBody, MetricTypes } from '../../../common/rest_types'; import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; interface ChartsProps { data: UsageMetricsResponseSchemaBody; diff --git a/x-pack/plugins/data_usage/public/app/components/charts_loading.tsx b/x-pack/plugins/data_usage/public/app/components/charts_loading.tsx new file mode 100644 index 000000000000..08c37934c451 --- /dev/null +++ b/x-pack/plugins/data_usage/public/app/components/charts_loading.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiPanel, EuiLoadingChart } from '@elastic/eui'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; + +export const ChartsLoading = ({ + 'data-test-subj': dataTestSubj, +}: { + 'data-test-subj'?: string; +}) => { + const getTestId = useTestIdGenerator(dataTestSubj); + // returns 2 loading icons for the two charts + return ( + <EuiFlexGroup + direction="column" + alignItems="center" + data-test-subj={getTestId('charts-loading')} + > + {[...Array(2)].map((i) => ( + <EuiFlexItem key={i}> + <EuiPanel paddingSize="xl" hasShadow={false} hasBorder={false}> + <EuiLoadingChart size="l" /> + </EuiPanel> + </EuiFlexItem> + ))} + </EuiFlexGroup> + ); +}; + +ChartsLoading.displayName = 'ChartsLoading'; diff --git a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx index 8ece65b7a57a..befae95393e1 100644 --- a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx +++ b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.test.tsx @@ -5,7 +5,8 @@ * 2.0. */ import React from 'react'; -import { render, waitFor } from '@testing-library/react'; +import { TestProvider } from '../../../common/test_utils'; +import { render, waitFor, within, type RenderResult } from '@testing-library/react'; import userEvent, { type UserEvent } from '@testing-library/user-event'; import { DataUsageMetrics } from './data_usage_metrics'; import { useGetDataUsageMetrics } from '../../hooks/use_get_usage_metrics'; @@ -102,21 +103,6 @@ jest.mock('@kbn/kibana-react-plugin/public', () => { to: 'now', display: 'Last 7 days', }, - { - from: 'now-30d', - to: 'now', - display: 'Last 30 days', - }, - { - from: 'now-90d', - to: 'now', - display: 'Last 90 days', - }, - { - from: 'now-1y', - to: 'now', - display: 'Last 1 year', - }, ], }; return x[k]; @@ -156,6 +142,7 @@ describe('DataUsageMetrics', () => { let user: UserEvent; const testId = 'test'; const testIdFilter = `${testId}-filter`; + let renderComponent: () => RenderResult; beforeAll(() => { jest.useFakeTimers(); @@ -167,18 +154,24 @@ describe('DataUsageMetrics', () => { beforeEach(() => { jest.clearAllMocks(); + renderComponent = () => + render( + <TestProvider> + <DataUsageMetrics data-test-subj={testId} /> + </TestProvider> + ); user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime, pointerEventsCheck: 0 }); mockUseGetDataUsageMetrics.mockReturnValue(getBaseMockedDataUsageMetrics); mockUseGetDataUsageDataStreams.mockReturnValue(getBaseMockedDataStreams); }); it('renders', () => { - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); expect(getByTestId(`${testId}`)).toBeTruthy(); }); it('should show date filter', () => { - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); const dateFilter = getByTestId(`${testIdFilter}-date-range`); expect(dateFilter).toBeTruthy(); expect(dateFilter.textContent).toContain('to'); @@ -190,12 +183,12 @@ describe('DataUsageMetrics', () => { ...getBaseMockedDataStreams, isFetching: true, }); - const { queryByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { queryByTestId } = renderComponent(); expect(queryByTestId(`${testIdFilter}-dataStreams-popoverButton`)).not.toBeTruthy(); }); it('should show data streams filter', () => { - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); expect(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)).toBeTruthy(); }); @@ -205,7 +198,7 @@ describe('DataUsageMetrics', () => { data: generateDataStreams(5), isFetching: false, }); - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); expect(getByTestId(`${testIdFilter}-dataStreams-popoverButton`)).toHaveTextContent( 'Data streams5' ); @@ -217,29 +210,76 @@ describe('DataUsageMetrics', () => { data: generateDataStreams(100), isFetching: false, }); - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); const toggleFilterButton = getByTestId(`${testIdFilter}-dataStreams-popoverButton`); expect(toggleFilterButton).toHaveTextContent('Data streams50'); }); - it('should allow de-selecting all but one data stream option', async () => { + it('should allow de-selecting data stream options', async () => { mockUseGetDataUsageDataStreams.mockReturnValue({ error: undefined, - data: generateDataStreams(5), + data: generateDataStreams(10), isFetching: false, }); - const { getByTestId, getAllByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId, getAllByTestId } = renderComponent(); const toggleFilterButton = getByTestId(`${testIdFilter}-dataStreams-popoverButton`); - expect(toggleFilterButton).toHaveTextContent('Data streams5'); + expect(toggleFilterButton).toHaveTextContent('Data streams10'); await user.click(toggleFilterButton); const allFilterOptions = getAllByTestId('dataStreams-filter-option'); - for (let i = 0; i < allFilterOptions.length - 1; i++) { + // deselect 9 options + for (let i = 0; i < allFilterOptions.length; i++) { await user.click(allFilterOptions[i]); } expect(toggleFilterButton).toHaveTextContent('Data streams1'); + expect(within(toggleFilterButton).getByRole('marquee').getAttribute('aria-label')).toEqual( + '1 active filters' + ); + }); + + it('should allow selecting/deselecting all data stream options using `select all` and `clear all`', async () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + error: undefined, + data: generateDataStreams(10), + isFetching: false, + }); + const { getByTestId } = renderComponent(); + const toggleFilterButton = getByTestId(`${testIdFilter}-dataStreams-popoverButton`); + + expect(toggleFilterButton).toHaveTextContent('Data streams10'); + await user.click(toggleFilterButton); + + // all options are selected on load + expect(within(toggleFilterButton).getByRole('marquee').getAttribute('aria-label')).toEqual( + '10 active filters' + ); + + const selectAllButton = getByTestId(`${testIdFilter}-dataStreams-selectAllButton`); + const clearAllButton = getByTestId(`${testIdFilter}-dataStreams-clearAllButton`); + + // select all is disabled + expect(selectAllButton).toBeTruthy(); + expect(selectAllButton.getAttribute('disabled')).not.toBeNull(); + + // clear all is enabled + expect(clearAllButton).toBeTruthy(); + expect(clearAllButton.getAttribute('disabled')).toBeNull(); + // click clear all and expect all options to be deselected + await user.click(clearAllButton); + expect(within(toggleFilterButton).getByRole('marquee').getAttribute('aria-label')).toEqual( + '10 available filters' + ); + // select all is enabled again + expect(await selectAllButton.getAttribute('disabled')).toBeNull(); + // click select all + await user.click(selectAllButton); + + // all options are selected and clear all is disabled + expect(within(toggleFilterButton).getByRole('marquee').getAttribute('aria-label')).toEqual( + '10 active filters' + ); }); it('should not call usage metrics API if no data streams', async () => { @@ -247,7 +287,7 @@ describe('DataUsageMetrics', () => { ...getBaseMockedDataStreams, data: [], }); - render(<DataUsageMetrics data-test-subj={testId} />); + renderComponent(); expect(mockUseGetDataUsageMetrics).toHaveBeenCalledWith( expect.any(Object), expect.objectContaining({ enabled: false }) @@ -259,7 +299,7 @@ describe('DataUsageMetrics', () => { ...getBaseMockedDataUsageMetrics, isFetching: true, }); - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); expect(getByTestId(`${testId}-charts-loading`)).toBeTruthy(); }); @@ -290,23 +330,41 @@ describe('DataUsageMetrics', () => { ], }, }); - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId } = renderComponent(); expect(getByTestId(`${testId}-charts`)).toBeTruthy(); }); - it('should refetch usage metrics with `Refresh` button click', async () => { - const refetch = jest.fn(); + it('should show no charts callout', () => { mockUseGetDataUsageMetrics.mockReturnValue({ ...getBaseMockedDataUsageMetrics, - data: ['.ds-1', '.ds-2'], - isFetched: true, + isFetched: false, }); + const { getByTestId } = renderComponent(); + expect(getByTestId(`${testId}-no-charts-callout`)).toBeTruthy(); + }); + + it('should refetch usage metrics with `Refresh` button click', async () => { + mockUseGetDataUsageDataStreams.mockReturnValue({ + error: undefined, + data: generateDataStreams(3), + isFetching: false, + }); + const refetch = jest.fn(); mockUseGetDataUsageMetrics.mockReturnValue({ ...getBaseMockedDataUsageMetrics, - isFetched: true, + data: {}, + isFetched: false, refetch, }); - const { getByTestId } = render(<DataUsageMetrics data-test-subj={testId} />); + const { getByTestId, getAllByTestId } = renderComponent(); + + const toggleFilterButton = getByTestId(`${testIdFilter}-dataStreams-popoverButton`); + + expect(toggleFilterButton).toHaveTextContent('Data streams3'); + await user.click(toggleFilterButton); + const allFilterOptions = getAllByTestId('dataStreams-filter-option'); + await user.click(allFilterOptions[2]); + const refreshButton = getByTestId(`${testIdFilter}-super-refresh-button`); // click refresh 5 times for (let i = 0; i < 5; i++) { @@ -315,7 +373,7 @@ describe('DataUsageMetrics', () => { expect(mockUseGetDataUsageMetrics).toHaveBeenLastCalledWith( expect.any(Object), - expect.objectContaining({ enabled: false }) + expect.objectContaining({ enabled: true }) ); expect(refetch).toHaveBeenCalledTimes(5); }); @@ -326,7 +384,7 @@ describe('DataUsageMetrics', () => { isFetched: true, error: new Error('Uh oh!'), }); - render(<DataUsageMetrics data-test-subj={testId} />); + renderComponent(); await waitFor(() => { expect(mockServices.notifications.toasts.addDanger).toHaveBeenCalledWith({ title: 'Error getting usage metrics', @@ -341,7 +399,7 @@ describe('DataUsageMetrics', () => { isFetched: true, error: new Error('Uh oh!'), }); - render(<DataUsageMetrics data-test-subj={testId} />); + renderComponent(); await waitFor(() => { expect(mockServices.notifications.toasts.addDanger).toHaveBeenCalledWith({ title: 'Error getting data streams', diff --git a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx index 5460c7ada038..efaa779dfe3c 100644 --- a/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx +++ b/x-pack/plugins/data_usage/public/app/components/data_usage_metrics.tsx @@ -7,18 +7,25 @@ import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; import { css } from '@emotion/react'; -import { EuiFlexGroup, EuiFlexItem, EuiLoadingElastic } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Charts } from './charts'; import { useBreadcrumbs } from '../../utils/use_breadcrumbs'; import { useKibanaContextForPlugin } from '../../utils/use_kibana'; -import { PLUGIN_NAME } from '../../../common'; +import { DEFAULT_METRIC_TYPES, type UsageMetricsRequestBody } from '../../../common/rest_types'; +import { PLUGIN_NAME } from '../../translations'; import { useGetDataUsageMetrics } from '../../hooks/use_get_usage_metrics'; import { useGetDataUsageDataStreams } from '../../hooks/use_get_data_streams'; import { useDataUsageMetricsUrlParams } from '../hooks/use_charts_url_params'; -import { DEFAULT_DATE_RANGE_OPTIONS, useDateRangePicker } from '../hooks/use_date_picker'; -import { DEFAULT_METRIC_TYPES, UsageMetricsRequestBody } from '../../../common/rest_types'; +import { + DEFAULT_DATE_RANGE_OPTIONS, + transformToUTCtime, + isDateRangeValid, +} from '../../../common/utils'; +import { useDateRangePicker } from '../hooks/use_date_picker'; import { ChartFilters, ChartFiltersProps } from './filters/charts_filters'; +import { ChartsLoading } from './charts_loading'; +import { NoDataCallout } from './no_data_callout'; import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; const EuiItemCss = css` @@ -33,6 +40,8 @@ export const DataUsageMetrics = memo( ({ 'data-test-subj': dataTestSubj = 'data-usage-metrics' }: { 'data-test-subj'?: string }) => { const getTestId = useTestIdGenerator(dataTestSubj); + const [isFirstPageLoad, setIsFirstPageLoad] = useState(true); + const { services: { chrome, appParams, notifications }, } = useKibanaContextForPlugin(); @@ -68,10 +77,10 @@ export const DataUsageMetrics = memo( }); useEffect(() => { - if (!metricTypesFromUrl) { + if (!metricTypesFromUrl && isFirstPageLoad) { setUrlMetricTypesFilter(metricsFilters.metricTypes.join(',')); } - if (!dataStreamsFromUrl && dataStreams) { + if (!dataStreamsFromUrl && dataStreams && isFirstPageLoad) { const hasMoreThan50 = dataStreams.length > 50; const _dataStreams = hasMoreThan50 ? dataStreams.slice(0, 50) : dataStreams; setUrlDataStreamsFilter(_dataStreams.map((ds) => ds.name).join(',')); @@ -83,6 +92,7 @@ export const DataUsageMetrics = memo( dataStreams, dataStreamsFromUrl, endDateFromUrl, + isFirstPageLoad, metricTypesFromUrl, metricsFilters.dataStreams, metricsFilters.from, @@ -99,32 +109,69 @@ export const DataUsageMetrics = memo( ...prevState, metricTypes: metricTypesFromUrl?.length ? metricTypesFromUrl : prevState.metricTypes, dataStreams: dataStreamsFromUrl?.length ? dataStreamsFromUrl : prevState.dataStreams, + from: startDateFromUrl ?? prevState.from, + to: endDateFromUrl ?? prevState.to, })); - }, [metricTypesFromUrl, dataStreamsFromUrl]); + }, [metricTypesFromUrl, dataStreamsFromUrl, startDateFromUrl, endDateFromUrl]); const { dateRangePickerState, onRefreshChange, onTimeChange } = useDateRangePicker(); + const isValidDateRange = useMemo( + () => + isDateRangeValid({ + start: dateRangePickerState.startDate, + end: dateRangePickerState.endDate, + }), + [dateRangePickerState.endDate, dateRangePickerState.startDate] + ); + + const enableFetchUsageMetricsData = useMemo( + () => + isValidDateRange && + metricsFilters.dataStreams.length > 0 && + metricsFilters.metricTypes.length > 0, + [isValidDateRange, metricsFilters.dataStreams, metricsFilters.metricTypes] + ); + + const utcTimeRange = useMemo( + () => + transformToUTCtime({ + start: dateRangePickerState.startDate, + end: dateRangePickerState.endDate, + isISOString: true, + }), + [dateRangePickerState] + ); const { error: errorFetchingDataUsageMetrics, - data, + data: usageMetricsData, isFetching, - isFetched, + isFetched: hasFetchedDataUsageMetricsData, refetch: refetchDataUsageMetrics, } = useGetDataUsageMetrics( { ...metricsFilters, - from: dateRangePickerState.startDate, - to: dateRangePickerState.endDate, + from: utcTimeRange.start as string, + to: utcTimeRange.end as string, }, { retry: false, - enabled: !!metricsFilters.dataStreams.length, + enabled: enableFetchUsageMetricsData, } ); + useEffect(() => { + if (!isFetching && hasFetchedDataUsageMetricsData) { + setIsFirstPageLoad(false); + } + }, [isFetching, hasFetchedDataUsageMetricsData]); + const onRefresh = useCallback(() => { + if (!enableFetchUsageMetricsData) { + return; + } refetchDataUsageMetrics(); - }, [refetchDataUsageMetrics]); + }, [enableFetchUsageMetricsData, refetchDataUsageMetrics]); const onChangeDataStreamsFilter = useCallback( (selectedDataStreams: string[]) => { @@ -195,6 +242,7 @@ export const DataUsageMetrics = memo( <ChartFilters dateRangePickerState={dateRangePickerState} isDataLoading={isFetchingDataStreams} + isUpdateDisabled={!enableFetchUsageMetricsData} onClick={refetchDataUsageMetrics} onRefresh={onRefresh} onRefreshChange={onRefreshChange} @@ -204,13 +252,14 @@ export const DataUsageMetrics = memo( data-test-subj={getTestId('filter')} /> </FlexItemWithCss> - <FlexItemWithCss> - {isFetched && data ? ( - <Charts data={data} data-test-subj={dataTestSubj} /> + {hasFetchedDataUsageMetricsData && usageMetricsData ? ( + <Charts data={usageMetricsData} data-test-subj={dataTestSubj} /> ) : isFetching ? ( - <EuiLoadingElastic data-test-subj={getTestId('charts-loading')} /> - ) : null} + <ChartsLoading data-test-subj={dataTestSubj} /> + ) : ( + <NoDataCallout data-test-subj={dataTestSubj} /> + )} </FlexItemWithCss> </EuiFlexGroup> ); diff --git a/x-pack/plugins/data_usage/public/app/components/dataset_quality_link.tsx b/x-pack/plugins/data_usage/public/app/components/dataset_quality_link.tsx index d6627f3d8dca..8e81e6091156 100644 --- a/x-pack/plugins/data_usage/public/app/components/dataset_quality_link.tsx +++ b/x-pack/plugins/data_usage/public/app/components/dataset_quality_link.tsx @@ -6,13 +6,14 @@ */ import React from 'react'; -import { EuiListGroupItem } from '@elastic/eui'; import { DataQualityDetailsLocatorParams, DATA_QUALITY_DETAILS_LOCATOR_ID, } from '@kbn/deeplinks-observability'; import { useKibanaContextForPlugin } from '../../utils/use_kibana'; import { useDateRangePicker } from '../hooks/use_date_picker'; +import { LegendActionItem } from './legend_action_item'; +import { UX_LABELS } from '../../translations'; interface DatasetQualityLinkProps { dataStreamName: string; @@ -39,6 +40,8 @@ export const DatasetQualityLink: React.FC<DatasetQualityLinkProps> = React.memo( await locator.navigate(locatorParams); } }; - return <EuiListGroupItem label="View data quality" onClick={onClickDataQuality} />; + return ( + <LegendActionItem label={UX_LABELS.dataQualityPopup.view} onClick={onClickDataQuality} /> + ); } ); diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx index 6b4806537e74..2e60561f3ed2 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter.tsx @@ -7,16 +7,13 @@ import { orderBy } from 'lodash/fp'; import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { EuiPopoverTitle, EuiSelectable } from '@elastic/eui'; +import { EuiPopoverTitle, EuiSelectable, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; -import { - METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP, - type MetricTypes, -} from '../../../../common/rest_types'; - -import { UX_LABELS } from '../../translations'; +import { METRIC_TYPE_UI_OPTIONS_VALUES_TO_API_MAP } from '../../../../common/rest_types'; +import { UX_LABELS } from '../../../translations'; import { ChartsFilterPopover } from './charts_filter_popover'; +import { ToggleAllButton } from './toggle_all_button'; import { FilterItems, FilterName, useChartsFilter } from '../../hooks'; const getSearchPlaceholder = (filterName: FilterName) => { @@ -84,6 +81,11 @@ export const ChartsFilter = memo<ChartsFilterProps>( }, }); + const addHeightToPopover = useMemo( + () => isDataStreamsFilter && numFilters + numActiveFilters > 15, + [isDataStreamsFilter, numFilters, numActiveFilters] + ); + // track popover state to pin selected options const wasPopoverOpen = useRef(isPopoverOpen); @@ -102,7 +104,7 @@ export const ChartsFilter = memo<ChartsFilterProps>( ); // augmented options based on the dataStreams filter - const sortedHostsFilterOptions = useMemo(() => { + const sortedDataStreamsFilterOptions = useMemo(() => { if (shouldPinSelectedDataStreams() || areDataStreamsSelectedOnMount) { // pin checked items to the top return orderBy('checked', 'asc', items); @@ -116,12 +118,6 @@ export const ChartsFilter = memo<ChartsFilterProps>( const onOptionsChange = useCallback( (newOptions: FilterItems) => { const optionItemsToSet = newOptions.map((option) => option); - const currChecks = optionItemsToSet.filter((option) => option.checked === 'on'); - - // don't update filter state if trying to uncheck all options - if (currChecks.length < 1) { - return; - } // update filter UI options state setItems(optionItemsToSet); @@ -136,13 +132,9 @@ export const ChartsFilter = memo<ChartsFilterProps>( // update URL params if (isMetricsFilter) { - setUrlMetricTypesFilter( - selectedItems - .map((item) => METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP[item as MetricTypes]) - .join() - ); + setUrlMetricTypesFilter(selectedItems.join(',')); } else if (isDataStreamsFilter) { - setUrlDataStreamsFilter(selectedItems.join()); + setUrlDataStreamsFilter(selectedItems.join(',')); } // reset shouldPinSelectedDataStreams, setAreDataStreamsSelectedOnMount shouldPinSelectedDataStreams(false); @@ -162,6 +154,63 @@ export const ChartsFilter = memo<ChartsFilterProps>( ] ); + const onSelectAll = useCallback(() => { + const allItems: FilterItems = items.map((item) => { + return { + ...item, + checked: 'on', + }; + }); + setItems(allItems); + const optionsToSelect = allItems.map((i) => i.label); + onChangeFilterOptions(optionsToSelect); + + if (isDataStreamsFilter) { + setUrlDataStreamsFilter(optionsToSelect.join(',')); + } + if (isMetricsFilter) { + setUrlMetricTypesFilter( + optionsToSelect + .map((option) => METRIC_TYPE_UI_OPTIONS_VALUES_TO_API_MAP[option]) + .join(',') + ); + } + }, [ + items, + isDataStreamsFilter, + isMetricsFilter, + setItems, + onChangeFilterOptions, + setUrlDataStreamsFilter, + setUrlMetricTypesFilter, + ]); + + const onClearAll = useCallback(() => { + setItems( + items.map((item) => { + return { + ...item, + checked: undefined, + }; + }) + ); + onChangeFilterOptions([]); + if (isDataStreamsFilter) { + setUrlDataStreamsFilter(''); + } + if (isMetricsFilter) { + setUrlMetricTypesFilter(''); + } + }, [ + items, + isDataStreamsFilter, + isMetricsFilter, + setItems, + onChangeFilterOptions, + setUrlDataStreamsFilter, + setUrlMetricTypesFilter, + ]); + useEffect(() => { return () => { wasPopoverOpen.current = isPopoverOpen; @@ -182,9 +231,10 @@ export const ChartsFilter = memo<ChartsFilterProps>( <EuiSelectable aria-label={`${filterName}`} emptyMessage={UX_LABELS.filterEmptyMessage(filterName)} + height={addHeightToPopover ? 380 : undefined} isLoading={isFilterLoading} onChange={onOptionsChange} - options={sortedHostsFilterOptions} + options={sortedDataStreamsFilterOptions} searchable={isSearchable ? true : undefined} searchProps={{ placeholder: getSearchPlaceholder(filterName), @@ -203,6 +253,28 @@ export const ChartsFilter = memo<ChartsFilterProps>( </EuiPopoverTitle> )} {list} + <EuiFlexGroup gutterSize="none"> + <EuiFlexItem grow={1}> + <ToggleAllButton + color="primary" + data-test-subj={getTestId(`${filterName}-selectAllButton`)} + icon="check" + label={UX_LABELS.filterSelectAll} + isDisabled={hasActiveFilters && numFilters === 0} + onClick={onSelectAll} + /> + </EuiFlexItem> + <EuiFlexItem grow={1}> + <ToggleAllButton + color="danger" + data-test-subj={getTestId(`${filterName}-clearAllButton`)} + icon="cross" + label={UX_LABELS.filterClearAll} + isDisabled={!hasActiveFilters} + onClick={onClearAll} + /> + </EuiFlexItem> + </EuiFlexGroup> </div> ); }} diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx index 3c0237c84a0c..a2f4585e592c 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filter_popover.tsx @@ -9,7 +9,7 @@ import React, { memo, useMemo } from 'react'; import { EuiFilterButton, EuiPopover, useGeneratedHtmlId } from '@elastic/eui'; import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; import { type FilterName } from '../../hooks/use_charts_filter'; -import { FILTER_NAMES } from '../../translations'; +import { FILTER_NAMES } from '../../../translations'; export const ChartsFilterPopover = memo( ({ diff --git a/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx b/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx index 3b2142e0e336..52561aa9f26f 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/charts_filters.tsx @@ -20,6 +20,7 @@ import { FilterName } from '../../hooks'; export interface ChartFiltersProps { dateRangePickerState: DateRangePickerValues; isDataLoading: boolean; + isUpdateDisabled: boolean; filterOptions: Record<FilterName, ChartsFilterProps['filterOptions']>; onRefresh: () => void; onRefreshChange: (evt: OnRefreshChangeProps) => void; @@ -33,6 +34,7 @@ export const ChartFilters = memo<ChartFiltersProps>( ({ dateRangePickerState, isDataLoading, + isUpdateDisabled, filterOptions, onClick, onRefresh, @@ -59,7 +61,8 @@ export const ChartFilters = memo<ChartFiltersProps>( const onClickRefreshButton = useCallback(() => onClick(), [onClick]); return ( - <EuiFlexGroup responsive gutterSize="m"> + <EuiFlexGroup responsive gutterSize="m" alignItems="center" justifyContent="flexEnd"> + <EuiFlexItem grow={2} /> <EuiFlexItem grow={1}> <EuiFilterGroup>{filters}</EuiFilterGroup> </EuiFlexItem> @@ -78,6 +81,7 @@ export const ChartFilters = memo<ChartFiltersProps>( data-test-subj={getTestId('super-refresh-button')} fill={false} isLoading={isDataLoading} + isDisabled={isUpdateDisabled} onClick={onClickRefreshButton} /> </EuiFlexItem> diff --git a/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx b/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx index 62c6cc542a52..1b04587b4245 100644 --- a/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx +++ b/x-pack/plugins/data_usage/public/app/components/filters/date_picker.tsx @@ -15,7 +15,7 @@ import type { OnRefreshChangeProps, } from '@elastic/eui/src/components/date_picker/types'; import { UI_SETTINGS } from '@kbn/data-plugin/common'; -import moment from 'moment'; +import { momentDateParser, DEFAULT_DATE_RANGE_OPTIONS } from '../../../../common/utils'; import { useTestIdGenerator } from '../../../hooks/use_test_id_generator'; export interface DateRangePickerValues { @@ -50,16 +50,23 @@ export const UsageMetricsDateRangePicker = memo<UsageMetricsDateRangePickerProps const kibana = useKibana<IUnifiedSearchPluginServices>(); const { uiSettings } = kibana.services; const [commonlyUsedRanges] = useState(() => { - return ( - uiSettings - ?.get(UI_SETTINGS.TIMEPICKER_QUICK_RANGES) - ?.map(({ from, to, display }: { from: string; to: string; display: string }) => { - return { + const _commonlyUsedRanges: Array<{ from: string; to: string; display: string }> = + uiSettings.get(UI_SETTINGS.TIMEPICKER_QUICK_RANGES); + if (!_commonlyUsedRanges) { + return []; + } + return _commonlyUsedRanges.reduce<DurationRange[]>( + (acc, { from, to, display }: { from: string; to: string; display: string }) => { + if (!['now-30d/d', 'now-90d/d', 'now-1y/d'].includes(from)) { + acc.push({ start: from, end: to, label: display, - }; - }) ?? [] + }); + } + return acc; + }, + [] ); }); @@ -80,9 +87,9 @@ export const UsageMetricsDateRangePicker = memo<UsageMetricsDateRangePickerProps showUpdateButton={false} timeFormat={'HH:mm'} updateButtonProps={{ iconOnly: false, fill: false }} - utcOffset={moment().utcOffset() / 60} - maxDate={moment()} - minDate={moment().subtract(9, 'days').startOf('day')} + utcOffset={0} + maxDate={momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.maxDate)} + minDate={momentDateParser(DEFAULT_DATE_RANGE_OPTIONS.minDate)} width="auto" /> ); diff --git a/x-pack/plugins/data_usage/public/app/components/filters/toggle_all_button.tsx b/x-pack/plugins/data_usage/public/app/components/filters/toggle_all_button.tsx new file mode 100644 index 000000000000..3d1c4080fcc9 --- /dev/null +++ b/x-pack/plugins/data_usage/public/app/components/filters/toggle_all_button.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/react'; +import { euiThemeVars } from '@kbn/ui-theme'; +import React, { memo } from 'react'; +import { EuiButtonEmpty, EuiButtonEmptyProps } from '@elastic/eui'; + +const EuiButtonEmptyCss = css` + border-top: ${euiThemeVars.euiBorderThin}; + border-radius: 0; +`; + +interface ToggleAllButtonProps { + 'data-test-subj'?: string; + color: EuiButtonEmptyProps['color']; + icon: EuiButtonEmptyProps['iconType']; + isDisabled: boolean; + onClick: () => void; + label: string; +} + +export const ToggleAllButton = memo<ToggleAllButtonProps>( + ({ color, 'data-test-subj': dataTestSubj, icon, isDisabled, label, onClick }) => { + // const getTestId = useTestIdGenerator(dataTestSubj); + return ( + <EuiButtonEmpty + color={color} + css={EuiButtonEmptyCss} + data-test-subj={dataTestSubj} + iconType={icon} + isDisabled={isDisabled} + onClick={onClick} + > + {label} + </EuiButtonEmpty> + ); + } +); + +ToggleAllButton.displayName = 'ToggleAllButton'; diff --git a/x-pack/plugins/data_usage/public/app/components/legend_action.tsx b/x-pack/plugins/data_usage/public/app/components/legend_action.tsx index c9059037c444..b748b7716324 100644 --- a/x-pack/plugins/data_usage/public/app/components/legend_action.tsx +++ b/x-pack/plugins/data_usage/public/app/components/legend_action.tsx @@ -5,18 +5,12 @@ * 2.0. */ import React, { useCallback } from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiButtonIcon, - EuiPopover, - EuiListGroup, - EuiListGroupItem, - EuiSpacer, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiButtonIcon, EuiPopover, EuiListGroup } from '@elastic/eui'; import { IndexManagementLocatorParams } from '@kbn/index-management-shared-types'; import { DatasetQualityLink } from './dataset_quality_link'; import { useKibanaContextForPlugin } from '../../utils/use_kibana'; +import { LegendActionItem } from './legend_action_item'; +import { UX_LABELS } from '../../translations'; interface LegendActionProps { idx: number; @@ -63,7 +57,7 @@ export const LegendAction: React.FC<LegendActionProps> = React.memo( <EuiFlexItem grow={false}> <EuiButtonIcon iconType="boxesHorizontal" - aria-label="Open data stream actions" + aria-label={UX_LABELS.dataQualityPopup.open} onClick={() => togglePopover(uniqueStreamName)} /> </EuiFlexItem> @@ -74,11 +68,15 @@ export const LegendAction: React.FC<LegendActionProps> = React.memo( anchorPosition="downRight" > <EuiListGroup gutterSize="none"> - <EuiListGroupItem label="Copy data stream name" onClick={onCopyDataStreamName} /> - <EuiSpacer size="s" /> - + <LegendActionItem + label={UX_LABELS.dataQualityPopup.copy} + onClick={onCopyDataStreamName} + /> {hasIndexManagementFeature && ( - <EuiListGroupItem label="Manage data stream" onClick={onClickIndexManagement} /> + <LegendActionItem + label={UX_LABELS.dataQualityPopup.manage} + onClick={onClickIndexManagement} + /> )} {hasDataSetQualityFeature && <DatasetQualityLink dataStreamName={label} />} </EuiListGroup> diff --git a/x-pack/plugins/data_usage/public/app/components/legend_action_item.tsx b/x-pack/plugins/data_usage/public/app/components/legend_action_item.tsx new file mode 100644 index 000000000000..3b4f0d9f698f --- /dev/null +++ b/x-pack/plugins/data_usage/public/app/components/legend_action_item.tsx @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo } from 'react'; +import { EuiListGroupItem } from '@elastic/eui'; + +export const LegendActionItem = memo( + ({ label, onClick }: { label: string; onClick: () => Promise<void> | void }) => ( + <EuiListGroupItem label={label} onClick={onClick} size="s" /> + ) +); + +LegendActionItem.displayName = 'LegendActionItem'; diff --git a/x-pack/plugins/data_usage/public/app/components/no_data_callout.tsx b/x-pack/plugins/data_usage/public/app/components/no_data_callout.tsx new file mode 100644 index 000000000000..c8c06db35106 --- /dev/null +++ b/x-pack/plugins/data_usage/public/app/components/no_data_callout.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiPanel, EuiFlexGroup, EuiFlexItem, EuiImage, EuiText, EuiTitle } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import icon from './assets/illustration_product_no_results_magnifying_glass.svg'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; + +export const NoDataCallout = ({ + 'data-test-subj': dateTestSubj, +}: { + 'data-test-subj'?: string; +}) => { + const getTestId = useTestIdGenerator(dateTestSubj); + + return ( + <EuiFlexGroup + style={{ height: 490 }} + alignItems="center" + justifyContent="center" + data-test-subj={getTestId('no-charts-callout')} + > + <EuiFlexItem grow={false}> + <EuiPanel hasBorder={true} style={{ maxWidth: 500 }}> + <EuiFlexGroup> + <EuiFlexItem> + <EuiText size="s"> + <EuiTitle> + <h3> + <FormattedMessage + id="xpack.dataUsage.noCharts.title" + defaultMessage="No chart data without data streams" + /> + </h3> + </EuiTitle> + <p> + <FormattedMessage + id="xpack.dataUsage.noCharts.description" + defaultMessage="Try searching with at least one data stream." + /> + </p> + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiImage style={{ width: 200, height: 148 }} size="200" alt="" url={icon} /> + </EuiFlexItem> + </EuiFlexGroup> + </EuiPanel> + </EuiFlexItem> + </EuiFlexGroup> + ); +}; + +NoDataCallout.displayName = 'NoDataCallout'; diff --git a/x-pack/plugins/data_usage/public/app/data_usage_metrics_page.tsx b/x-pack/plugins/data_usage/public/app/data_usage_metrics_page.tsx index 69edb7a7f01c..adc53e12b574 100644 --- a/x-pack/plugins/data_usage/public/app/data_usage_metrics_page.tsx +++ b/x-pack/plugins/data_usage/public/app/data_usage_metrics_page.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { DataUsagePage } from './components/page'; -import { DATA_USAGE_PAGE } from './translations'; +import { DATA_USAGE_PAGE } from '../translations'; import { DataUsageMetrics } from './components/data_usage_metrics'; export const DataUsageMetricsPage = () => { diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_charts_filter.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_charts_filter.tsx index d2c5dc554ff2..012a6027aadb 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_charts_filter.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_charts_filter.tsx @@ -6,13 +6,13 @@ */ import { useState, useEffect, useMemo } from 'react'; +import { DEFAULT_SELECTED_OPTIONS } from '../../../common'; import { - isDefaultMetricType, - METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP, METRIC_TYPE_VALUES, + METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP, + isDefaultMetricType, } from '../../../common/rest_types'; -import { DEFAULT_SELECTED_OPTIONS } from '../../../common'; -import { FILTER_NAMES } from '../translations'; +import { FILTER_NAMES } from '../../translations'; import { useDataUsageMetricsUrlParams } from './use_charts_url_params'; import { formatBytes } from '../../utils/format_bytes'; import { ChartsFilterProps } from '../components/filters/charts_filter'; @@ -48,6 +48,7 @@ export const useChartsFilter = ({ } => { const { dataStreams: selectedDataStreamsFromUrl, + metricTypes: selectedMetricTypesFromUrl, setUrlMetricTypesFilter, setUrlDataStreamsFilter, } = useDataUsageMetricsUrlParams(); @@ -73,8 +74,13 @@ export const useChartsFilter = ({ ? METRIC_TYPE_VALUES.map((metricType) => ({ key: metricType, label: METRIC_TYPE_API_VALUES_TO_UI_OPTIONS_MAP[metricType], - checked: isDefaultMetricType(metricType) ? 'on' : undefined, // default metrics are selected by default - disabled: isDefaultMetricType(metricType), + checked: selectedMetricTypesFromUrl + ? selectedMetricTypesFromUrl.includes(metricType) + ? 'on' + : undefined + : isDefaultMetricType(metricType) // default metrics are selected by default + ? 'on' + : undefined, 'data-test-subj': `${filterOptions.filterName}-filter-option`, })) : isDataStreamsFilter && !!filterOptions.options.length diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.test.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.test.tsx index c73e35fe1397..20f091029f5b 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.test.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.test.tsx @@ -5,12 +5,10 @@ * 2.0. */ -import moment from 'moment'; -import { METRIC_TYPE_VALUES, MetricTypes } from '../../../common/rest_types'; +import { METRIC_TYPE_VALUES, type MetricTypes } from '../../../common/rest_types'; import { getDataUsageMetricsFiltersFromUrlParams } from './use_charts_url_params'; -// FLAKY: https://github.com/elastic/kibana/issues/200888 -describe.skip('#getDataUsageMetricsFiltersFromUrlParams', () => { +describe('#getDataUsageMetricsFiltersFromUrlParams', () => { const getMetricTypesAsArray = (): MetricTypes[] => { return [...METRIC_TYPE_VALUES]; }; @@ -58,12 +56,12 @@ describe.skip('#getDataUsageMetricsFiltersFromUrlParams', () => { it('should use given relative startDate and endDate values URL params', () => { expect( getDataUsageMetricsFiltersFromUrlParams({ - startDate: moment().subtract(24, 'hours').toISOString(), - endDate: moment().toISOString(), + startDate: 'now-9d', + endDate: 'now-24h/h', }) ).toEqual({ - endDate: moment().toISOString(), - startDate: moment().subtract(24, 'hours').toISOString(), + endDate: 'now-24h/h', + startDate: 'now-9d', }); }); diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx index ed833393ad7e..37e1fdc5d1ab 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_charts_url_params.tsx @@ -6,9 +6,9 @@ */ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useHistory, useLocation } from 'react-router-dom'; -import { MetricTypes, isMetricType } from '../../../common/rest_types'; +import { type MetricTypes, isMetricType } from '../../../common/rest_types'; import { useUrlParams } from '../../hooks/use_url_params'; -import { DEFAULT_DATE_RANGE_OPTIONS } from './use_date_picker'; +import { DEFAULT_DATE_RANGE_OPTIONS } from '../../../common/utils'; interface UrlParamsDataUsageMetricsFilters { metricTypes: string; diff --git a/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx b/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx index 1b4b7e38e355..6b7e6f792b69 100644 --- a/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx +++ b/x-pack/plugins/data_usage/public/app/hooks/use_date_picker.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import moment from 'moment'; import { useCallback, useState } from 'react'; import type { DurationRange, @@ -13,16 +12,7 @@ import type { } from '@elastic/eui/src/components/date_picker/types'; import { useDataUsageMetricsUrlParams } from './use_charts_url_params'; import { DateRangePickerValues } from '../components/filters/date_picker'; - -export const DEFAULT_DATE_RANGE_OPTIONS = Object.freeze({ - autoRefreshOptions: { - enabled: false, - duration: 10000, - }, - startDate: moment().subtract(24, 'hours').startOf('day').toISOString(), - endDate: moment().toISOString(), - recentlyUsedDateRanges: [], -}); +import { DEFAULT_DATE_RANGE_OPTIONS } from '../../../common/utils'; export const useDateRangePicker = () => { const { diff --git a/x-pack/plugins/data_usage/public/application.tsx b/x-pack/plugins/data_usage/public/application.tsx index 0e6cdc6192c7..7bd2c794d5b3 100644 --- a/x-pack/plugins/data_usage/public/application.tsx +++ b/x-pack/plugins/data_usage/public/application.tsx @@ -16,8 +16,8 @@ import { PerformanceContextProvider } from '@kbn/ebt-tools'; import { useKibanaContextForPluginProvider } from './utils/use_kibana'; import { DataUsageStartDependencies, DataUsagePublicStart } from './types'; import { PLUGIN_ID } from '../common'; -import { DataUsageMetricsPage } from './app/data_usage_metrics_page'; import { DataUsageReactQueryClientProvider } from '../common/query_client'; +import { DataUsageMetricsPage } from './app/data_usage_metrics_page'; export const renderApp = ( core: CoreStart, diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx index 04cee589a523..28be186a0380 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx +++ b/x-pack/plugins/data_usage/public/hooks/use_get_data_streams.test.tsx @@ -7,11 +7,11 @@ import React, { ReactNode } from 'react'; import { QueryClient, QueryClientProvider, useQuery as _useQuery } from '@tanstack/react-query'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useGetDataUsageDataStreams } from './use_get_data_streams'; import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../common'; import { coreMock as mockCore } from '@kbn/core/public/mocks'; -import { dataUsageTestQueryClientOptions } from '../../common/test_utils/test_query_client_options'; +import { dataUsageTestQueryClientOptions } from '../../common/test_utils'; const useQueryMock = _useQuery as jest.Mock; diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx index 677bd4bdfcef..a507c6720759 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.test.tsx @@ -5,14 +5,14 @@ * 2.0. */ -import moment from 'moment'; import React, { ReactNode } from 'react'; import { QueryClient, QueryClientProvider, useQuery as _useQuery } from '@tanstack/react-query'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useGetDataUsageMetrics } from './use_get_usage_metrics'; import { DATA_USAGE_METRICS_API_ROUTE } from '../../common'; import { coreMock as mockCore } from '@kbn/core/public/mocks'; -import { dataUsageTestQueryClientOptions } from '../../common/test_utils/test_query_client_options'; +import { dataUsageTestQueryClientOptions } from '../../common/test_utils'; +import { transformToUTCtime } from '../../common/utils'; const useQueryMock = _useQuery as jest.Mock; @@ -41,16 +41,31 @@ jest.mock('../utils/use_kibana', () => { }; }); -const defaultUsageMetricsRequestBody = { - from: moment().subtract(15, 'minutes').toISOString(), - to: moment().toISOString(), - metricTypes: ['ingest_rate'], - dataStreams: ['ds-1'], -}; - describe('useGetDataUsageMetrics', () => { + const timeRange = { + start: 'now-15m', + end: 'now', + }; + const getUtcTimeRange = (range: { start: string; end: string }) => + transformToUTCtime({ + ...range, + isISOString: true, + }); + let defaultUsageMetricsRequestBody = { + from: 'now-15m', + to: 'now', + metricTypes: ['ingest_rate'], + dataStreams: ['ds-1'], + }; + beforeEach(() => { jest.clearAllMocks(); + + defaultUsageMetricsRequestBody = { + ...defaultUsageMetricsRequestBody, + from: getUtcTimeRange(timeRange).start as string, + to: getUtcTimeRange(timeRange).end as string, + }; }); it('should call the correct API', async () => { @@ -68,6 +83,19 @@ describe('useGetDataUsageMetrics', () => { }); }); + it('should not call the API if invalid date range', async () => { + const requestBody = { + ...defaultUsageMetricsRequestBody, + from: 'invalid-date', + to: 'invalid-date', + }; + await renderHook(() => useGetDataUsageMetrics(requestBody, { enabled: true }), { + wrapper: createWrapper(), + }); + + expect(mockServices.http.post).not.toHaveBeenCalled(); + }); + it('should not call the API if disabled', async () => { await renderHook( () => useGetDataUsageMetrics(defaultUsageMetricsRequestBody, { enabled: false }), diff --git a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts index 6b2ef5316b0f..649bcb45ee37 100644 --- a/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts +++ b/x-pack/plugins/data_usage/public/hooks/use_get_usage_metrics.ts @@ -8,8 +8,12 @@ import type { UseQueryOptions, UseQueryResult } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query'; import type { IHttpFetchError } from '@kbn/core-http-browser'; -import { UsageMetricsRequestBody, UsageMetricsResponseSchemaBody } from '../../common/rest_types'; +import { momentDateParser } from '../../common/utils'; import { DATA_USAGE_METRICS_API_ROUTE } from '../../common'; +import type { + UsageMetricsRequestBody, + UsageMetricsResponseSchemaBody, +} from '../../common/rest_types'; import { useKibanaContextForPlugin } from '../utils/use_kibana'; interface ErrorType { @@ -23,9 +27,15 @@ export const useGetDataUsageMetrics = ( ): UseQueryResult<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>> => { const { http } = useKibanaContextForPlugin().services; + // parse values anyway to ensure they are valid + // and to avoid sending invalid values to the server + const from = momentDateParser(body.from)?.toISOString(); + const to = momentDateParser(body.to)?.toISOString(); + return useQuery<UsageMetricsResponseSchemaBody, IHttpFetchError<ErrorType>>({ queryKey: ['get-data-usage-metrics', body], ...options, + enabled: !!(from && to) && options.enabled, keepPreviousData: true, queryFn: async ({ signal }) => { return http @@ -33,8 +43,8 @@ export const useGetDataUsageMetrics = ( signal, version: '1', body: JSON.stringify({ - from: body.from, - to: body.to, + from, + to, metricTypes: body.metricTypes, dataStreams: body.dataStreams, }), diff --git a/x-pack/plugins/data_usage/public/index.ts b/x-pack/plugins/data_usage/public/index.ts index e18b801a6a38..3ac8c6950a04 100644 --- a/x-pack/plugins/data_usage/public/index.ts +++ b/x-pack/plugins/data_usage/public/index.ts @@ -11,7 +11,6 @@ import type { DataUsagePublicStart, DataUsageSetupDependencies, DataUsageStartDependencies, - ConfigSchema, } from './types'; import { DataUsagePlugin } from './plugin'; @@ -22,4 +21,5 @@ export const plugin: PluginInitializer< DataUsagePublicStart, DataUsageSetupDependencies, DataUsageStartDependencies -> = (pluginInitializerContext: PluginInitializerContext<ConfigSchema>) => new DataUsagePlugin(); +> = (pluginInitializerContext: PluginInitializerContext) => + new DataUsagePlugin(pluginInitializerContext); diff --git a/x-pack/plugins/data_usage/public/plugin.ts b/x-pack/plugins/data_usage/public/plugin.ts index aa3b02c2b671..5878f8503882 100644 --- a/x-pack/plugins/data_usage/public/plugin.ts +++ b/x-pack/plugins/data_usage/public/plugin.ts @@ -5,16 +5,21 @@ * 2.0. */ -import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { ManagementAppMountParams } from '@kbn/management-plugin/public'; import { DataUsagePublicSetup, DataUsagePublicStart, DataUsageStartDependencies, DataUsageSetupDependencies, + DataUsagePublicConfigType, } from './types'; -import { PLUGIN_ID, PLUGIN_NAME } from '../common'; - +import { PLUGIN_ID } from '../common'; +import { PLUGIN_NAME } from './translations'; +import { + ExperimentalFeatures, + parseExperimentalConfigValue, +} from '../common/experimental_features'; export class DataUsagePlugin implements Plugin< @@ -24,30 +29,46 @@ export class DataUsagePlugin DataUsageStartDependencies > { + private config: DataUsagePublicConfigType; + private experimentalFeatures: ExperimentalFeatures; + + constructor(private readonly initializerContext: PluginInitializerContext) { + this.config = this.initializerContext.config.get<DataUsagePublicConfigType>(); + this.experimentalFeatures = {} as ExperimentalFeatures; + } + public setup( core: CoreSetup<DataUsageStartDependencies, DataUsagePublicStart>, plugins: DataUsageSetupDependencies ): DataUsagePublicSetup { const { management } = plugins; - management.sections.section.data.registerApp({ - id: PLUGIN_ID, - title: PLUGIN_NAME, - order: 6, - keywords: ['data usage', 'usage'], - async mount(params: ManagementAppMountParams) { - const [{ renderApp }, [coreStart, pluginsStartDeps, pluginStart]] = await Promise.all([ - import('./application'), - core.getStartServices(), - ]); - - return renderApp(coreStart, pluginsStartDeps, pluginStart, params); - }, - }); + this.experimentalFeatures = parseExperimentalConfigValue( + this.config.enableExperimental + ).features; + + const experimentalFeatures = this.experimentalFeatures; + + if (!experimentalFeatures.dataUsageDisabled) { + management.sections.section.data.registerApp({ + id: PLUGIN_ID, + title: PLUGIN_NAME, + order: 6, + keywords: ['data usage', 'usage'], + async mount(params: ManagementAppMountParams) { + const [{ renderApp }, [coreStart, pluginsStartDeps, pluginStart]] = await Promise.all([ + import('./application'), + core.getStartServices(), + ]); + + return renderApp(coreStart, pluginsStartDeps, pluginStart, params); + }, + }); + } return {}; } - public start(_core: CoreStart): DataUsagePublicStart { + public start(_core: CoreStart, plugins: DataUsageStartDependencies): DataUsagePublicStart { return {}; } diff --git a/x-pack/plugins/data_usage/public/app/translations.tsx b/x-pack/plugins/data_usage/public/translations.tsx similarity index 68% rename from x-pack/plugins/data_usage/public/app/translations.tsx rename to x-pack/plugins/data_usage/public/translations.tsx index ee42d3b58906..0996ec2bb6d5 100644 --- a/x-pack/plugins/data_usage/public/app/translations.tsx +++ b/x-pack/plugins/data_usage/public/translations.tsx @@ -7,6 +7,10 @@ import { i18n } from '@kbn/i18n'; +export const PLUGIN_NAME = i18n.translate('xpack.dataUsage.name', { + defaultMessage: 'Data Usage', +}); + export const FILTER_NAMES = Object.freeze({ metricTypes: i18n.translate('xpack.dataUsage.metrics.filter.metricTypes', { defaultMessage: 'Metric types', @@ -35,6 +39,9 @@ export const DATA_USAGE_PAGE = Object.freeze({ }); export const UX_LABELS = Object.freeze({ + filterSelectAll: i18n.translate('xpack.dataUsage.metrics.filter.selectAll', { + defaultMessage: 'Select all', + }), filterClearAll: i18n.translate('xpack.dataUsage.metrics.filter.clearAll', { defaultMessage: 'Clear all', }), @@ -48,4 +55,18 @@ export const UX_LABELS = Object.freeze({ defaultMessage: 'No {filterName} available', values: { filterName }, }), + dataQualityPopup: { + open: i18n.translate('xpack.dataUsage.metrics.dataQuality.open.actions', { + defaultMessage: 'Open data stream actions', + }), + copy: i18n.translate('xpack.dataUsage.metrics.dataQuality.copy.dataStream', { + defaultMessage: 'Copy data stream name', + }), + manage: i18n.translate('xpack.dataUsage.metrics.dataQuality.manage.dataStream', { + defaultMessage: 'Manage data stream', + }), + view: i18n.translate('xpack.dataUsage.metrics.dataQuality.view', { + defaultMessage: 'View data quality', + }), + }, }); diff --git a/x-pack/plugins/data_usage/public/types.ts b/x-pack/plugins/data_usage/public/types.ts index e65865dc3182..8c92d27c3d9b 100644 --- a/x-pack/plugins/data_usage/public/types.ts +++ b/x-pack/plugins/data_usage/public/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { schema, TypeOf } from '@kbn/config-schema'; import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; import { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; @@ -23,5 +24,21 @@ export interface DataUsageStartDependencies { management: ManagementStart; share: SharePluginStart; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ConfigSchema {} + +const schemaObject = schema.object({ + /** + * For internal use. A list of string values (comma delimited) that will enable experimental + * type of functionality that is not yet released. Valid values for this settings need to + * be defined in: + * `x-pack/plugins/dataUsage/common/experimental_features.ts` + * under the `allowedExperimentalValues` object + * + * @example + * xpack.dataUsage.enableExperimental: ['someFeature'] + */ + enableExperimental: schema.arrayOf(schema.string(), { + defaultValue: () => [], + }), +}); + +export type DataUsagePublicConfigType = TypeOf<typeof schemaObject>; diff --git a/x-pack/plugins/data_usage/server/config.ts b/x-pack/plugins/data_usage/server/config.ts index c6721592b6aa..c00c08bb1b05 100644 --- a/x-pack/plugins/data_usage/server/config.ts +++ b/x-pack/plugins/data_usage/server/config.ts @@ -26,6 +26,19 @@ export const configSchema = schema.object({ ), }) ), + /** + * For internal use. A list of string values (comma delimited) that will enable experimental + * type of functionality that is not yet released. Valid values for this settings need to + * be defined in: + * `x-pack/plugins/dataUsage/common/experimental_features.ts` + * under the `allowedExperimentalValues` object + * + * @example + * xpack.dataUsage.enableExperimental: ['someFeature'] + */ + enableExperimental: schema.arrayOf(schema.string(), { + defaultValue: () => [], + }), }); export type DataUsageConfigType = TypeOf<typeof configSchema>; diff --git a/x-pack/plugins/data_usage/server/index.ts b/x-pack/plugins/data_usage/server/index.ts index 66d839303d71..826486dc717f 100644 --- a/x-pack/plugins/data_usage/server/index.ts +++ b/x-pack/plugins/data_usage/server/index.ts @@ -25,6 +25,9 @@ export type { DataUsageServerSetup, DataUsageServerStart }; export const config: PluginConfigDescriptor<DataUsageConfigType> = { schema: configSchema, + exposeToBrowser: { + enableExperimental: true, + }, }; export const plugin: PluginInitializer< diff --git a/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts b/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts index 2330e465d9b1..374c4b9c82e7 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/data_streams.test.ts @@ -84,6 +84,48 @@ describe('registerDataStreamsRoute', () => { }); }); + it('should not include data streams with 0 size', async () => { + mockGetMeteringStats.mockResolvedValue({ + datastreams: [ + { + name: 'datastream1', + size_in_bytes: 100, + }, + { + name: 'datastream2', + size_in_bytes: 200, + }, + { + name: 'datastream3', + size_in_bytes: 0, + }, + { + name: 'datastream4', + size_in_bytes: 0, + }, + ], + }); + const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); + const mockResponse = httpServerMock.createResponseFactory(); + const mockRouter = mockCore.http.createRouter.mock.results[0].value; + const [[, handler]] = mockRouter.versioned.get.mock.results[0].value.addVersion.mock.calls; + await handler(context, mockRequest, mockResponse); + + expect(mockResponse.ok).toHaveBeenCalledTimes(1); + expect(mockResponse.ok.mock.calls[0][0]).toEqual({ + body: [ + { + name: 'datastream2', + storageSizeBytes: 200, + }, + { + name: 'datastream1', + storageSizeBytes: 100, + }, + ], + }); + }); + it('should return correct error if metering stats request fails', async () => { // using custom error for test here to avoid having to import the actual error class mockGetMeteringStats.mockRejectedValue( @@ -105,7 +147,7 @@ describe('registerDataStreamsRoute', () => { it.each([ ['no datastreams', {}, []], ['empty array', { datastreams: [] }, []], - ['an empty element', { datastreams: [{}] }, [{ name: undefined, storageSizeBytes: 0 }]], + ['an empty element', { datastreams: [{}] }, []], ])('should return empty array when no stats data with %s', async (_, stats, res) => { mockGetMeteringStats.mockResolvedValue(stats); const mockRequest = httpServerMock.createKibanaRequest({ body: {} }); diff --git a/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts b/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts index bfa236aa1cec..6a1a4517bf6e 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/data_streams.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { DataStreamsResponseSchema } from '../../../common/rest_types'; +import { DataStreamsResponseSchema, DataStreamsRequestSchema } from '../../../common/rest_types'; import { DATA_USAGE_DATA_STREAMS_API_ROUTE } from '../../../common'; import { DataUsageContext, DataUsageRouter } from '../../types'; import { getDataStreamsHandler } from './data_streams_handler'; @@ -23,7 +23,7 @@ export const registerDataStreamsRoute = ( { version: '1', validate: { - request: {}, + request: DataStreamsRequestSchema, response: { 200: DataStreamsResponseSchema, }, diff --git a/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts b/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts index 9abd898358e9..726aa157050f 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/data_streams_handler.ts @@ -9,12 +9,15 @@ import { RequestHandler } from '@kbn/core/server'; import { DataUsageContext, DataUsageRequestHandlerContext } from '../../types'; import { errorHandler } from '../error_handler'; import { getMeteringStats } from '../../utils/get_metering_stats'; +import { DataStreamsRequestQuery } from '../../../common/rest_types/data_streams'; export const getDataStreamsHandler = ( dataUsageContext: DataUsageContext -): RequestHandler<never, never, unknown, DataUsageRequestHandlerContext> => { +): RequestHandler<never, DataStreamsRequestQuery, unknown, DataUsageRequestHandlerContext> => { const logger = dataUsageContext.logFactory.get('dataStreamsRoute'); - return async (context, _, response) => { + return async (context, request, response) => { + const { includeZeroStorage } = request.query; + logger.debug('Retrieving user data streams'); try { @@ -27,10 +30,15 @@ export const getDataStreamsHandler = ( meteringStats && !!meteringStats.length ? meteringStats .sort((a, b) => b.size_in_bytes - a.size_in_bytes) - .map((stat) => ({ - name: stat.name, - storageSizeBytes: stat.size_in_bytes ?? 0, - })) + .reduce<Array<{ name: string; storageSizeBytes: number }>>((acc, stat) => { + if (includeZeroStorage || stat.size_in_bytes > 0) { + acc.push({ + name: stat.name, + storageSizeBytes: stat.size_in_bytes ?? 0, + }); + } + return acc; + }, []) : []; return response.ok({ diff --git a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts index d6337bbcc8dc..f2bccd6d9c6b 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics.test.ts @@ -4,7 +4,6 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import moment from 'moment'; import type { MockedKeys } from '@kbn/utility-types-jest'; import type { CoreSetup } from '@kbn/core/server'; import { registerUsageMetricsRoute } from './usage_metrics'; @@ -20,6 +19,16 @@ import { DATA_USAGE_METRICS_API_ROUTE } from '../../../common'; import { createMockedDataUsageContext } from '../../mocks'; import { CustomHttpRequestError } from '../../utils'; import { AutoOpsError } from '../../services/errors'; +import { transformToUTCtime } from '../../../common/utils'; + +const timeRange = { + start: 'now-15m', + end: 'now', +}; +const utcTimeRange = transformToUTCtime({ + ...timeRange, + isISOString: true, +}); describe('registerUsageMetricsRoute', () => { let mockCore: MockedKeys<CoreSetup<{}, DataUsageServerStart>>; @@ -56,8 +65,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: moment().subtract(15, 'minutes').toISOString(), - to: moment().toISOString(), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate'], dataStreams: [], }, @@ -123,8 +132,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: moment().subtract(15, 'minutes').toISOString(), - to: moment().toISOString(), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate', 'storage_retained'], dataStreams: ['.ds-1', '.ds-2'], }, @@ -191,8 +200,8 @@ describe('registerUsageMetricsRoute', () => { const mockRequest = httpServerMock.createKibanaRequest({ body: { - from: moment().subtract(15, 'minutes').toISOString(), - to: moment().toISOString(), + from: utcTimeRange.start, + to: utcTimeRange.end, metricTypes: ['ingest_rate'], dataStreams: ['.ds-1', '.ds-2'], }, diff --git a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts index 6907a683696a..eb27c2a9b7ed 100644 --- a/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts +++ b/x-pack/plugins/data_usage/server/routes/internal/usage_metrics_handler.ts @@ -5,8 +5,10 @@ * 2.0. */ +import { chunk } from 'lodash/fp'; import { RequestHandler } from '@kbn/core/server'; -import { +import { momentDateParser } from '../../../common/utils'; +import type { MetricTypes, UsageMetricsAutoOpsResponseSchemaBody, UsageMetricsRequestBody, @@ -30,10 +32,23 @@ export const getUsageMetricsHandler = ( const core = await context.core; const esClient = core.elasticsearch.client.asCurrentUser; + const getDataStreams = (name: string[]) => + esClient.indices.getDataStream({ name, expand_wildcards: 'all' }); logger.debug(`Retrieving usage metrics`); const { from, to, metricTypes, dataStreams: requestDsNames } = request.body; + // parse date strings to validate + const parsedFrom = momentDateParser(from)?.toISOString(); + const parsedTo = momentDateParser(to)?.toISOString(); + + if (!parsedFrom || !parsedTo) { + const customErrorMessage = `[request body.${ + !parsedTo ? 'to' : 'from' + }] Invalid date range ${!parsedTo ? to : from} is out of range`; + return errorHandler(logger, response, new CustomHttpRequestError(customErrorMessage, 400)); + } + // redundant check as we don't allow making requests via UI without data streams, // but it's here to make sure the request body is validated before requesting metrics from auto-ops if (!requestDsNames?.length) { @@ -43,15 +58,24 @@ export const getUsageMetricsHandler = ( new CustomHttpRequestError('[request body.dataStreams]: no data streams selected', 400) ); } - let dataStreamsResponse; + + let dataStreamsResponse: Array<{ name: string }>; try { - // Attempt to fetch data streams - const { data_streams: dataStreams } = await esClient.indices.getDataStream({ - name: requestDsNames, - expand_wildcards: 'all', - }); - dataStreamsResponse = dataStreams; + if (requestDsNames.length <= 50) { + logger.debug(`Retrieving usage metrics`); + const { data_streams: dataStreams } = await getDataStreams(requestDsNames); + dataStreamsResponse = dataStreams; + } else { + logger.debug(`Retrieving usage metrics in chunks of 50`); + // Attempt to fetch data streams in chunks of 50 + const dataStreamsChunks = Math.ceil(requestDsNames.length / 50); + const chunkedDsLists = chunk(dataStreamsChunks, requestDsNames); + const chunkedDataStreams = await Promise.all( + chunkedDsLists.map((dsList) => getDataStreams(dsList)) + ); + dataStreamsResponse = chunkedDataStreams.flatMap((ds) => ds.data_streams); + } } catch (error) { return errorHandler( logger, @@ -62,8 +86,8 @@ export const getUsageMetricsHandler = ( const dataUsageService = new DataUsageService(logger); const metrics = await dataUsageService.getMetrics({ - from, - to, + from: parsedFrom, + to: parsedTo, metricTypes: formatStringParams(metricTypes) as MetricTypes[], dataStreams: formatStringParams(dataStreamsResponse.map((ds) => ds.name)), }); diff --git a/x-pack/plugins/data_usage/server/services/autoops_api.ts b/x-pack/plugins/data_usage/server/services/autoops_api.ts index 9fd742a3e73f..d98b0c507fe1 100644 --- a/x-pack/plugins/data_usage/server/services/autoops_api.ts +++ b/x-pack/plugins/data_usage/server/services/autoops_api.ts @@ -6,7 +6,7 @@ */ import https from 'https'; -import dateMath from '@kbn/datemath'; + import { SslConfig, sslSchema } from '@kbn/server-http-tools'; import apm from 'elastic-apm-node'; @@ -14,10 +14,11 @@ import { Logger } from '@kbn/logging'; import type { AxiosError, AxiosRequestConfig } from 'axios'; import axios from 'axios'; import { LogMeta } from '@kbn/core/server'; +import { momentDateParser } from '../../common/utils'; import { UsageMetricsAutoOpsResponseSchema, - UsageMetricsAutoOpsResponseSchemaBody, - UsageMetricsRequestBody, + type UsageMetricsAutoOpsResponseSchemaBody, + type UsageMetricsRequestBody, } from '../../common/rest_types'; import { AutoOpsConfig } from '../types'; import { AutoOpsError } from './errors'; @@ -30,7 +31,6 @@ const AUTO_OPS_MISSING_CONFIG_ERROR = 'Missing autoops configuration'; const getAutoOpsAPIRequestUrl = (url?: string, projectId?: string): string => `${url}/monitoring/serverless/v1/projects/${projectId}/metrics`; -const dateParser = (date: string) => dateMath.parse(date)?.toISOString(); export class AutoOpsAPIService { private logger: Logger; constructor(logger: Logger) { @@ -76,8 +76,8 @@ export class AutoOpsAPIService { const requestConfig: AxiosRequestConfig = { url: getAutoOpsAPIRequestUrl(autoopsConfig.api?.url, cloudSetup?.serverless.projectId), data: { - from: dateParser(requestBody.from), - to: dateParser(requestBody.to), + from: momentDateParser(requestBody.from)?.toISOString(), + to: momentDateParser(requestBody.to)?.toISOString(), size: requestBody.dataStreams.length, level: 'datastream', metric_types: requestBody.metricTypes, @@ -123,7 +123,7 @@ export class AutoOpsAPIService { `${AUTO_OPS_AGENT_CREATION_PREFIX} with an error ${error} ${requestConfigDebugStatus}`, errorMetadataWithRequestConfig ); - throw new Error(withRequestIdMessage(error.message)); + throw new AutoOpsError(withRequestIdMessage(error.message)); } const errorLogCodeCause = `${error.code} ${this.convertCauseErrorsToString(error)}`; @@ -152,14 +152,16 @@ export class AutoOpsAPIService { `${AUTO_OPS_AGENT_CREATION_PREFIX} while sending the request to the AutoOps API: ${errorLogCodeCause} ${requestConfigDebugStatus}`, errorMetadataWithRequestConfig ); - throw new Error(withRequestIdMessage(`no response received from the AutoOps API`)); + throw new AutoOpsError(withRequestIdMessage(`no response received from the AutoOps API`)); } else { // Something happened in setting up the request that triggered an Error this.logger.error( - `${AUTO_OPS_AGENT_CREATION_PREFIX} to be created ${errorLogCodeCause} ${requestConfigDebugStatus}`, + `${AUTO_OPS_AGENT_CREATION_PREFIX} to be created ${errorLogCodeCause} ${requestConfigDebugStatus} ${error.toJSON()}`, errorMetadataWithRequestConfig ); - throw new AutoOpsError(withRequestIdMessage(AGENT_CREATION_FAILED_ERROR)); + throw new AutoOpsError( + withRequestIdMessage(`${AGENT_CREATION_FAILED_ERROR}, ${error.message}`) + ); } } ); diff --git a/x-pack/plugins/data_usage/server/services/index.ts b/x-pack/plugins/data_usage/server/services/index.ts index 69db6b590c6f..56e449c8a567 100644 --- a/x-pack/plugins/data_usage/server/services/index.ts +++ b/x-pack/plugins/data_usage/server/services/index.ts @@ -6,7 +6,7 @@ */ import { ValidationError } from '@kbn/config-schema'; import { Logger } from '@kbn/logging'; -import { MetricTypes } from '../../common/rest_types'; +import type { MetricTypes } from '../../common/rest_types'; import { AutoOpsError } from './errors'; import { AutoOpsAPIService } from './autoops_api'; diff --git a/x-pack/plugins/data_usage/tsconfig.json b/x-pack/plugins/data_usage/tsconfig.json index 309bad3e1b63..8647f7957451 100644 --- a/x-pack/plugins/data_usage/tsconfig.json +++ b/x-pack/plugins/data_usage/tsconfig.json @@ -33,6 +33,8 @@ "@kbn/server-http-tools", "@kbn/utility-types-jest", "@kbn/datemath", + "@kbn/ui-theme", + "@kbn/i18n-react", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/discover_enhanced/tsconfig.json b/x-pack/plugins/discover_enhanced/tsconfig.json index ada69e95f32a..6839f4c2c18e 100644 --- a/x-pack/plugins/discover_enhanced/tsconfig.json +++ b/x-pack/plugins/discover_enhanced/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "target/types", }, - "include": ["*.ts", "common/**/*", "public/**/*", "server/**/*"], + "include": ["*.ts", "common/**/*", "public/**/*", "server/**/*", "ui_tests/**/*"], "kbn_references": [ "@kbn/core", "@kbn/data-plugin", @@ -21,6 +21,7 @@ "@kbn/presentation-publishing", "@kbn/data-views-plugin", "@kbn/unified-search-plugin", + "@kbn/scout", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/discover_enhanced/ui_tests/README.md b/x-pack/plugins/discover_enhanced/ui_tests/README.md new file mode 100644 index 000000000000..e6c5943e1533 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/README.md @@ -0,0 +1,20 @@ +## How to run tests +First start the servers with + +```bash +// ESS +node scripts/scout_start_servers.js --stateful +// Serverless +node scripts/scout_start_servers.js --serverless=es +``` + +Then you can run the tests multiple times in another terminal with: + +```bash +// ESS +npx playwright test --config x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts --grep @ess +// Serverless +npx playwright test --config x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts --grep @svlSearch // @svlOblt, @svlSecurity +``` + +Test results are available in `x-pack/plugins/discover_enhanced/ui_tests/output` diff --git a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/assertion_messages.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/assertion_messages.ts new file mode 100644 index 000000000000..6ccbe4df990c --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/assertion_messages.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const QUERY_BAR_VALIDATION = { + SUGGESTIONS_COUNT: 'The query bar suggestions count should be', +}; diff --git a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/constants.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/constants.ts new file mode 100644 index 000000000000..3ac2c34586f4 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/constants.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const LOGSTASH_DEFAULT_START_TIME = '2015-09-19T06:31:44.000Z'; +export const LOGSTASH_DEFAULT_END_TIME = '2015-09-23T18:31:44.000Z'; + +export const DATA_VIEW_ID = { + ECOMMERCE: '5193f870-d861-11e9-a311-0fa548c5f953', + LOGSTASH: 'logstash-*', +}; + +export const DATA_VIEW = { + ECOMMERCE: 'ecommerce', + LOGSTASH: 'logstash-*', +}; + +export const LOGSTASH_OUT_OF_RANGE_DATES = { + from: 'Mar 1, 2020 @ 00:00:00.000', + to: 'Nov 1, 2020 @ 00:00:00.000', +}; + +export const LOGSTASH_IN_RANGE_DATES = { + from: 'Sep 19, 2015 @ 06:31:44.000', + to: 'Sep 23, 2015 @ 18:31:44.000', +}; + +export const ES_ARCHIVES = { + LOGSTASH: 'x-pack/test/functional/es_archives/logstash_functional', + NO_TIME_FIELD: 'test/functional/fixtures/es_archiver/index_pattern_without_timefield', + ECOMMERCE: 'x-pack/test/functional/es_archives/reporting/ecommerce', +}; + +export const KBN_ARCHIVES = { + INVALID_SCRIPTED_FIELD: 'test/functional/fixtures/kbn_archiver/invalid_scripted_field', + NO_TIME_FIELD: 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield', + DASHBOARD_DRILLDOWNS: + 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns', + DISCOVER: 'test/functional/fixtures/kbn_archiver/discover', + ECOMMERCE: 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json', +}; diff --git a/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.ts new file mode 100644 index 000000000000..4cff802b3b89 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/index.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + test as base, + PageObjects, + createLazyPageObject, + ScoutTestFixtures, + ScoutWorkerFixtures, +} from '@kbn/scout'; +import { DemoPage } from './page_objects'; + +export interface ExtendedScoutTestFixtures extends ScoutTestFixtures { + pageObjects: PageObjects & { + demo: DemoPage; + }; +} + +export const test = base.extend<ExtendedScoutTestFixtures, ScoutWorkerFixtures>({ + pageObjects: async ({ pageObjects, page }, use) => { + const extendedPageObjects = { + ...pageObjects, + demo: createLazyPageObject(DemoPage, page), + }; + + await use(extendedPageObjects); + }, +}); + +export * as testData from './constants'; +export * as assertionMessages from './assertion_messages'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/page_objects/demo.ts similarity index 58% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.ts rename to x-pack/plugins/discover_enhanced/ui_tests/fixtures/page_objects/demo.ts index 74845b5f257a..4c65384b9c81 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/translations.ts +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/page_objects/demo.ts @@ -5,11 +5,12 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; +import { ScoutPage } from '@kbn/scout'; -export const COLUMN_STATUS = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.columns.statusTitle', - { - defaultMessage: 'Status', +export class DemoPage { + constructor(private readonly page: ScoutPage) {} + + async goto() { + this.page.gotoApp('not_implemented'); } -); +} diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/index.ts b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/page_objects/index.ts similarity index 85% rename from x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/index.ts rename to x-pack/plugins/discover_enhanced/ui_tests/fixtures/page_objects/index.ts index 9e2785233684..47afc9c11fe7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/index.ts +++ b/x-pack/plugins/discover_enhanced/ui_tests/fixtures/page_objects/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ErrorState } from './error_state'; +export { DemoPage } from './demo'; diff --git a/x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts b/x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts new file mode 100644 index 000000000000..34b370396b67 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/playwright.config.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createPlaywrightConfig } from '@kbn/scout'; + +// eslint-disable-next-line import/no-default-export +export default createPlaywrightConfig({ + testDir: './tests', +}); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/error_handling.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/error_handling.spec.ts new file mode 100644 index 000000000000..914558fbdc97 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/error_handling.spec.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from '@kbn/scout'; +import { test, testData } from '../fixtures'; + +test.describe('Discover app - errors', { tag: ['@ess'] }, () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await kbnClient.savedObjects.clean({ types: ['search', 'index-pattern'] }); + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.INVALID_SCRIPTED_FIELD); + await uiSettings.setDefaultTime({ + from: testData.LOGSTASH_DEFAULT_START_TIME, + to: testData.LOGSTASH_DEFAULT_END_TIME, + }); + }); + + test.afterAll(async ({ kbnClient }) => { + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); + + test('should render invalid scripted field error', async ({ page }) => { + await page.testSubj.locator('discoverErrorCalloutTitle').waitFor({ state: 'visible' }); + await expect( + page.testSubj.locator('painlessStackTrace'), + 'Painless error stacktrace should be displayed' + ).toBeVisible(); + }); +}); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_search_embeddable.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_search_embeddable.spec.ts new file mode 100644 index 000000000000..7103f2b25e63 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_search_embeddable.spec.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ScoutWorkerFixtures, expect } from '@kbn/scout'; +import { test, testData } from '../fixtures'; + +const createSavedSearch = async ( + kbnClient: ScoutWorkerFixtures['kbnClient'], + searchId: string, + searchTitle: string, + dataViewId: string +) => + await kbnClient.savedObjects.create({ + type: 'search', + id: searchId, + overwrite: false, + attributes: { + title: searchTitle, + description: '', + columns: ['agent', 'bytes', 'clientip'], + sort: [['@timestamp', 'desc']], + kibanaSavedObjectMeta: { + searchSourceJSON: + '{"highlightAll":true,"version":true,"query":{"language":"lucene","query":""},"filter":[],"indexRefName":"kibanaSavedObjectMeta.searchSourceJSON.index"}', + }, + }, + references: [ + { + id: dataViewId, + name: 'kibanaSavedObjectMeta.searchSourceJSON.index', + type: 'index-pattern', + }, + ], + }); + +test.describe( + 'Discover app - saved search embeddable', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + const SAVED_SEARCH_TITLE = 'TempSearch'; + const SAVED_SEARCH_ID = '90943e30-9a47-11e8-b64d-95841ca0b247'; + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, // TODO: investigate why it is required for `node scripts/playwright_test.js` run + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + }); + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsPrivilegedUser(); + await pageObjects.dashboard.goto(); + }); + + test('should allow removing the dashboard panel after the underlying saved search has been deleted', async ({ + kbnClient, + page, + pageObjects, + }) => { + await pageObjects.dashboard.openNewDashboard(); + await createSavedSearch( + kbnClient, + SAVED_SEARCH_ID, + SAVED_SEARCH_TITLE, + testData.DATA_VIEW_ID.LOGSTASH + ); + await pageObjects.dashboard.addPanelFromLibrary(SAVED_SEARCH_TITLE); + await page.testSubj.locator('savedSearchTotalDocuments').waitFor({ + state: 'visible', + }); + + await pageObjects.dashboard.saveDashboard('Dashboard with deleted saved search'); + await kbnClient.savedObjects.delete({ + type: 'search', + id: SAVED_SEARCH_ID, + }); + + await page.reload(); + await page.waitForLoadingIndicatorHidden(); + await expect( + page.testSubj.locator('embeddableError'), + 'Embeddable error should be displayed' + ).toBeVisible(); + + await pageObjects.dashboard.removePanel('embeddableError'); + await expect( + page.testSubj.locator('embeddableError'), + 'Embeddable error should not be displayed' + ).toBeHidden(); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_searches.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_searches.spec.ts new file mode 100644 index 000000000000..1398f5f24ab2 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/saved_searches.spec.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from '@kbn/scout'; +import { test, testData } from '../fixtures'; +import type { ExtendedScoutTestFixtures } from '../fixtures'; + +const assertNoFilterAndEmptyQuery = async ( + filterBadge: { field: string; value: string }, + pageObjects: ExtendedScoutTestFixtures['pageObjects'], + page: ExtendedScoutTestFixtures['page'] +) => { + expect( + // checking if filter exists, enabled or disabled + await pageObjects.filterBar.hasFilter(filterBadge), + `Filter ${JSON.stringify(filterBadge)} should not exist` + ).toBe(false); + await expect( + page.testSubj.locator('queryInput'), + 'Query Bar input field should be empty' + ).toHaveText(''); +}; + +const assertDataViewIsSelected = async (page: ExtendedScoutTestFixtures['page'], name: string) => + await expect( + page.testSubj.locator('*dataView-switch-link'), + 'Incorrect data view is selected' + ).toHaveText(name); + +test.describe( + 'Discover app - saved searches', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + const START_TIME = '2019-04-27T23:56:51.374Z'; + const END_TIME = '2019-08-23T16:18:51.821Z'; + const PANEL_NAME = 'Ecommerce Data'; + const SEARCH_QUERY = 'customer_gender:MALE'; + const SAVED_SEARCH_NAME = 'test-unselect-saved-search'; + const filterFieldAndValue = { + field: 'category', + value: `Men's Shoes`, + }; + + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.ECOMMERCE); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DISCOVER); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.ECOMMERCE); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.ECOMMERCE, + 'timepicker:timeDefaults': `{ "from": "${START_TIME}", "to": "${END_TIME}"}`, + }); + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth }) => { + await browserAuth.loginAsPrivilegedUser(); + }); + + test('should customize time range on dashboards', async ({ pageObjects, page }) => { + await pageObjects.dashboard.goto(); + await pageObjects.dashboard.openNewDashboard(); + await pageObjects.dashboard.addPanelFromLibrary(PANEL_NAME); + await page.testSubj.locator('savedSearchTotalDocuments').waitFor({ + state: 'visible', + }); + + await pageObjects.dashboard.customizePanel({ + name: PANEL_NAME, + customTimeRageCommonlyUsed: { value: 'Last_90 days' }, + }); + await expect( + page.testSubj.locator('embeddedSavedSearchDocTable').locator('.euiDataGrid__noResults'), + 'No results message in Saved Search panel should be visible' + ).toBeVisible(); + }); + + test(`should unselect saved search when navigating to a 'new'`, async ({ + pageObjects, + page, + }) => { + await pageObjects.discover.goto(); + await assertDataViewIsSelected(page, testData.DATA_VIEW.ECOMMERCE); + await pageObjects.filterBar.addFilter({ + ...filterFieldAndValue, + operator: 'is', + }); + await page.testSubj.fill('queryInput', SEARCH_QUERY); + await page.testSubj.click('querySubmitButton'); + await pageObjects.discover.waitForHistogramRendered(); + + await pageObjects.discover.saveSearch(SAVED_SEARCH_NAME); + await pageObjects.discover.waitForHistogramRendered(); + + expect( + await pageObjects.filterBar.hasFilter({ + ...filterFieldAndValue, + enabled: true, // Filter is enabled by default + }) + ).toBe(true); + await expect(page.testSubj.locator('queryInput')).toHaveText(SEARCH_QUERY); + + // create new search + await pageObjects.discover.clickNewSearch(); + await assertDataViewIsSelected(page, testData.DATA_VIEW.ECOMMERCE); + await assertNoFilterAndEmptyQuery(filterFieldAndValue, pageObjects, page); + + // change data view + await pageObjects.discover.selectDataView(testData.DATA_VIEW.LOGSTASH); + await assertNoFilterAndEmptyQuery(filterFieldAndValue, pageObjects, page); + + // change data view again + await pageObjects.discover.selectDataView(testData.DATA_VIEW.ECOMMERCE); + await assertNoFilterAndEmptyQuery(filterFieldAndValue, pageObjects, page); + + // create new search again + await pageObjects.discover.clickNewSearch(); + await assertDataViewIsSelected(page, testData.DATA_VIEW.ECOMMERCE); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts new file mode 100644 index 000000000000..04836afb99b5 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions.spec.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from '@kbn/scout'; +import { test, testData, assertionMessages } from '../fixtures'; + +test.describe( + 'Discover app - value suggestions: useTimeRange enabled', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, // TODO: investigate why it is required for `node scripts/playwright_test.js` run + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + }); + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); + + test('dont show up if outside of range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_OUT_OF_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect(page.testSubj.locator('autoCompleteSuggestionText')).toHaveCount(0); + }); + + test('show up if in range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_IN_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(5); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('jpg'); + }); + + test('also displays descriptions for operators', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_IN_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw'); + await expect(page.testSubj.locator('^autocompleteSuggestion-operator')).toHaveCount(2); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts new file mode 100644 index 000000000000..319d8af3e93c --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_non_time_based.spec.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from '@kbn/scout'; +import { test, testData, assertionMessages } from '../fixtures'; + +test.describe( + 'Discover app - value suggestions non-time based', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.NO_TIME_FIELD); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.NO_TIME_FIELD); + await uiSettings.set({ + defaultIndex: 'without-timefield', + }); + }); + + test.afterAll(async ({ kbnClient, uiSettings }) => { + await uiSettings.unset('defaultIndex'); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); + + test('shows all auto-suggest options for a filter in discover context app', async ({ + page, + }) => { + await page.testSubj.fill('queryInput', 'type.keyword : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(1); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('"apache"'); + }); + } +); diff --git a/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_use_time_range_disabled.spec.ts b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_use_time_range_disabled.spec.ts new file mode 100644 index 000000000000..857709b09194 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/ui_tests/tests/value_suggestions_use_time_range_disabled.spec.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { expect } from '@kbn/scout'; +import { test, testData, assertionMessages } from '../fixtures'; + +test.describe( + 'Discover app - value suggestions: useTimeRange disabled', + { tag: ['@ess', '@svlSecurity', '@svlOblt', '@svlSearch'] }, + () => { + test.beforeAll(async ({ esArchiver, kbnClient, uiSettings }) => { + await esArchiver.loadIfNeeded(testData.ES_ARCHIVES.LOGSTASH); + await kbnClient.importExport.load(testData.KBN_ARCHIVES.DASHBOARD_DRILLDOWNS); + await uiSettings.set({ + defaultIndex: testData.DATA_VIEW_ID.LOGSTASH, // TODO: investigate why it is required for `node scripts/playwright_test.js` run + 'timepicker:timeDefaults': `{ "from": "${testData.LOGSTASH_DEFAULT_START_TIME}", "to": "${testData.LOGSTASH_DEFAULT_END_TIME}"}`, + 'autocomplete:useTimeRange': false, + }); + }); + + test.afterAll(async ({ uiSettings, kbnClient }) => { + await uiSettings.unset('defaultIndex', 'timepicker:timeDefaults'); + await uiSettings.set({ 'autocomplete:useTimeRange': true }); + await kbnClient.savedObjects.cleanStandardList(); + }); + + test.beforeEach(async ({ browserAuth, pageObjects }) => { + await browserAuth.loginAsViewer(); + await pageObjects.discover.goto(); + }); + + test('show up if outside of range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_OUT_OF_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(5); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('jpg'); + }); + + test('show up if in range', async ({ page, pageObjects }) => { + await pageObjects.datePicker.setAbsoluteRange(testData.LOGSTASH_IN_RANGE_DATES); + await page.testSubj.fill('queryInput', 'extension.raw : '); + await expect( + page.testSubj.locator('autoCompleteSuggestionText'), + assertionMessages.QUERY_BAR_VALIDATION.SUGGESTIONS_COUNT + ).toHaveCount(5); + const actualSuggestions = await page.testSubj + .locator('autoCompleteSuggestionText') + .allTextContents(); + expect(actualSuggestions.join(',')).toContain('jpg'); + }); + } +); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts index 231aa1c319da..c3ce7fb1a43a 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_data_clients/knowledge_base/index.ts @@ -178,9 +178,22 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { public createInferenceEndpoint = async () => { const elserId = await this.options.getElserId(); this.options.logger.debug(`Deploying ELSER model '${elserId}'...`); + const esClient = await this.options.elasticsearchClientPromise; + try { - const esClient = await this.options.elasticsearchClientPromise; + await esClient.inference.delete({ + inference_id: ASSISTANT_ELSER_INFERENCE_ID, + // it's being used in the mapping so we need to force delete + force: true, + }); + this.options.logger.debug(`Deleted existing inference endpoint for ELSER model '${elserId}'`); + } catch (error) { + this.options.logger.error( + `Error deleting inference endpoint for ELSER model '${elserId}':\n${error}` + ); + } + try { await esClient.inference.put({ task_type: 'sparse_embedding', inference_id: ASSISTANT_ELSER_INFERENCE_ID, @@ -198,6 +211,9 @@ export class AIAssistantKnowledgeBaseDataClient extends AIAssistantDataClient { task_settings: {}, }, }); + + // await for the model to be deployed + await this.isInferenceEndpointExists(); } catch (error) { this.options.logger.error( `Error creating inference endpoint for ELSER model '${elserId}':\n${error}` diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts index 57b7745a89c7..2a4ad628eb75 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/helpers.ts @@ -9,6 +9,9 @@ import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import type { KibanaRequest } from '@kbn/core-http-server'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import type { MlPluginSetup } from '@kbn/ml-plugin/server'; +import { DeleteByQueryRequest } from '@elastic/elasticsearch/lib/api/types'; +import { i18n } from '@kbn/i18n'; +import { getResourceName } from '.'; import { knowledgeBaseIngestPipeline } from '../ai_assistant_data_clients/knowledge_base/ingest_pipeline'; import { GetElser } from '../types'; @@ -96,3 +99,45 @@ export const deletePipeline = async ({ esClient, id }: DeletePipelineParams): Pr return response.acknowledged; }; + +export const removeLegacyQuickPrompt = async (esClient: ElasticsearchClient) => { + try { + const deleteQuery: DeleteByQueryRequest = { + index: `${getResourceName('prompts')}-*`, + query: { + bool: { + must: [ + { + term: { + name: ESQL_QUERY_GENERATION_TITLE, + }, + }, + { + term: { + prompt_type: 'quick', + }, + }, + { + term: { + is_default: true, + }, + }, + ], + }, + }, + }; + return esClient.deleteByQuery(deleteQuery); + } catch (e) { + // swallow any errors + return { + total: 0, + }; + } +}; + +const ESQL_QUERY_GENERATION_TITLE = i18n.translate( + 'xpack.elasticAssistantPlugin.assistant.quickPrompts.esqlQueryGenerationTitle', + { + defaultMessage: 'ES|QL Query Generation', + } +); diff --git a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts index 81ddd69fb67d..233b5781ddf6 100644 --- a/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts +++ b/x-pack/plugins/elastic_assistant/server/ai_assistant_service/index.ts @@ -40,7 +40,7 @@ import { hasAIAssistantLicense } from '../routes/helpers'; const TOTAL_FIELDS_LIMIT = 2500; -function getResourceName(resource: string) { +export function getResourceName(resource: string) { return `.kibana-elastic-ai-assistant-${resource}`; } diff --git a/x-pack/plugins/elastic_assistant/server/plugin.ts b/x-pack/plugins/elastic_assistant/server/plugin.ts index 4386b95c3fa7..110dbbc05f2a 100755 --- a/x-pack/plugins/elastic_assistant/server/plugin.ts +++ b/x-pack/plugins/elastic_assistant/server/plugin.ts @@ -25,7 +25,7 @@ import { RequestContextFactory } from './routes/request_context_factory'; import { PLUGIN_ID } from '../common/constants'; import { registerRoutes } from './routes/register_routes'; import { appContextService } from './services/app_context'; -import { createGetElserId } from './ai_assistant_service/helpers'; +import { createGetElserId, removeLegacyQuickPrompt } from './ai_assistant_service/helpers'; export class ElasticAssistantPlugin implements @@ -109,6 +109,12 @@ export class ElasticAssistantPlugin this.getElserId = createGetElserId(this.mlTrainedModelsProvider); } }); + removeLegacyQuickPrompt(core.elasticsearch.client.asInternalUser) + .then((res) => { + if (res?.total) + this.logger.info(`Removed ${res.total} legacy quick prompts from AI Assistant`); + }) + .catch(() => {}); return { actions: plugins.actions, diff --git a/x-pack/plugins/enterprise_search/common/constants.ts b/x-pack/plugins/enterprise_search/common/constants.ts index 0c13a772862b..2603ea3d8901 100644 --- a/x-pack/plugins/enterprise_search/common/constants.ts +++ b/x-pack/plugins/enterprise_search/common/constants.ts @@ -211,7 +211,7 @@ export const SEARCH_RELEVANCE_PLUGIN = { DESCRIPTION: i18n.translate('xpack.enterpriseSearch.inferenceEndpoints.description', { defaultMessage: 'Manage your inference endpoints for semantic search and AI use cases.', }), - URL: '/app/enterprise_search/relevance', + URL: '/app/elasticsearch/relevance', LOGO: 'logoEnterpriseSearch', SUPPORT_URL: 'https://discuss.elastic.co/c/enterprise-search/', }; diff --git a/x-pack/plugins/enterprise_search/common/locators/index.ts b/x-pack/plugins/enterprise_search/common/locators/index.ts index 0f9d2060cd82..35c1d43b3b30 100644 --- a/x-pack/plugins/enterprise_search/common/locators/index.ts +++ b/x-pack/plugins/enterprise_search/common/locators/index.ts @@ -6,14 +6,17 @@ */ import type { SharePluginSetup } from '@kbn/share-plugin/public'; +import { SerializableRecord } from '@kbn/utility-types'; import { CreateIndexLocatorDefinition, type CreateIndexLocatorParams, } from './create_index_locator'; +import { SearchInferenceEndpointLocatorDefinition } from './inference_locator'; import { PlaygroundLocatorDefinition, type PlaygroundLocatorParams } from './playground_locator'; export function registerLocators(share: SharePluginSetup) { share.url.locators.create<CreateIndexLocatorParams>(new CreateIndexLocatorDefinition()); share.url.locators.create<PlaygroundLocatorParams>(new PlaygroundLocatorDefinition()); + share.url.locators.create<SerializableRecord>(new SearchInferenceEndpointLocatorDefinition()); } diff --git a/x-pack/plugins/enterprise_search/common/locators/inference_locator.tsx b/x-pack/plugins/enterprise_search/common/locators/inference_locator.tsx new file mode 100644 index 000000000000..f20d628bf189 --- /dev/null +++ b/x-pack/plugins/enterprise_search/common/locators/inference_locator.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LocatorDefinition } from '@kbn/share-plugin/common'; +import type { SharePluginSetup } from '@kbn/share-plugin/public'; +import type { SerializableRecord } from '@kbn/utility-types'; + +import { SEARCH_RELEVANCE_PLUGIN } from '../constants'; + +export function registerLocators(share: SharePluginSetup) { + share.url.locators.create<SerializableRecord>(new SearchInferenceEndpointLocatorDefinition()); +} + +export class SearchInferenceEndpointLocatorDefinition + implements LocatorDefinition<SerializableRecord> +{ + public readonly getLocation = async () => { + return { + app: SEARCH_RELEVANCE_PLUGIN.ID, + path: '/inference_endpoints', + state: {}, + }; + }; + + public readonly id = 'SEARCH_INFERENCE_ENDPOINTS'; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx index 2920a4900f0b..bcb4441750d0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/ai_search/index.tsx @@ -9,35 +9,17 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AISearchGuide } from './components/ai_search_guide/ai_search_guide'; import { ROOT_PATH } from './routes'; -export const EnterpriseSearchAISearch: React.FC<InitialAppData> = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } - - return <AISearchGuide />; - }; - +export const EnterpriseSearchAISearch: React.FC<InitialAppData> = () => { return ( <Routes> <Route exact path={ROOT_PATH}> - {showView()} + <AISearchGuide /> </Route> </Routes> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx index d3261eb265c0..a9914ca244f5 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/index.test.tsx @@ -14,8 +14,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; - import { AnalyticsOverview } from './components/analytics_overview/analytics_overview'; import { Analytics } from '.'; @@ -30,10 +28,4 @@ describe('EnterpriseSearchAnalytics', () => { expect(wrapper.find(AnalyticsOverview)).toHaveLength(1); }); - - it('renders VersionMismatchPage when there are mismatching versions', () => { - const wrapper = shallow(<Analytics enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" />); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx b/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx index 19d7b67be6bf..03de5eff9783 100644 --- a/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/analytics/index.tsx @@ -9,30 +9,18 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AnalyticsCollectionView } from './components/analytics_collection_view/analytics_collection_view'; import { AnalyticsOverview } from './components/analytics_overview/analytics_overview'; import { ROOT_PATH, COLLECTION_VIEW_PATH } from './routes'; -export const Analytics: React.FC<InitialAppData> = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - +export const Analytics: React.FC<InitialAppData> = () => { return ( <Routes> <Route exact path={ROOT_PATH}> - {incompatibleVersions ? ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ) : ( - <AnalyticsOverview /> - )} + <AnalyticsOverview /> </Route> <Route path={COLLECTION_VIEW_PATH}> <AnalyticsCollectionView /> diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/manage_queries_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/manage_queries_modal.tsx index ba0ee70859a7..0ccff49503c7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/manage_queries_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/curations/curation/queries/manage_queries_modal.tsx @@ -17,6 +17,7 @@ import { EuiText, EuiSpacer, EuiButton, + useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -33,19 +34,25 @@ export const ManageQueriesModal: React.FC = () => { const [isModalVisible, setModalVisibility] = useState(false); const showModal = () => setModalVisibility(true); const hideModal = () => setModalVisibility(false); + const modalTitleId = useGeneratedHtmlId(); return ( <> - <EuiButton fill onClick={showModal} isLoading={queriesLoading}> + <EuiButton + data-test-subj="enterpriseSearchManageQueriesModalManageQueriesButton" + fill + onClick={showModal} + isLoading={queriesLoading} + > {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.manageQueryButtonLabel', { defaultMessage: 'Manage queries' } )} </EuiButton> {isModalVisible && ( - <EuiModal onClose={hideModal}> + <EuiModal onClose={hideModal} aria-labelledby={modalTitleId}> <EuiModalHeader> - <EuiModalHeaderTitle> + <EuiModalHeaderTitle id={modalTitleId}> {i18n.translate( 'xpack.enterpriseSearch.appSearch.engine.curations.manageQueryTitle', { defaultMessage: 'Manage queries' } diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx index 299a840cf891..779158ae1e11 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/documents/search_experience/customization_modal.tsx @@ -20,6 +20,7 @@ import { EuiModalFooter, EuiModalHeader, EuiModalHeaderTitle, + useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -44,6 +45,7 @@ export const CustomizationModal: React.FC<Props> = ({ sortFields, }) => { const { engine } = useValues(EngineLogic); + const modalTitleId = useGeneratedHtmlId(); const [selectedFilterFields, setSelectedFilterFields] = useState( filterFields.map(fieldNameToComboBoxOption) @@ -69,9 +71,9 @@ export const CustomizationModal: React.FC<Props> = ({ ); return ( - <EuiModal onClose={onClose}> + <EuiModal onClose={onClose} aria-labelledby={modalTitleId}> <EuiModalHeader> - <EuiModalHeaderTitle> + <EuiModalHeaderTitle id={modalTitleId}> {i18n.translate( 'xpack.enterpriseSearch.appSearch.documents.search.customizationModal.title', { @@ -132,8 +134,11 @@ export const CustomizationModal: React.FC<Props> = ({ </EuiForm> </EuiModalBody> <EuiModalFooter> - <EuiButtonEmpty onClick={onClose}>{CANCEL_BUTTON_LABEL}</EuiButtonEmpty> + <EuiButtonEmpty data-test-subj="enterpriseSearchCustomizationModalButton" onClick={onClose}> + {CANCEL_BUTTON_LABEL} + </EuiButtonEmpty> <EuiButton + data-test-subj="enterpriseSearchCustomizationModalButton" fill onClick={() => { onSave({ diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx deleted file mode 100644 index b307835534dd..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorConnecting } from '.'; - -describe('ErrorConnecting', () => { - it('renders', () => { - const wrapper = shallow(<ErrorConnecting />); - - const errorStatePrompt = wrapper.find(ErrorStatePrompt); - expect(errorStatePrompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx deleted file mode 100644 index 2d1235e0b5c4..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/error_connecting.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SetAppSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendAppSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -export const ErrorConnecting: React.FC = () => { - return ( - <> - <SetPageChrome /> - <SendTelemetry action="error" metric="cannot_connect" /> - - <KibanaPageTemplate isEmptyState> - <ErrorStatePrompt /> - </KibanaPageTemplate> - </> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx index bb413298f51c..3d4207d49985 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/components/settings/log_retention/log_retention_panel.tsx @@ -17,6 +17,7 @@ import { EuiText, EuiTextColor, EuiTitle, + useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -34,6 +35,7 @@ export const LogRetentionPanel: React.FC = () => { const apiLogRetentionSettings = logRetention?.[LogRetentionOptions.API]; const auditLogRetentionSettings = logRetention?.[LogRetentionOptions.Audit]; const crawlerLogRetentionSettings = logRetention?.[LogRetentionOptions.Crawler]; + const switchPrefixId = useGeneratedHtmlId(); useEffect(() => { fetchLogRetention(); @@ -51,9 +53,10 @@ export const LogRetentionPanel: React.FC = () => { <EuiSpacer size="m" /> <EuiText> <EuiSwitch + aria-labelledby={`${switchPrefixId}analytics`} label={ <> - <strong> + <strong id={`${switchPrefixId}analytics`}> {i18n.translate( 'xpack.enterpriseSearch.appSearch.settings.logRetention.analytics.label', { @@ -61,11 +64,13 @@ export const LogRetentionPanel: React.FC = () => { } )} </strong> - {': '} {hasILM && ( - <EuiTextColor color="subdued"> - <LogRetentionMessage type={LogRetentionOptions.Analytics} /> - </EuiTextColor> + <> + {': '} + <EuiTextColor color="subdued"> + <LogRetentionMessage type={LogRetentionOptions.Analytics} /> + </EuiTextColor> + </> )} </> } @@ -78,9 +83,10 @@ export const LogRetentionPanel: React.FC = () => { <EuiSpacer size="m" /> <EuiText> <EuiSwitch + aria-labelledby={`${switchPrefixId}api`} label={ <> - <strong> + <strong id={`${switchPrefixId}api`}> {i18n.translate( 'xpack.enterpriseSearch.appSearch.settings.logRetention.api.label', { @@ -88,11 +94,13 @@ export const LogRetentionPanel: React.FC = () => { } )} </strong> - {': '} {hasILM && ( - <EuiTextColor color="subdued"> - <LogRetentionMessage type={LogRetentionOptions.API} /> - </EuiTextColor> + <> + {': '} + <EuiTextColor color="subdued"> + <LogRetentionMessage type={LogRetentionOptions.API} /> + </EuiTextColor> + </> )} </> } @@ -105,9 +113,10 @@ export const LogRetentionPanel: React.FC = () => { <EuiSpacer size="m" /> <EuiText> <EuiSwitch + aria-labelledby={`${switchPrefixId}crawler`} label={ <> - <strong> + <strong id={`${switchPrefixId}crawler`}> {i18n.translate( 'xpack.enterpriseSearch.appSearch.settings.logRetention.crawler.label', { @@ -115,11 +124,13 @@ export const LogRetentionPanel: React.FC = () => { } )} </strong> - {': '} {hasILM && ( - <EuiTextColor color="subdued"> - <LogRetentionMessage type={LogRetentionOptions.Crawler} /> - </EuiTextColor> + <> + {': '} + <EuiTextColor color="subdued"> + <LogRetentionMessage type={LogRetentionOptions.Crawler} /> + </EuiTextColor> + </> )} </> } @@ -132,9 +143,10 @@ export const LogRetentionPanel: React.FC = () => { <EuiSpacer size="m" /> <EuiText> <EuiSwitch + aria-labelledby={`${switchPrefixId}audit`} label={ <> - <strong> + <strong id={`${switchPrefixId}audit`}> {i18n.translate( 'xpack.enterpriseSearch.appSearch.settings.logRetention.audit.label', { @@ -142,11 +154,14 @@ export const LogRetentionPanel: React.FC = () => { } )} </strong> - {': '} {hasILM && ( - <EuiTextColor color="subdued"> - <LogRetentionMessage type={LogRetentionOptions.Audit} /> - </EuiTextColor> + <> + {': '} + <EuiTextColor color="subdued"> + <LogRetentionMessage type={LogRetentionOptions.Audit} /> + </EuiTextColor> + {': '} + </> )} </> } @@ -163,7 +178,11 @@ export const LogRetentionPanel: React.FC = () => { defaultMessage: 'Log retention is determined by the ILM policies for your deployment.', })} <br /> - <EuiLink href={docLinks.appSearchLogSettings} target="_blank"> + <EuiLink + data-test-subj="enterpriseSearchLogRetentionPanelLearnMoreAboutLogRetentionForEnterpriseSearchLink" + href={docLinks.appSearchLogSettings} + target="_blank" + > {i18n.translate('xpack.enterpriseSearch.appSearch.settings.logRetention.learnMore', { defaultMessage: 'Learn more about log retention for Enterprise Search.', })} diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx index bd8d6c30a018..2c73e7606cd8 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.test.tsx @@ -16,7 +16,6 @@ import { Redirect } from 'react-router-dom'; import { shallow, ShallowWrapper } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { rerender } from '../test_helpers'; jest.mock('./app_logic', () => ({ AppLogic: jest.fn() })); @@ -26,7 +25,6 @@ import { Credentials } from './components/credentials'; import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; -import { ErrorConnecting } from './components/error_connecting'; import { Library } from './components/library'; import { MetaEngineCreation } from './components/meta_engine_creation'; import { RoleMappings } from './components/role_mappings'; @@ -42,12 +40,6 @@ describe('AppSearch', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); }); - it('renders VersionMismatchPage when there are mismatching versions', () => { - const wrapper = shallow(<AppSearch enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" />); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); - it('renders AppSearchUnconfigured when config.host is not set', () => { setMockValues({ config: { host: '' } }); const wrapper = shallow(<AppSearch />); @@ -55,14 +47,6 @@ describe('AppSearch', () => { expect(wrapper.find(AppSearchUnconfigured)).toHaveLength(1); }); - it('renders ErrorConnecting when Enterprise Search is unavailable', () => { - setMockValues({ errorConnectingMessage: '502 Bad Gateway' }); - const wrapper = shallow(<AppSearch />); - - const errorConnection = wrapper.find(ErrorConnecting); - expect(errorConnection).toHaveLength(1); - }); - it('renders AppSearchConfigured when config.host is set & available', () => { setMockValues({ errorConnectingMessage: '', config: { host: 'some.url' } }); const wrapper = shallow(<AppSearch />); diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx index 7f7237555867..1a75cd58b1a2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/app_search/index.tsx @@ -12,19 +12,15 @@ import { useValues } from 'kea'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; import { EndpointsHeaderAction } from '../shared/layout/endpoints_header_action'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AppLogic } from './app_logic'; import { Credentials } from './components/credentials'; import { EngineRouter } from './components/engine'; import { EngineCreation } from './components/engine_creation'; import { EnginesOverview } from './components/engines'; -import { ErrorConnecting } from './components/error_connecting'; import { KibanaHeaderActions } from './components/layout'; import { Library } from './components/library'; import { MetaEngineCreation } from './components/meta_engine_creation'; @@ -47,24 +43,10 @@ import { export const AppSearch: React.FC<InitialAppData> = (props) => { const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - const showView = () => { if (!config.host) { return <AppSearchUnconfigured />; - } else if (incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } else if (errorConnectingMessage) { - return <ErrorConnecting />; } - return <AppSearchConfigured {...(props as Required<InitialAppData>)} />; }; diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx index f3047ac23b64..99f44cbb01f0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/connect/search_application_connect.tsx @@ -21,7 +21,6 @@ import { } from '../../../routes'; import { EnterpriseSearchApplicationsPageTemplate } from '../../layout/page_template'; -import { SearchApplicationError } from '../search_application_error'; import { SearchApplicationViewLogic } from '../search_application_view_logic'; import { SearchApplicationAPI } from './search_application_api'; @@ -47,7 +46,6 @@ const DOCUMENTATION_TAB_TITLE = i18n.translate( defaultMessage: 'Documentation', } ); -const ConnectTabs: string[] = Object.values(SearchApplicationConnectTabs); const getTabBreadCrumb = (tabId: string) => { switch (tabId) { case SearchApplicationConnectTabs.SEARCHAPI: @@ -76,26 +74,6 @@ export const SearchApplicationConnect: React.FC = () => { ); }; - if (!ConnectTabs.includes(connectTabId)) { - return ( - <EnterpriseSearchApplicationsPageTemplate - pageChrome={[searchApplicationName, pageTitle]} - pageViewTelemetry={SearchApplicationViewTabs.CONNECT} - isLoading={isLoadingSearchApplication} - pageHeader={{ - bottomBorder: false, - className: 'searchApplicationHeaderBackgroundColor', - pageTitle, - rightSideItems: [], - }} - searchApplicationName={searchApplicationName} - hasSchemaConflicts={hasSchemaConflicts} - > - <SearchApplicationError notFound /> - </EnterpriseSearchApplicationsPageTemplate> - ); - } - return ( <EnterpriseSearchApplicationsPageTemplate pageChrome={[searchApplicationName, pageTitle, getTabBreadCrumb(connectTabId)]} diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_content.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_content.tsx index 577154e27163..743176737f17 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_content.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_content.tsx @@ -25,7 +25,6 @@ import { import { EnterpriseSearchApplicationsPageTemplate } from '../layout/page_template'; import { AddIndicesFlyout } from './add_indices_flyout'; -import { SearchApplicationError } from './search_application_error'; import { SearchApplicationIndices } from './search_application_indices'; import { SearchApplicationIndicesLogic } from './search_application_indices_logic'; import { SearchApplicationSchema } from './search_application_schema'; @@ -62,8 +61,6 @@ const getTabBreadCrumb = (tabId: string) => { } }; -const ContentTabs: string[] = Object.values(SearchApplicationContentTabs); - export const SearchApplicationContent = () => { const { searchApplicationName, isLoadingSearchApplication, hasSchemaConflicts } = useValues( SearchApplicationViewLogic @@ -74,26 +71,6 @@ export const SearchApplicationContent = () => { contentTabId?: string; }>(); - if (!ContentTabs.includes(contentTabId)) { - return ( - <EnterpriseSearchApplicationsPageTemplate - pageChrome={[searchApplicationName, pageTitle]} - pageViewTelemetry={SearchApplicationViewTabs.CONTENT} - isLoading={isLoadingSearchApplication} - pageHeader={{ - bottomBorder: false, - className: 'searchApplicationHeaderBackgroundColor', - pageTitle, - rightSideItems: [], - }} - searchApplicationName={searchApplicationName} - hasSchemaConflicts={hasSchemaConflicts} - > - <SearchApplicationError notFound /> - </EnterpriseSearchApplicationsPageTemplate> - ); - } - const onTabClick = (tab: SearchApplicationContentTabs) => () => { KibanaLogic.values.navigateToUrl( generateEncodedPath(SEARCH_APPLICATION_CONTENT_PATH, { diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.test.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.test.tsx deleted file mode 100644 index d24675822a73..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.test.tsx +++ /dev/null @@ -1,68 +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 { setMockValues } from '../../../__mocks__/kea_logic'; - -import React from 'react'; - -import { HttpError } from '../../../../../common/types/api'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { NotFoundPrompt } from '../../../shared/not_found'; -import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; - -import { mountWithIntl } from '../../../test_helpers'; - -import { SearchApplicationError } from './search_application_error'; - -describe('SearchApplicationError', () => { - beforeEach(() => { - jest.clearAllMocks(); - setMockValues({}); - }); - - it('renders 404 prompt for 404 error', () => { - const error = { - body: { - error: 'NOT_FOUND', - message: 'Not Found', - statusCode: 404, - }, - } as HttpError; - const wrapper = mountWithIntl(<SearchApplicationError error={error} />); - - expect(wrapper.find(NotFoundPrompt)).toHaveLength(1); - expect(wrapper.find(SendEnterpriseSearchTelemetry)).toHaveLength(1); - expect(wrapper.find(ErrorStatePrompt)).toHaveLength(0); - - const notFound = wrapper.find(NotFoundPrompt); - expect(notFound.prop('backToLink')).toEqual('/search_applications'); - expect(notFound.prop('backToContent')).toEqual('Back to Search Applications'); - - const telemetry = wrapper.find(SendEnterpriseSearchTelemetry); - expect(telemetry.prop('action')).toEqual('error'); - expect(telemetry.prop('metric')).toEqual('not_found'); - }); - - it('renders error prompt for api errors', () => { - const error = { - body: { - error: 'ERROR', - message: 'Internal Server Error', - statusCode: 500, - }, - } as HttpError; - const wrapper = mountWithIntl(<SearchApplicationError error={error} />); - - expect(wrapper.find(ErrorStatePrompt)).toHaveLength(1); - expect(wrapper.find(SendEnterpriseSearchTelemetry)).toHaveLength(1); - expect(wrapper.find(NotFoundPrompt)).toHaveLength(0); - - const telemetry = wrapper.find(SendEnterpriseSearchTelemetry); - expect(telemetry.prop('action')).toEqual('error'); - expect(telemetry.prop('metric')).toEqual('cannot_connect'); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.tsx deleted file mode 100644 index 49a783dbbcec..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_error.tsx +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { i18n } from '@kbn/i18n'; - -import { APPLICATIONS_PLUGIN } from '../../../../../common/constants'; -import { HttpError } from '../../../../../common/types/api'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { NotFoundPrompt } from '../../../shared/not_found'; -import { SendEnterpriseSearchTelemetry } from '../../../shared/telemetry'; - -import { SEARCH_APPLICATIONS_PATH } from '../../routes'; - -export const SearchApplicationError: React.FC<{ error?: HttpError; notFound?: boolean }> = ({ - error, - notFound, -}) => { - if (notFound || error?.body?.statusCode === 404) { - return ( - <> - <SendEnterpriseSearchTelemetry action="error" metric="not_found" /> - <NotFoundPrompt - backToContent={i18n.translate( - 'xpack.enterpriseSearch.searchApplications.searchApplication.notFound.action1', - { - defaultMessage: 'Back to Search Applications', - } - )} - backToLink={SEARCH_APPLICATIONS_PATH} - productSupportUrl={APPLICATIONS_PLUGIN.SUPPORT_URL} - /> - </> - ); - } - return ( - <> - <SendEnterpriseSearchTelemetry action="error" metric="cannot_connect" /> - <ErrorStatePrompt /> - </> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx index fef6f95c3b43..001d36a0faf4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_application/search_application_view.tsx @@ -6,13 +6,12 @@ */ import React, { useEffect } from 'react'; -import { useParams, Redirect } from 'react-router-dom'; +import { Redirect } from 'react-router-dom'; import { useValues, useActions } from 'kea'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { Status } from '../../../../../common/types/api'; import { SEARCH_APPLICATION_PATH, SEARCH_APPLICATION_CONTENT_PATH, @@ -22,52 +21,23 @@ import { SearchApplicationContentTabs, } from '../../routes'; -import { EnterpriseSearchApplicationsPageTemplate } from '../layout/page_template'; import { DeleteSearchApplicationModal } from '../search_applications/delete_search_application_modal'; import { SearchApplicationConnect } from './connect/search_application_connect'; import { SearchApplicationDocsExplorer } from './docs_explorer/docs_explorer'; import { SearchApplicationContent } from './search_application_content'; -import { SearchApplicationError } from './search_application_error'; import { SearchApplicationViewLogic } from './search_application_view_logic'; export const SearchApplicationView: React.FC = () => { const { fetchSearchApplication, closeDeleteSearchApplicationModal } = useActions( SearchApplicationViewLogic ); - const { - searchApplicationName, - fetchSearchApplicationApiError, - fetchSearchApplicationApiStatus, - hasSchemaConflicts, - isDeleteModalVisible, - } = useValues(SearchApplicationViewLogic); - const { tabId = SearchApplicationViewTabs.DOCS_EXPLORER } = useParams<{ - tabId?: string; - }>(); + const { searchApplicationName, isDeleteModalVisible } = useValues(SearchApplicationViewLogic); useEffect(() => { fetchSearchApplication({ name: searchApplicationName }); }, [searchApplicationName]); - if (fetchSearchApplicationApiStatus === Status.ERROR) { - return ( - <EnterpriseSearchApplicationsPageTemplate - isEmptyState - pageChrome={[searchApplicationName]} - pageViewTelemetry={tabId} - pageHeader={{ - bottomBorder: false, - pageTitle: searchApplicationName, - rightSideItems: [], - }} - searchApplicationName={searchApplicationName} - emptyState={<SearchApplicationError error={fetchSearchApplicationApiError} />} - hasSchemaConflicts={hasSchemaConflicts} - /> - ); - } - return ( <> {isDeleteModalVisible ? ( @@ -92,22 +62,6 @@ export const SearchApplicationView: React.FC = () => { from={`${SEARCH_APPLICATION_PATH}/${SearchApplicationViewTabs.CONNECT}`} to={`${SEARCH_APPLICATION_PATH}/${SearchApplicationViewTabs.CONNECT}/${SearchApplicationConnectTabs.SEARCHAPI}`} /> - <Route> - <EnterpriseSearchApplicationsPageTemplate - isEmptyState - pageChrome={[searchApplicationName]} - pageViewTelemetry={tabId} - pageHeader={{ - bottomBorder: false, - pageTitle: searchApplicationName, - rightSideItems: [], - }} - searchApplicationName={searchApplicationName} - hasSchemaConflicts={hasSchemaConflicts} - > - <SearchApplicationError notFound /> - </EnterpriseSearchApplicationsPageTemplate> - </Route> </Routes> </> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx index 532ba053af1d..78f20bc122ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_application_indices_flyout.tsx @@ -26,7 +26,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../../../../common/constants'; -import { Status } from '../../../../../common/types/api'; import { EnterpriseSearchApplicationIndex } from '../../../../../common/types/search_applications'; @@ -35,8 +34,6 @@ import { healthColorsMap } from '../../../shared/constants/health_colors'; import { generateEncodedPath } from '../../../shared/encode_path_params'; import { EuiLinkTo } from '../../../shared/react_router_helpers'; -import { SearchApplicationError } from '../search_application/search_application_error'; - import { SearchApplicationIndicesFlyoutLogic } from './search_application_indices_flyout_logic'; export const SearchApplicationIndicesFlyout: React.FC = () => { @@ -45,15 +42,11 @@ export const SearchApplicationIndicesFlyout: React.FC = () => { searchApplicationName, isSearchApplicationLoading, isFlyoutVisible, - fetchSearchApplicationApiStatus, - fetchSearchApplicationApiError, } = useValues(SearchApplicationIndicesFlyoutLogic); const { closeFlyout } = useActions(SearchApplicationIndicesFlyoutLogic); if (!searchApplicationData) return null; const { indices } = searchApplicationData; - const searchApplicationFetchError = - fetchSearchApplicationApiStatus === Status.ERROR ? true : false; const columns: Array<EuiBasicTableColumn<EnterpriseSearchApplicationIndex>> = [ { @@ -139,11 +132,7 @@ export const SearchApplicationIndicesFlyout: React.FC = () => { </EuiFlyoutHeader> <EuiFlyoutBody> - {searchApplicationFetchError ? ( - <SearchApplicationError error={fetchSearchApplicationApiError} /> - ) : ( - <EuiBasicTable items={indices} columns={columns} loading={isSearchApplicationLoading} /> - )} + <EuiBasicTable items={indices} columns={columns} loading={isSearchApplicationLoading} /> </EuiFlyoutBody> </EuiFlyout> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_create_button.test.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_create_button.test.tsx new file mode 100644 index 000000000000..548314dcda43 --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_create_button.test.tsx @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type ReactNode } from 'react'; + +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; + +import { waitForEuiToolTipVisible } from '@elastic/eui/lib/test/rtl'; + +import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; + +import { CreateSearchApplicationButton } from './search_applications_list'; + +function Container({ children }: { children?: ReactNode }) { + return <IntlProvider locale="en">{children}</IntlProvider>; +} + +describe('CreateSearchApplicationButton', () => { + test('disabled={false}', async () => { + render( + <Container> + <CreateSearchApplicationButton disabled={false} /> + </Container> + ); + + await userEvent.hover( + await screen.findByTestId('enterprise-search-search-applications-creation-button') + ); + + await waitForEuiToolTipVisible(); + + expect( + await screen.findByTestId('create-search-application-button-popover-content') + ).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.test.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.test.tsx index f34aac9e4359..2683a0afc0ca 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.test.tsx @@ -9,7 +9,7 @@ import { setMockActions, setMockValues } from '../../../__mocks__/kea_logic'; import React from 'react'; -import { mountWithIntl, shallowWithIntl } from '@kbn/test-jest-helpers'; +import { shallowWithIntl } from '@kbn/test-jest-helpers'; import { Status } from '../../../../../common/types/api'; @@ -116,80 +116,3 @@ describe('SearchApplicationsList', () => { expect(wrapper.find(LicensingCallout)).toHaveLength(0); }); }); - -describe('CreateSearchApplicationButton', () => { - describe('disabled={true}', () => { - it('renders a disabled button that shows a popover when hovered', () => { - const wrapper = mountWithIntl(<CreateSearchApplicationButton disabled />); - - const button = wrapper.find( - 'button[data-test-subj="enterprise-search-search-applications-creation-button"]' - ); - - expect(button).toHaveLength(1); - expect(button.prop('disabled')).toBeTruthy(); - - let popover = wrapper.find( - 'div[data-test-subj="create-search-application-button-popover-content"]' - ); - - expect(popover).toHaveLength(0); - - const hoverTarget = wrapper.find( - 'div[data-test-subj="create-search-application-button-hover-target"]' - ); - - expect(hoverTarget).toHaveLength(1); - - hoverTarget.simulate('mouseEnter'); - - wrapper.update(); - - popover = wrapper.find( - 'div[data-test-subj="create-search-application-button-popover-content"]' - ); - - expect(popover).toHaveLength(1); - expect(popover.text()).toMatch( - 'This functionality may be changed or removed completely in a future release.' - ); - }); - }); - describe('disabled={false}', () => { - it('renders a button and shows a popover when hovered', () => { - const wrapper = mountWithIntl(<CreateSearchApplicationButton disabled={false} />); - - const button = wrapper.find( - 'button[data-test-subj="enterprise-search-search-applications-creation-button"]' - ); - - expect(button).toHaveLength(1); - expect(button.prop('disabled')).toBeFalsy(); - - let popover = wrapper.find( - 'div[data-test-subj="create-search-application-button-popover-content"]' - ); - - expect(popover).toHaveLength(0); - - const hoverTarget = wrapper.find( - 'div[data-test-subj="create-search-application-button-hover-target"]' - ); - - expect(hoverTarget).toHaveLength(1); - - hoverTarget.simulate('mouseEnter'); - - wrapper.update(); - - popover = wrapper.find( - 'div[data-test-subj="create-search-application-button-popover-content"]' - ); - - expect(popover).toHaveLength(1); - expect(popover.text()).toMatch( - 'This functionality may be changed or removed completely in a future release.' - ); - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.tsx b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.tsx index 126c44b6b5dc..fbc07eef5c5e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/applications/components/search_applications/search_applications_list.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { useActions, useValues } from 'kea'; import useThrottle from 'react-use/lib/useThrottle'; @@ -17,10 +17,9 @@ import { EuiFlexItem, EuiIcon, EuiLink, - EuiPopover, - EuiPopoverTitle, EuiSpacer, EuiText, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -53,38 +52,10 @@ interface CreateSearchApplicationButtonProps { export const CreateSearchApplicationButton: React.FC<CreateSearchApplicationButtonProps> = ({ disabled, }) => { - const [showPopover, setShowPopover] = useState<boolean>(false); - return ( - <EuiPopover - isOpen={showPopover} - closePopover={() => setShowPopover(false)} - button={ - <div - data-test-subj="create-search-application-button-hover-target" - onMouseEnter={() => setShowPopover(true)} - onMouseLeave={() => setShowPopover(false)} - tabIndex={0} - > - <EuiButton - fill - iconType="plusInCircle" - data-test-subj="enterprise-search-search-applications-creation-button" - data-telemetry-id="entSearchApplications-list-createSearchApplication" - isDisabled={disabled} - onClick={() => KibanaLogic.values.navigateToUrl(SEARCH_APPLICATION_CREATION_PATH)} - > - {i18n.translate( - 'xpack.enterpriseSearch.searchApplications.list.createSearchApplicationButton.label', - { - defaultMessage: 'Create', - } - )} - </EuiButton> - </div> - } - > - <EuiPopoverTitle> + <EuiToolTip + position="top" + title={ <EuiFlexGroup justifyContent="center" gutterSize="s"> <EuiFlexItem grow={false}> <EuiIcon type="beaker" /> @@ -96,23 +67,35 @@ export const CreateSearchApplicationButton: React.FC<CreateSearchApplicationButt /> </EuiFlexItem> </EuiFlexGroup> - </EuiPopoverTitle> - <div - style={{ width: '300px' }} - data-test-subj="create-search-application-button-popover-content" + } + content={ + <EuiText size="s" data-test-subj="create-search-application-button-popover-content"> + <FormattedMessage + id="xpack.enterpriseSearch.searchApplications.list.createSearchApplicationTechnicalPreviewPopover.body" + defaultMessage="This functionality may be changed or removed completely in a future release." + /> + </EuiText> + } + > + <EuiButton + fill + iconType="plusInCircle" + data-test-subj="enterprise-search-search-applications-creation-button" + data-telemetry-id="entSearchApplications-list-createSearchApplication" + isDisabled={disabled} + onClick={() => KibanaLogic.values.navigateToUrl(SEARCH_APPLICATION_CREATION_PATH)} > - <EuiFlexGroup direction="column" gutterSize="m"> - <EuiText size="s"> - <FormattedMessage - id="xpack.enterpriseSearch.searchApplications.list.createSearchApplicationTechnicalPreviewPopover.body" - defaultMessage="This functionality may be changed or removed completely in a future release." - /> - </EuiText> - </EuiFlexGroup> - </div> - </EuiPopover> + {i18n.translate( + 'xpack.enterpriseSearch.searchApplications.list.createSearchApplicationButton.label', + { + defaultMessage: 'Create', + } + )} + </EuiButton> + </EuiToolTip> ); }; + interface ListProps { createSearchApplicationFlyoutOpen?: boolean; } @@ -223,6 +206,7 @@ export const SearchApplicationsList: React.FC<ListProps> = ({ <> <div> <EuiFieldSearch + data-test-subj="enterpriseSearchSearchApplicationsListFieldSearch" value={searchQuery} placeholder={i18n.translate( 'xpack.enterpriseSearch.searchApplications.list.searchBar.placeholder', diff --git a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx index e5da2b5610d3..881f042d1d62 100644 --- a/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/elasticsearch/index.tsx @@ -9,35 +9,17 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { ElasticsearchGuide } from './components/elasticsearch_guide/elasticsearch_guide'; import { ROOT_PATH } from './routes'; -export const Elasticsearch: React.FC<InitialAppData> = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } - - return <ElasticsearchGuide />; - }; - +export const Elasticsearch: React.FC<InitialAppData> = () => { return ( <Routes> <Route exact path={ROOT_PATH}> - {showView()} + <ElasticsearchGuide /> </Route> </Routes> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts index 8d2ee0ee87aa..d2bd5cfe7149 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/api/connector/generate_connector_names_api_logic.ts @@ -10,6 +10,7 @@ import { HttpLogic } from '../../../shared/http'; export interface GenerateConnectorNamesApiArgs { connectorName?: string; connectorType?: string; + isManagedConnector?: boolean; } export interface GenerateConnectorNamesApiResponse { @@ -19,14 +20,16 @@ export interface GenerateConnectorNamesApiResponse { } export const generateConnectorNames = async ( - { connectorType, connectorName }: GenerateConnectorNamesApiArgs = { connectorType: 'custom' } + { connectorType, connectorName, isManagedConnector }: GenerateConnectorNamesApiArgs = { + connectorType: 'custom', + } ) => { if (connectorType === '') { connectorType = 'custom'; } const route = `/internal/enterprise_search/connectors/generate_connector_name`; return await HttpLogic.values.http.post(route, { - body: JSON.stringify({ connectorName, connectorType }), + body: JSON.stringify({ connectorName, connectorType, isManagedConnector }), }); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx index 5a2e279026bd..dbc854251e33 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/attach_index_box.tsx @@ -27,7 +27,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { Connector } from '@kbn/search-connectors'; +import { Connector, MANAGED_CONNECTOR_INDEX_PREFIX } from '@kbn/search-connectors'; import { Status } from '../../../../../common/types/api'; @@ -65,66 +65,114 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => createApiError, attachApiError, } = useValues(AttachIndexLogic); + + const { makeRequest } = useActions(FetchAvailableIndicesAPILogic); + const { data, status } = useValues(FetchAvailableIndicesAPILogic); + const isLoading = [Status.IDLE, Status.LOADING].includes(status); + + // Helper function to remove the managed connector index prefix from the index name + const removePrefixConnectorIndex = (connectorIndexName: string) => { + if (!connector.is_native) { + return connectorIndexName; + } + if (connectorIndexName.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX)) { + return connectorIndexName.substring(MANAGED_CONNECTOR_INDEX_PREFIX.length); + } + return connectorIndexName; + }; + + // Helper function to add the managed connector index prefix to the index name + const prefixConnectorIndex = (connectorIndexName: string) => { + if (!connector.is_native) { + return connectorIndexName; + } + if (connectorIndexName.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX)) { + return connectorIndexName; + } + return `${MANAGED_CONNECTOR_INDEX_PREFIX}${connectorIndexName}`; + }; + + const [query, setQuery] = useState<{ + isFullMatch: boolean; + searchValue: string; + }>(); + const [sanitizedName, setSanitizedName] = useState<string>( + prefixConnectorIndex(formatApiName(connector.name)) + ); + const [selectedIndex, setSelectedIndex] = useState< { label: string; shouldCreate?: boolean } | undefined >( + // For managed connectors, the index name should be displayed without prefix + // As `content-` is fixed UI element connector.index_name ? { - label: connector.index_name, + label: removePrefixConnectorIndex(connector.index_name), } : undefined ); - const [selectedLanguage] = useState<string>(); - const [query, setQuery] = useState<{ - isFullMatch: boolean; - searchValue: string; - }>(); - const [sanitizedName, setSanitizedName] = useState<string>(formatApiName(connector.name)); - - const { makeRequest } = useActions(FetchAvailableIndicesAPILogic); - const { data, status } = useValues(FetchAvailableIndicesAPILogic); - const isLoading = [Status.IDLE, Status.LOADING].includes(status); const onSave = () => { - if (selectedIndex?.shouldCreate) { - createIndex({ indexName: selectedIndex.label, language: selectedLanguage ?? null }); - } else if (selectedIndex && !(selectedIndex.label === connector.index_name)) { - attachIndex({ connectorId: connector.id, indexName: selectedIndex.label }); + if (!selectedIndex) return; + // Always attach and/or create prefixed index for managed connectors + const prefixedIndex = prefixConnectorIndex(selectedIndex.label); + if (selectedIndex.shouldCreate) { + createIndex({ + indexName: prefixedIndex, + language: null, + }); + } else if (connector.index_name !== prefixedIndex) { + attachIndex({ + connectorId: connector.id, + indexName: prefixedIndex, + }); } }; + // For managed connectors ensure that only prefixed indices are displayed in the dropdown + // This takes care of the initial component state where all indices could be displayed briefly const options: Array<EuiComboBoxOptionOption<string>> = isLoading ? [] - : data?.indexNames.map((name) => { - return { + : data?.indexNames + .filter((name) => !connector.is_native || name.startsWith(MANAGED_CONNECTOR_INDEX_PREFIX)) + .map((name) => ({ label: name, - }; - }) ?? []; + value: removePrefixConnectorIndex(name), + })) ?? []; const hasMatchingOptions = data?.indexNames.some((name) => - name.toLocaleLowerCase().includes(query?.searchValue.toLocaleLowerCase() ?? '') + name + .toLocaleLowerCase() + .includes(prefixConnectorIndex(query?.searchValue?.toLocaleLowerCase() || '')) ) ?? false; + const isFullMatch = data?.indexNames.some( - (name) => name.toLocaleLowerCase() === query?.searchValue.toLocaleLowerCase() + (name) => + name.toLocaleLowerCase() === + prefixConnectorIndex(query?.searchValue?.toLocaleLowerCase() || '') ) ?? false; - const shouldPrependUserInputAsOption = !!query?.searchValue && hasMatchingOptions && !isFullMatch; + const shouldPrependUserInputAsOption = + !!query && + !!query.searchValue && + query.searchValue !== MANAGED_CONNECTOR_INDEX_PREFIX && + hasMatchingOptions && + !isFullMatch; const groupedOptions: Array<EuiComboBoxOptionOption<string>> = shouldPrependUserInputAsOption ? [ - ...[ - { - label: CREATE_NEW_INDEX_GROUP_LABEL, - options: [ - { - label: query.searchValue, - }, - ], - }, - ], - ...[{ label: SELECT_EXISTING_INDEX_GROUP_LABEL, options }], + { + label: CREATE_NEW_INDEX_GROUP_LABEL, + options: [ + { + label: prefixConnectorIndex(query!.searchValue), + value: query!.searchValue, + }, + ], + }, + { label: SELECT_EXISTING_INDEX_GROUP_LABEL, options }, ] : [{ label: SELECT_EXISTING_INDEX_GROUP_LABEL, options }]; @@ -144,7 +192,8 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => }, [query]); useEffect(() => { - setSanitizedName(formatApiName(connector.name)); + // Suggested name for managed connector should include the content- prefix + setSanitizedName(prefixConnectorIndex(formatApiName(connector.name))); }, [connector.name]); const { hash } = useLocation(); @@ -170,9 +219,10 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => } ) : attachApiError?.body?.message || createApiError?.body?.message || undefined; + if (indexName) { - // We don't want to let people edit indices when on the index route - return <></>; + // Do not render when on the index route + return null; } return ( @@ -189,8 +239,8 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => <FormattedMessage id="xpack.enterpriseSearch.attachIndexBox.thisIndexWillHoldTextLabel" defaultMessage="This index will hold your data source content, and is optimized with default field mappings - for relevant search experiences. Give your index a unique name and optionally set a default - language analyzer for the index." + for relevant search experiences. Give your index a unique name and optionally set a default + language analyzer for the index." /> </EuiText> <EuiSpacer /> @@ -201,10 +251,20 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedIndexLabel', { defaultMessage: 'Associated index' } )} - helpText={i18n.translate( - 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedIndexHelpTextLabel', - { defaultMessage: 'You can use an existing index or create a new one.' } - )} + helpText={ + connector.is_native + ? i18n.translate( + 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedManagedConnectorIndexHelpTextLabel', + { + defaultMessage: + 'Managed connector indices must be prefixed. Use an existing index or create a new one.', + } + ) + : i18n.translate( + 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.associatedIndexHelpTextLabel', + { defaultMessage: 'You can use an existing index or create a new one.' } + ) + } error={error} isInvalid={!!error} > @@ -217,11 +277,13 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => 'xpack.enterpriseSearch.attachIndexBox.euiFormRow.indexSelector.customOption', { defaultMessage: 'Create index {searchValue}', - values: { searchValue: '{searchValue}' }, + values: { searchValue: prefixConnectorIndex('{searchValue}') }, } )} isLoading={isLoading} options={groupedOptions} + singleSelection={{ asPlainText: connector.is_native }} + prepend={connector.is_native ? MANAGED_CONNECTOR_INDEX_PREFIX : undefined} onKeyDown={(event) => { // Index name should not contain spaces if (event.key === ' ') { @@ -229,28 +291,34 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => } }} onSearchChange={(searchValue) => { + // Match by option value to ensure accurate comparison with non-prefixed + // user input for managed connectors setQuery({ - isFullMatch: options.some((option) => option.label === searchValue), - searchValue, + isFullMatch: options.some( + (option) => option.value === prefixConnectorIndex(searchValue) + ), + searchValue: prefixConnectorIndex(searchValue), }); }} onChange={(selection) => { - const currentSelection = selection[0] ?? undefined; + const currentSelection = selection[0]; const selectedIndexOption = currentSelection ? { - label: currentSelection.label, + label: removePrefixConnectorIndex(currentSelection.label), shouldCreate: shouldPrependUserInputAsOption && - !!(currentSelection?.label === query?.searchValue), + currentSelection.value === query?.searchValue, } : undefined; setSelectedIndex(selectedIndexOption); }} selectedOptions={selectedIndex ? [selectedIndex] : undefined} onCreateOption={(value) => { - setSelectedIndex({ label: value.trim(), shouldCreate: true }); + setSelectedIndex({ + label: removePrefixConnectorIndex(value.trim()), + shouldCreate: true, + }); }} - singleSelection /> </EuiFormRow> </EuiFlexItem> @@ -261,8 +329,12 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => <EuiButton data-test-subj="entSearchContent-connector-connectorDetail-saveConfigurationButton" data-telemetry-id="entSearchContent-connector-connectorDetail-saveConfigurationButton" - onClick={() => onSave()} - disabled={!selectedIndex || selectedIndex.label === connector.index_name} + onClick={onSave} + disabled={ + !selectedIndex || + prefixConnectorIndex(selectedIndex.label) === connector.index_name || + !!error + } isLoading={isSaveLoading} > {i18n.translate('xpack.enterpriseSearch.attachIndexBox.saveConfigurationButtonLabel', { @@ -314,15 +386,13 @@ export const AttachIndexBox: React.FC<AttachIndexBoxProps> = ({ connector }) => } )} </EuiButton> - {indexExists[sanitizedName] ? ( + {indexExists[sanitizedName] && ( <EuiText size="xs"> {i18n.translate('xpack.enterpriseSearch.attachIndexBox.indexNameExistsError', { defaultMessage: 'Index with name {indexName} already exists', values: { indexName: sanitizedName }, })} </EuiText> - ) : ( - <></> )} </EuiFlexItem> </EuiFlexGroup> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/components/docker_instructions_step.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/components/docker_instructions_step.tsx index ea5b59c4d326..9202e5af7d9f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/components/docker_instructions_step.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/components/docker_instructions_step.tsx @@ -58,7 +58,10 @@ export const DockerInstructionsStep: React.FC<DockerInstructionsStepProps> = ({ host: elasticsearchUrl, }); - const escapedConfigYamlContent = configYamlContent.replace(/"/g, '\\"').replace(/\$/g, '\\$'); + const escapedConfigYamlContent = configYamlContent + .replace(/\\/g, '\\\\') + .replace(/"/g, '\\"') + .replace(/\$/g, '\\$'); const createConfigCommand = `mkdir -p "$HOME/elastic-connectors" && echo "${escapedConfigYamlContent}" > "$HOME/elastic-connectors/config.yml"`; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_description.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_description.tsx new file mode 100644 index 000000000000..c6f41acb10da --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_description.tsx @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { Connector } from '@kbn/search-connectors'; + +import { ConnectorField } from './connector_field'; + +export const ConnectorDescription: React.FC<{ connector: Connector }> = ({ connector }) => ( + <ConnectorField connector={connector} field="description" /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_detail.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_detail.tsx index 4c787e9ef28e..b3251ad5a15b 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_detail.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_detail.tsx @@ -28,7 +28,8 @@ import { SearchIndexPipelines } from '../search_index/pipelines/pipelines'; import { getHeaderActions } from '../shared/header_actions/header_actions'; import { ConnectorConfiguration } from './connector_configuration'; -import { ConnectorNameAndDescription } from './connector_name_and_description'; +import { ConnectorDescription } from './connector_description'; +import { ConnectorName } from './connector_name'; import { ConnectorViewLogic } from './connector_view_logic'; import { ConnectorDetailOverview } from './overview'; @@ -246,7 +247,8 @@ export const ConnectorDetail: React.FC = () => { pageViewTelemetry={tabId} isLoading={isLoading} pageHeader={{ - pageTitle: connector ? <ConnectorNameAndDescription connector={connector} /> : '...', + description: connector ? <ConnectorDescription connector={connector} /> : '...', + pageTitle: connector ? <ConnectorName connector={connector} /> : '...', rightSideGroupProps: { gutterSize: 's', responsive: false, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_field.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_field.tsx new file mode 100644 index 000000000000..8bddef94243e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_field.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { ChangeEvent, useEffect, useState } from 'react'; + +import { useActions, useValues } from 'kea'; + +import { EuiFlexItem, EuiInlineEditText, EuiInlineEditTitle } from '@elastic/eui'; + +import { i18n } from '@kbn/i18n'; +import { Connector } from '@kbn/search-connectors'; + +import { ConnectorNameAndDescriptionLogic } from './connector_name_and_description_logic'; + +interface ConnectorFieldProps { + connector: Connector; + field: 'name' | 'description'; // The field to edit + isTitle?: boolean; // Whether to render a title (`EuiInlineEditTitle`) or text (`EuiInlineEditText`) +} + +export const ConnectorField: React.FC<ConnectorFieldProps> = ({ connector, field, isTitle }) => { + const [value, setValue] = useState<string | null>(connector[field]); + const [resolverObject, setResolverObject] = useState({ + rej: () => {}, + res: () => {}, + }); + const { saveNameAndDescription, setConnector } = useActions(ConnectorNameAndDescriptionLogic); + const { status, isLoading, isFailed, isSuccess } = useValues(ConnectorNameAndDescriptionLogic); + + useEffect(() => { + setConnector(connector); + }, [connector]); + + useEffect(() => { + if (isSuccess) resolverObject.res(); + if (isFailed) resolverObject.rej(); + }, [status]); + + const getValidationPromiseResolvers = () => { + const resolvers = { + rej: () => {}, + res: () => {}, + }; + const promise = new Promise<void>((resolve, reject) => { + resolvers.res = resolve; + resolvers.rej = reject; + }); + setResolverObject(resolvers); + return promise; + }; + + const handleSave = async (newValue: string) => { + setValue(newValue); + saveNameAndDescription({ ...connector, [field]: newValue }); + await getValidationPromiseResolvers(); + return true; + }; + + const handleCancel = (previousValue: string) => { + setValue(previousValue); + }; + + const Component = isTitle ? EuiInlineEditTitle : EuiInlineEditText; + + return ( + <EuiFlexItem grow={false}> + <Component + inputAriaLabel={i18n.translate( + `xpack.enterpriseSearch.content.connectors.nameAndDescription.${field}.ariaLabel`, + { + defaultMessage: `Edit connector ${field}`, + } + )} + placeholder={i18n.translate( + `xpack.enterpriseSearch.content.connectors.nameAndDescription.${field}.placeholder`, + { + defaultMessage: field === 'name' ? 'Add a name to your connector' : 'Add a description', + } + )} + value={value || ''} + isLoading={isLoading} + isInvalid={field === 'name' && !value?.trim()} + size="m" + heading={isTitle ? 'h1' : 'span'} + editModeProps={{ + cancelButtonProps: { onClick: () => handleCancel(connector[field] || '') }, + formRowProps: + field === 'name' && !value?.trim() + ? { + error: [ + i18n.translate( + 'xpack.enterpriseSearch.content.nameAndDescription.name.error.empty', + { defaultMessage: 'Connector name cannot be empty' } + ), + ], + } + : undefined, + inputProps: { readOnly: isLoading }, + }} + onSave={handleSave} + onChange={(e: ChangeEvent<HTMLInputElement>) => setValue(e.target.value)} + onCancel={() => handleCancel(connector[field] || '')} + /> + </EuiFlexItem> + ); +}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_name.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_name.tsx new file mode 100644 index 000000000000..54f31c4beb6e --- /dev/null +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_name.tsx @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; + +import { Connector } from '@kbn/search-connectors'; + +import { ConnectorField } from './connector_field'; + +export const ConnectorName: React.FC<{ connector: Connector }> = ({ connector }) => ( + <ConnectorField connector={connector} field="name" isTitle /> +); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_name_and_description.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_name_and_description.tsx deleted file mode 100644 index cab9624a2d19..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/connector_name_and_description.tsx +++ /dev/null @@ -1,142 +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, { ChangeEvent, useEffect, useState } from 'react'; - -import { useActions, useValues } from 'kea'; - -import { EuiFlexGroup, EuiFlexItem, EuiInlineEditText, EuiInlineEditTitle } from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; -import { Connector } from '@kbn/search-connectors'; - -import { ConnectorNameAndDescriptionLogic } from './connector_name_and_description_logic'; - -export interface ConnectorNameAndDescriptionProps { - connector: Connector; -} - -export interface ResolverObject { - rej: (value: boolean | void | PromiseLike<boolean | void>) => void; - res: (value: boolean | void | PromiseLike<boolean | void>) => void; -} - -let promise: Promise<boolean | void> | undefined; - -const getValidationPromiseResolvers = (): ResolverObject => { - const resolvers = { - rej: () => {}, - res: () => {}, - }; - promise = new Promise((resolve, reject) => { - resolvers.res = resolve; - resolvers.rej = reject; - }); - return resolvers; -}; - -export const ConnectorNameAndDescription: React.FC<ConnectorNameAndDescriptionProps> = ({ - connector, -}) => { - const [resolverObject, setResolverObject] = useState<ResolverObject>({ - rej: () => {}, - res: () => {}, - }); - const [connectorName, setConnectorName] = useState<string>(connector.name); - const [connectorDescription, setConnectorDescription] = useState<string | null>( - connector.description - ); - const [nameErrors, setNameErrors] = useState<string[]>([]); - const { saveNameAndDescription, setConnector } = useActions(ConnectorNameAndDescriptionLogic); - const { status, isLoading, isFailed, isSuccess } = useValues(ConnectorNameAndDescriptionLogic); - useEffect(() => { - setConnector(connector); - }, [connector]); - - useEffect(() => { - if (isSuccess) { - resolverObject.res(true); - } - if (isFailed) { - resolverObject.rej(); - } - }, [status]); - - return ( - <EuiFlexGroup direction="column" gutterSize="xs"> - <EuiFlexItem grow={false}> - <EuiInlineEditTitle - heading="h1" - inputAriaLabel={i18n.translate( - 'xpack.enterpriseSearch.content.connectors.nameAndDescription.name.ariaLabel', - { defaultMessage: 'Edit connector name' } - )} - placeholder={i18n.translate( - 'xpack.enterpriseSearch.content.connectors.nameAndDescription.name.placeholder', - { defaultMessage: 'Add a name to your connector' } - )} - value={connectorName} - isLoading={isLoading} - isInvalid={nameErrors.length > 0} - size="m" - editModeProps={{ - formRowProps: { error: nameErrors }, - cancelButtonProps: { onClick: () => setNameErrors([]) }, - inputProps: { readOnly: isLoading }, - }} - onSave={(inputValue) => { - if (inputValue.trim().length <= 0) { - setNameErrors([ - i18n.translate( - 'xpack.enterpriseSearch.content.nameAndDescription.name.error.empty', - { defaultMessage: 'Connector name cannot be empty' } - ), - ]); - return false; - } - setConnectorName(inputValue); - saveNameAndDescription({ description: connectorDescription, name: inputValue }); - setResolverObject(getValidationPromiseResolvers()); - return promise; - }} - onChange={(event: ChangeEvent<HTMLInputElement>) => { - setConnectorName(event.target.value); - }} - onCancel={(previousValue) => { - setConnectorName(previousValue); - }} - /> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiInlineEditText - isLoading={isLoading} - inputAriaLabel={i18n.translate( - 'xpack.enterpriseSearch.content.connectors.nameAndDescription.description.ariaLabel', - { defaultMessage: 'Edit connector description' } - )} - placeholder={i18n.translate( - 'xpack.enterpriseSearch.content.connectors.nameAndDescription.description.placeholder', - { defaultMessage: 'Add a description' } - )} - value={connectorDescription || ''} - onSave={(inputValue) => { - setConnectorDescription(inputValue); - saveNameAndDescription({ description: inputValue, name: connectorName }); - setResolverObject(getValidationPromiseResolvers()); - return promise; - }} - onChange={(event: ChangeEvent<HTMLInputElement>) => { - setConnectorDescription(event.target.value); - }} - onCancel={(previousValue) => { - setConnectorDescription(previousValue); - }} - /> - </EuiFlexItem> - </EuiFlexGroup> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx index 29a54c913301..86a3bf83f1b7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/native_connector_configuration.tsx @@ -11,7 +11,6 @@ import { useValues } from 'kea'; import { EuiBadge, - EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiIcon, @@ -23,12 +22,8 @@ import { import { i18n } from '@kbn/i18n'; import { BetaConnectorCallout } from '../../../shared/beta/beta_connector_callout'; -import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; -import { GenerateConnectorApiKeyApiLogic } from '../../api/connector/generate_connector_api_key_api_logic'; - -import { ApiKeyConfig } from '../search_index/connector/api_key_configuration'; import { ConvertConnector } from '../search_index/connector/native_connector_configuration/convert_connector'; import { NativeConnectorConfigurationConfig } from '../search_index/connector/native_connector_configuration/native_connector_configuration_config'; import { ResearchConfiguration } from '../search_index/connector/native_connector_configuration/research_configuration'; @@ -39,9 +34,7 @@ import { ConnectorViewLogic } from './connector_view_logic'; export const NativeConnectorConfiguration: React.FC = () => { const { connector } = useValues(ConnectorViewLogic); - const { config, connectorTypes: connectors } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { data: apiKeyData } = useValues(GenerateConnectorApiKeyApiLogic); + const { connectorTypes: connectors } = useValues(KibanaLogic); const NATIVE_CONNECTORS = useMemo( () => connectors.filter(({ isNative }) => isNative), @@ -68,7 +61,6 @@ export const NativeConnectorConfiguration: React.FC = () => { }; const iconPath = nativeConnector.iconPath; - const hasApiKey = !!(connector.api_key_id ?? apiKeyData); // TODO service_type === "" is considered unknown/custom connector multipleplaces replace all of them with a better solution const isBeta = @@ -114,39 +106,8 @@ export const NativeConnectorConfiguration: React.FC = () => { </EuiBadge> </EuiFlexItem> </EuiFlexGroup> - {config.host && config.canDeployEntSearch && errorConnectingMessage && ( - <> - <EuiCallOut - color="warning" - size="m" - title={i18n.translate( - 'xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.title', - { - defaultMessage: 'No running Enterprise Search instance detected', - } - )} - iconType="warning" - > - <p> - {i18n.translate( - 'xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.text', - { - defaultMessage: - 'Elastic managed connectors require a running Enterprise Search instance.', - } - )} - </p> - </EuiCallOut> - - <EuiSpacer /> - </> - )} - { - <> - <EuiSpacer /> - <AttachIndexBox connector={connector} /> - </> - } + <EuiSpacer /> + <AttachIndexBox connector={connector} /> {connector.index_name && ( <> <EuiSpacer /> @@ -170,23 +131,6 @@ export const NativeConnectorConfiguration: React.FC = () => { <EuiSpacer /> </EuiPanel> <EuiSpacer /> - <EuiPanel hasBorder> - <EuiTitle size="s"> - <h4> - {i18n.translate( - 'xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.apiKey.title', - { defaultMessage: 'API Key' } - )} - </h4> - </EuiTitle> - <EuiSpacer size="m" /> - <ApiKeyConfig - indexName={connector.index_name || ''} - hasApiKey={hasApiKey} - isNative - /> - </EuiPanel> - <EuiSpacer /> <EuiPanel hasBorder> <ConvertConnector /> </EuiPanel> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx index 906c64ccae8e..3fdd3d379eac 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connector_detail/overview.tsx @@ -95,7 +95,7 @@ export const ConnectorDetailOverview: React.FC = () => { <> <EuiCallOut iconType="iInCircle" - color="danger" + color="warning" title={i18n.translate( 'xpack.enterpriseSearch.content.connectors.overview.connectorNoIndexCallOut.title', { @@ -115,7 +115,7 @@ export const ConnectorDetailOverview: React.FC = () => { </EuiText> <EuiSpacer /> <EuiButtonTo - color="danger" + color="warning" fill to={`${generateEncodedPath(CONNECTOR_DETAIL_TAB_PATH, { connectorId: connector.id, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors.tsx index c12dd8036b6b..ed6ff07c0caf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors.tsx @@ -36,8 +36,6 @@ import { } from '../../routes'; import { EnterpriseSearchContentPageTemplate } from '../layout'; -import { CannotConnect } from '../search_index/components/cannot_connect'; - import { DefaultSettingsFlyout } from '../settings/default_settings_flyout'; import { ConnectorStats } from './connector_stats'; @@ -241,12 +239,6 @@ export const Connectors: React.FC<ConnectorsProps> = ({ isCrawler }) => { {productFeatures.hasDefaultIngestPipeline && showDefaultSettingsFlyout && ( <DefaultSettingsFlyout closeFlyout={() => setShowDefaultSettingsFlyout(false)} /> )} - {Boolean(errorConnectingMessage) && ( - <> - <CannotConnect /> - <EuiSpacer /> - </> - )} <ConnectorStats isCrawler={isCrawler} /> <EuiSpacer /> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors_table.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors_table.tsx index 82f258487f39..4f7937a0f1c7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors_table.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/connectors_table.tsx @@ -16,6 +16,7 @@ import { EuiBasicTableColumn, EuiFlexGroup, EuiFlexItem, + EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -221,7 +222,18 @@ export const ConnectorsTable: React.FC<ConnectorsTableProps> = ({ columns={columns} onChange={onChange} tableLayout="fixed" + tableCaption={i18n.translate( + 'xpack.enterpriseSearch.connectorsTable.table.availableConnectorsTableCaption', + { defaultMessage: 'Available connectors table' } + )} loading={isLoading} + noItemsMessage={ + <EuiText aria-live="polite" size="s"> + {i18n.translate('xpack.enterpriseSearch.connectorsTable.table.noResultsMessage', { + defaultMessage: 'No connectors found', + })} + </EuiText> + } pagination={{ pageIndex: meta.page.from / (meta.page.size || 1), pageSize: meta.page.size, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/choose_connector_selectable.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/choose_connector.tsx similarity index 54% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/choose_connector_selectable.tsx rename to x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/choose_connector.tsx index 7019fcbb71e3..21fa8e3f89f6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/choose_connector_selectable.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/choose_connector.tsx @@ -7,6 +7,7 @@ import React, { useEffect, useMemo, useState } from 'react'; +import { css } from '@emotion/react'; import { useActions, useValues } from 'kea'; import { @@ -18,11 +19,18 @@ import { EuiFlexGroup, EuiText, useEuiTheme, + EuiTextTruncate, + EuiBadgeGroup, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import connectorLogo from '../../../../../../assets/images/connector.svg'; +import { + BETA_LABEL, + TECH_PREVIEW_LABEL, + CONNECTOR_CLIENT_LABEL, +} from '../../../../../shared/constants'; import { KibanaLogic } from '../../../../../shared/kibana'; import { NewConnectorLogic } from '../../../new_index/method_connector/new_connector_logic'; import { SelfManagePreference } from '../create_connector'; @@ -34,9 +42,7 @@ interface OptionData { secondaryContent?: string; } -export const ChooseConnectorSelectable: React.FC<ChooseConnectorSelectableProps> = ({ - selfManaged, -}) => { +export const ChooseConnector: React.FC<ChooseConnectorSelectableProps> = ({ selfManaged }) => { const { euiTheme } = useEuiTheme(); const [selectedOption, setSelectedOption] = useState<Array<EuiComboBoxOptionOption<OptionData>>>( [] @@ -52,20 +58,26 @@ export const ChooseConnectorSelectable: React.FC<ChooseConnectorSelectableProps> }; return ( <EuiFlexGroup - gutterSize="m" - key={key + '-span'} - justifyContent="spaceBetween" className={contentClassName} + key={key + '-span'} + gutterSize="m" + responsive={false} + direction="row" > - <EuiFlexGroup gutterSize="m"> - <EuiFlexItem grow={false}>{_prepend}</EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiText size="s" textAlign="left"> - {label} - </EuiText> - </EuiFlexItem> - </EuiFlexGroup> - <EuiFlexItem grow={false}>{_append}</EuiFlexItem> + <EuiFlexItem grow={false}>{_prepend}</EuiFlexItem> + <EuiFlexItem + css={css` + overflow: auto; + `} + grow + > + <EuiText textAlign="left" size="s"> + <EuiTextTruncate text={label} truncation="end" /> + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiBadgeGroup gutterSize="xs">{_append}</EuiBadgeGroup> + </EuiFlexItem> </EuiFlexGroup> ); }; @@ -83,43 +95,39 @@ export const ChooseConnectorSelectable: React.FC<ChooseConnectorSelectableProps> const getInitialOptions = () => { return allConnectors.map((connector, key) => { const _append: JSX.Element[] = []; + let _ariaLabelAppend = ''; if (connector.isTechPreview) { _append.push( - <EuiBadge key={key + '-preview'} iconType="beaker" color="hollow"> - {i18n.translate( - 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.thechPreviewBadgeLabel', - { defaultMessage: 'Tech preview' } - )} + <EuiBadge + aria-label={TECH_PREVIEW_LABEL} + key={key + '-preview'} + iconType="beaker" + color="hollow" + > + {TECH_PREVIEW_LABEL} </EuiBadge> ); + _ariaLabelAppend += `, ${TECH_PREVIEW_LABEL}`; } if (connector.isBeta) { _append.push( - <EuiBadge key={key + '-beta'} iconType={'beta'} color="hollow"> - {i18n.translate( - 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.BetaBadgeLabel', - { - defaultMessage: 'Beta', - } - )} + <EuiBadge aria-label={BETA_LABEL} key={key + '-beta'} iconType={'beta'} color="hollow"> + {BETA_LABEL} </EuiBadge> ); + _ariaLabelAppend += `, ${BETA_LABEL}`; } if (selfManaged === 'native' && !connector.isNative) { _append.push( <EuiBadge key={key + '-self'} iconType={'warning'} color="warning"> - {i18n.translate( - 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.OnlySelfManagedBadgeLabel', - { - defaultMessage: 'Self managed', - } - )} + {CONNECTOR_CLIENT_LABEL} </EuiBadge> ); } return { _append, _prepend: <EuiIcon size="l" type={connector.iconPath} />, + 'aria-label': connector.name + _ariaLabelAppend, key: key.toString(), label: connector.name, }; @@ -133,33 +141,31 @@ export const ChooseConnectorSelectable: React.FC<ChooseConnectorSelectableProps> }, [selfManaged]); return ( - <EuiFlexItem> - <EuiComboBox - aria-label={i18n.translate( - 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.euiComboBox.accessibleScreenReaderLabelLabel', - { defaultMessage: 'Select a data source for your connector to use.' } - )} - prepend={<EuiIcon type={selectedConnector?.iconPath ?? connectorLogo} size="l" />} - singleSelection - fullWidth - placeholder={i18n.translate( - 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.placeholder.text', - { defaultMessage: 'Choose a data source' } - )} - options={selectableOptions} - selectedOptions={selectedOption} - onChange={(selectedItem) => { - setSelectedOption(selectedItem); - if (selectedItem.length === 0) { - setSelectedConnector(null); - return; - } - const keySelected = Number(selectedItem[0].key); - setSelectedConnector(allConnectors[keySelected]); - }} - renderOption={renderOption} - rowHeight={(euiTheme.base / 2) * 5} - /> - </EuiFlexItem> + <EuiComboBox + aria-label={i18n.translate( + 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.euiComboBox.accessibleScreenReaderLabelLabel', + { defaultMessage: 'Select a data source for your connector to use.' } + )} + prepend={<EuiIcon type={selectedConnector?.iconPath ?? connectorLogo} size="l" />} + singleSelection + fullWidth + placeholder={i18n.translate( + 'xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.placeholder.text', + { defaultMessage: 'Choose a data source' } + )} + options={selectableOptions} + selectedOptions={selectedOption} + onChange={(selectedItem) => { + setSelectedOption(selectedItem); + if (selectedItem.length === 0) { + setSelectedConnector(null); + return; + } + const keySelected = Number(selectedItem[0].key); + setSelectedConnector(allConnectors[keySelected]); + }} + renderOption={renderOption} + rowHeight={(euiTheme.base / 2) * 5} + /> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx index 9e0aed3fa75f..f91a8eff670f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/components/connector_description_popover.tsx @@ -6,7 +6,10 @@ */ import React, { useState } from 'react'; +import { css } from '@emotion/react'; + import { + EuiButton, EuiButtonIcon, EuiCallOut, EuiFlexGroup, @@ -83,13 +86,15 @@ const connectorClientPopoverPanels = [ ]; export interface ConnectorDescriptionPopoverProps { - isDisabled: boolean; isNative: boolean; + isRunningLocally?: boolean; + showIsOnlySelfManaged: boolean; } export const ConnectorDescriptionPopover: React.FC<ConnectorDescriptionPopoverProps> = ({ isNative, - isDisabled, + isRunningLocally, + showIsOnlySelfManaged, }) => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); const panels = isNative ? nativePopoverPanels : connectorClientPopoverPanels; @@ -111,55 +116,115 @@ export const ConnectorDescriptionPopover: React.FC<ConnectorDescriptionPopoverPr setIsPopoverOpen(false); }} > - <EuiPanel hasBorder={false} hasShadow={false}> - {isDisabled && ( - <EuiFlexGroup> - <EuiFlexItem> - <EuiCallOut - title={i18n.translate( - 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.notAvailableTitle', - { - defaultMessage: - 'This connector is not available as an Elastic-managed Connector', + <EuiPanel + css={css` + max-width: 700px; + `} + hasBorder={false} + hasShadow={false} + > + {(showIsOnlySelfManaged || isRunningLocally) && ( + <> + <EuiFlexGroup> + <EuiFlexItem> + <EuiCallOut + title={ + showIsOnlySelfManaged + ? i18n.translate( + 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.isOnlySelfManagedAvailableTitle', + { + defaultMessage: + 'This connector is not available as an Elastic-managed Connector', + } + ) + : i18n.translate( + 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.isRunningLocallyTitle', + { + defaultMessage: + 'Elastic managed connectors are only available in Elastic Cloud', + } + ) } - )} - size="s" - iconType="warning" - color="warning" - /> - </EuiFlexItem> + size="s" + iconType="warning" + color="warning" + /> + </EuiFlexItem> + </EuiFlexGroup> + <EuiSpacer size="m" /> + </> + )} + + {!isRunningLocally && ( + <EuiFlexGroup> + {panels.map((panel) => { + return ( + <EuiFlexItem grow={false} key={panel.id}> + <EuiFlexGroup + direction="column" + alignItems="center" + gutterSize="s" + style={{ maxWidth: 200 }} + > + <EuiFlexItem grow={false}> + <EuiFlexGroup responsive={false} gutterSize="s"> + {panel.icons.map((icon, index) => ( + <EuiFlexItem grow={false} key={index}> + {icon} + </EuiFlexItem> + ))} + </EuiFlexGroup> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiText size="s" grow={false} textAlign="center"> + <p>{panel.description}</p> + </EuiText> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + ); + })} </EuiFlexGroup> )} - <EuiSpacer size="m" /> - <EuiFlexGroup> - {panels.map((panel) => { - return ( - <EuiFlexItem grow={false} key={panel.id}> - <EuiFlexGroup - direction="column" - alignItems="center" - gutterSize="s" - style={{ maxWidth: 200 }} + {isRunningLocally && ( + <> + <EuiSpacer size="m" /> + <EuiFlexGroup direction="column" justifyContent="center"> + <EuiFlexItem grow> + <EuiText textAlign="center"> + <h3> + {i18n.translate( + 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.learnMore', + { defaultMessage: 'Explore Elastic Cloud with your 14-day free trial' } + )} + </h3> + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow> + <EuiText size="s" textAlign="center" color="subdued"> + {i18n.translate( + 'xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.learnMore', + { + defaultMessage: + 'Take advantage of Elastic managed connectors and generative AI capabilities to address search challenges across your organization in real time, at scale.', + } + )} + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiButton + data-test-subj="enterpriseSearchConnectorStartFreeTrialButton" + href="https://cloud.elastic.co/registration?onboarding_token=connectors" + target="_blank" > - <EuiFlexItem grow={false}> - <EuiFlexGroup responsive={false} gutterSize="s"> - {panel.icons.map((icon, index) => ( - <EuiFlexItem grow={false} key={index}> - {icon} - </EuiFlexItem> - ))} - </EuiFlexGroup> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiText size="s" grow={false} textAlign="center"> - <p>{panel.description}</p> - </EuiText> - </EuiFlexItem> - </EuiFlexGroup> + {i18n.translate('xpack.enterpriseSearch.createConnector.startTrialButtonLabel', { + defaultMessage: 'Start free trial', + })} + </EuiButton> </EuiFlexItem> - ); - })} - </EuiFlexGroup> + </EuiFlexGroup> + </> + )} </EuiPanel> </EuiPopover> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx index 6e83bf98c237..095990c823f0 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/create_connector.tsx @@ -65,9 +65,14 @@ export const CreateConnector: React.FC = () => { const { setCurrentStep } = useActions(NewConnectorLogic); const stepStates = generateStepState(currentStep); + const { config } = useValues(KibanaLogic); + const isRunningLocally = (config.host ?? '').includes('localhost'); + useEffect(() => { - // TODO: separate this to ability and preference - if (selectedConnector && !selectedConnector.isNative && selfManagePreference === 'native') { + if ( + (selectedConnector && !selectedConnector.isNative && selfManagePreference === 'native') || + isRunningLocally + ) { setSelfManagePreference('selfManaged'); } }, [selectedConnector]); @@ -141,6 +146,7 @@ export const CreateConnector: React.FC = () => { setSelfManagePreference(preference); }} error={errorToText(error)} + isRunningLocally={isRunningLocally} /> ), }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx index 7e23474b207f..fb740189148d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/connectors/create_connector/start_step.tsx @@ -20,6 +20,7 @@ import { EuiRadio, EuiSpacer, EuiText, + useIsWithinBreakpoints, EuiTitle, useGeneratedHtmlId, } from '@elastic/eui'; @@ -33,13 +34,14 @@ import { GeneratedConfigFields } from '../../connector_detail/components/generat import { ConnectorViewLogic } from '../../connector_detail/connector_view_logic'; import { NewConnectorLogic } from '../../new_index/method_connector/new_connector_logic'; -import { ChooseConnectorSelectable } from './components/choose_connector_selectable'; +import { ChooseConnector } from './components/choose_connector'; import { ConnectorDescriptionPopover } from './components/connector_description_popover'; import { ManualConfiguration } from './components/manual_configuration'; import { SelfManagePreference } from './create_connector'; interface StartStepProps { error?: string | React.ReactNode; + isRunningLocally: boolean; onSelfManagePreferenceChange(preference: SelfManagePreference): void; selfManagePreference: SelfManagePreference; setCurrentStep: Function; @@ -48,11 +50,13 @@ interface StartStepProps { export const StartStep: React.FC<StartStepProps> = ({ title, + isRunningLocally, selfManagePreference, setCurrentStep, onSelfManagePreferenceChange, error, }) => { + const isMediumDevice = useIsWithinBreakpoints(['xs', 's', 'm', 'l']); const elasticManagedRadioButtonId = useGeneratedHtmlId({ prefix: 'elasticManagedRadioButton' }); const selfManagedRadioButtonId = useGeneratedHtmlId({ prefix: 'selfManagedRadioButton' }); @@ -93,8 +97,8 @@ export const StartStep: React.FC<StartStepProps> = ({ <h3>{title}</h3> </EuiTitle> <EuiSpacer size="m" /> - <EuiFlexGroup> - <EuiFlexItem> + <EuiFlexGroup direction={isMediumDevice ? 'column' : 'row'}> + <EuiFlexItem grow={7}> <EuiFormRow fullWidth label={i18n.translate( @@ -102,10 +106,10 @@ export const StartStep: React.FC<StartStepProps> = ({ { defaultMessage: 'Connector' } )} > - <ChooseConnectorSelectable selfManaged={selfManagePreference} /> + <ChooseConnector selfManaged={selfManagePreference} /> </EuiFormRow> </EuiFlexItem> - <EuiFlexItem> + <EuiFlexItem grow={5}> <EuiFormRow fullWidth isInvalid={!!error} @@ -142,6 +146,7 @@ export const StartStep: React.FC<StartStepProps> = ({ generateConnectorName({ connectorName: rawName, connectorType: selectedConnector.serviceType, + isManagedConnector: selectedConnector.isNative, }); } }} @@ -206,14 +211,15 @@ export const StartStep: React.FC<StartStepProps> = ({ { defaultMessage: 'Elastic managed' } )} checked={selfManagePreference === 'native'} - disabled={selectedConnector?.isNative === false} + disabled={selectedConnector?.isNative === false || isRunningLocally} onChange={() => onSelfManagePreferenceChange('native')} name="setUp" /> </EuiFlexItem> <EuiFlexItem grow={false}> <ConnectorDescriptionPopover - isDisabled={selectedConnector?.isNative === false} + showIsOnlySelfManaged={selectedConnector?.isNative === false} + isRunningLocally={isRunningLocally} isNative /> </EuiFlexItem> @@ -231,7 +237,7 @@ export const StartStep: React.FC<StartStepProps> = ({ /> </EuiFlexItem> <EuiFlexItem grow={false}> - <ConnectorDescriptionPopover isDisabled={false} isNative={false} /> + <ConnectorDescriptionPopover showIsOnlySelfManaged={false} isNative={false} /> </EuiFlexItem> </EuiFlexGroup> </EuiPanel> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.test.tsx deleted file mode 100644 index b307835534dd..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorConnecting } from '.'; - -describe('ErrorConnecting', () => { - it('renders', () => { - const wrapper = shallow(<ErrorConnecting />); - - const errorStatePrompt = wrapper.find(ErrorStatePrompt); - expect(errorStatePrompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.tsx deleted file mode 100644 index 69f479026014..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/error_connecting.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SetSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -export const ErrorConnecting: React.FC = () => { - return ( - <> - <SetPageChrome /> - <SendTelemetry action="error" metric="cannot_connect" /> - - <KibanaPageTemplate isEmptyState> - <ErrorStatePrompt /> - </KibanaPageTemplate> - </> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts index 0c8a81d90149..f2f327f40650 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_connector/new_connector_logic.ts @@ -192,6 +192,7 @@ export const NewConnectorLogic = kea<MakeLogicType<NewConnectorValues, NewConnec if (connector) { actions.generateConnectorName({ connectorType: connector.serviceType, + isManagedConnector: connector.isNative, }); } }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_crawler/method_crawler.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_crawler/method_crawler.tsx index 9e7702379a9a..e4842f765b4a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_crawler/method_crawler.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/method_crawler/method_crawler.tsx @@ -21,7 +21,6 @@ import { LICENSING_FEATURE, } from '../../../../shared/licensing_callout/licensing_callout'; import { CreateCrawlerIndexApiLogic } from '../../../api/crawler/create_crawler_index_api_logic'; -import { CannotConnect } from '../../search_index/components/cannot_connect'; import { NewSearchIndexTemplate } from '../new_search_index_template'; import { MethodCrawlerLogic } from './method_crawler_logic'; @@ -44,11 +43,6 @@ export const MethodCrawler: React.FC = () => { <LicensingCallout feature={LICENSING_FEATURE.CRAWLER} /> </EuiFlexItem> )} - {Boolean(errorConnectingMessage) && ( - <EuiFlexItem> - <CannotConnect /> - </EuiFlexItem> - )} <EuiFlexItem> <NewSearchIndexTemplate type="crawler" diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_index.tsx index 7b71ee9e41ca..0244e9acbe35 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/new_index/new_index.tsx @@ -21,7 +21,6 @@ import { KibanaLogic } from '../../../shared/kibana/kibana_logic'; import { NEW_API_PATH, NEW_CRAWLER_PATH, NEW_INDEX_SELECT_CONNECTOR_PATH } from '../../routes'; import { EnterpriseSearchContentPageTemplate } from '../layout/page_template'; -import { CannotConnect } from '../search_index/components/cannot_connect'; import { baseBreadcrumbs } from '../search_indices'; import { NewIndexCard } from './new_index_card'; @@ -60,33 +59,30 @@ export const NewIndex: React.FC = () => { }} > <EuiFlexGroup direction="column"> - {errorConnectingMessage && productFeatures.hasWebCrawler && <CannotConnect />} - <> - <EuiFlexItem> - <EuiFlexGroup> - {availableIngestionMethodOptions.map((type) => ( - <EuiFlexItem key={type}> - <NewIndexCard - disabled={Boolean( - type === INGESTION_METHOD_IDS.CRAWLER && - (errorConnectingMessage || !config.host) - )} - type={type} - onSelect={() => { - if (type === INGESTION_METHOD_IDS.CONNECTOR) { - KibanaLogic.values.navigateToUrl(NEW_INDEX_SELECT_CONNECTOR_PATH); - } else if (type === INGESTION_METHOD_IDS.CRAWLER) { - KibanaLogic.values.navigateToUrl(NEW_CRAWLER_PATH); - } else { - KibanaLogic.values.navigateToUrl(NEW_API_PATH); - } - }} - /> - </EuiFlexItem> - ))} - </EuiFlexGroup> - </EuiFlexItem> - </> + <EuiFlexItem> + <EuiFlexGroup> + {availableIngestionMethodOptions.map((type) => ( + <EuiFlexItem key={type}> + <NewIndexCard + disabled={Boolean( + type === INGESTION_METHOD_IDS.CRAWLER && + (errorConnectingMessage || !config.host) + )} + type={type} + onSelect={() => { + if (type === INGESTION_METHOD_IDS.CONNECTOR) { + KibanaLogic.values.navigateToUrl(NEW_INDEX_SELECT_CONNECTOR_PATH); + } else if (type === INGESTION_METHOD_IDS.CRAWLER) { + KibanaLogic.values.navigateToUrl(NEW_CRAWLER_PATH); + } else { + KibanaLogic.values.navigateToUrl(NEW_API_PATH); + } + }} + /> + </EuiFlexItem> + ))} + </EuiFlexGroup> + </EuiFlexItem> </EuiFlexGroup> </EnterpriseSearchContentPageTemplate> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/cannot_connect.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/cannot_connect.tsx deleted file mode 100644 index 3fa7b40117a6..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/components/cannot_connect.tsx +++ /dev/null @@ -1,47 +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 { EuiCallOut, EuiSpacer, EuiText } from '@elastic/eui'; - -import { i18n } from '@kbn/i18n'; - -import { FormattedMessage } from '@kbn/i18n-react'; - -import { EuiLinkTo } from '../../../../shared/react_router_helpers'; - -import { ERROR_STATE_PATH } from '../../../routes'; - -export const CannotConnect: React.FC = () => { - return ( - <EuiCallOut - iconType="warning" - color="warning" - title={i18n.translate('xpack.enterpriseSearch.content.cannotConnect.title', { - defaultMessage: 'Cannot connect to Enterprise Search', - })} - > - <EuiSpacer size="s" /> - <EuiText size="s"> - <FormattedMessage - id="xpack.enterpriseSearch.content.searchIndex.cannotConnect.body" - defaultMessage="The Elastic web crawler requires Enterprise Search. {link}" - values={{ - link: ( - <EuiLinkTo to={ERROR_STATE_PATH}> - {i18n.translate('xpack.enterpriseSearch.content.cannotConnect.body', { - defaultMessage: 'More information.', - })} - </EuiLinkTo> - ), - }} - /> - </EuiText> - </EuiCallOut> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_error.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_error.tsx index 1ed3857b2c7c..9d3daac23111 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_error.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/index_error.tsx @@ -31,15 +31,10 @@ export interface IndexErrorProps { } interface SemanticTextProperty extends MappingPropertyBase { - inference_id?: string; + inference_id: string; type: 'semantic_text'; } -/* - This will be repalce once we add default elser inference_id - with the index mapping response. -*/ -const ELSER_PRECONFIGURED_ENDPOINTS = '.elser-2-elasticsearch'; const isInferencePreconfigured = (inferenceId: string) => inferenceId.startsWith('.'); const parseMapping = (mappings: MappingTypeMapping) => { @@ -56,11 +51,6 @@ const getSemanticTextFields = ( ): Array<{ path: string; source: SemanticTextProperty }> => { return Object.entries(fields).flatMap(([key, value]) => { const currentPath: string = path ? `${path}.${key}` : key; - if (value.type === 'semantic_text') { - value = value.inference_id - ? value - : { ...value, inference_id: ELSER_PRECONFIGURED_ENDPOINTS }; - } const currentField: Array<{ path: string; source: SemanticTextProperty }> = value.type === 'semantic_text' ? [{ path: currentPath, source: value }] : []; if (hasProperties(value)) { diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx index acba51ed497d..b12dac64ea60 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/inference_pipeline_card.tsx @@ -51,17 +51,11 @@ export const TrainedModelHealthPopover: React.FC<InferencePipeline> = (pipeline) const { pipelineName } = pipeline; const actionButton = ( - <EuiButtonEmpty - iconSide="right" - flush="both" - iconType="boxesHorizontal" - onClick={() => setIsPopOverOpen(!isPopOverOpen)} - > - <TrainedModelHealth - modelState={pipeline.modelState} - modelStateReason={pipeline.modelStateReason} - /> - </EuiButtonEmpty> + <TrainedModelHealth + modelState={pipeline.modelState} + modelStateReason={pipeline.modelStateReason} + onClickAction={() => setIsPopOverOpen(!isPopOverOpen)} + /> ); const showConfirmDeleteModal = () => { @@ -81,6 +75,7 @@ export const TrainedModelHealthPopover: React.FC<InferencePipeline> = (pipeline) <EuiFlexItem> <span> <EuiButtonEmpty + data-test-subj="enterpriseSearchTrainedModelHealthPopoverFixIssueInTrainedModelsButton" data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-inferencePipeline-fixIssueInTrainedModels`} size="s" flush="both" @@ -101,6 +96,7 @@ export const TrainedModelHealthPopover: React.FC<InferencePipeline> = (pipeline) <EuiFlexItem> <span> <EuiButtonEmpty + data-test-subj="enterpriseSearchTrainedModelHealthPopoverViewInStackManagementButton" data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-inferencePipeline-stackManagement`} size="s" flush="both" @@ -119,6 +115,7 @@ export const TrainedModelHealthPopover: React.FC<InferencePipeline> = (pipeline) <EuiFlexItem> <span> <EuiButtonEmpty + data-test-subj="enterpriseSearchTrainedModelHealthPopoverDetachPipelineButton" data-telemetry-id={`entSearchContent-${ingestionMethod}-pipelines-inferencePipeline-detachPipeline`} size="s" flush="both" diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx index 329a89f0e462..2037785a0457 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/pipelines/ml_model_health.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { EuiHealth, EuiToolTip } from '@elastic/eui'; +import { EuiButtonEmpty, EuiHealth, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -113,12 +113,14 @@ export interface TrainedModelHealthProps { modelState: TrainedModelState | MlModelDeploymentState; modelStateReason?: string; isDownloadable?: boolean; + onClickAction?: Function; } export const TrainedModelHealth: React.FC<TrainedModelHealthProps> = ({ modelState, modelStateReason, isDownloadable, + onClickAction, }) => { let modelHealth: { healthColor: string; @@ -207,7 +209,19 @@ export const TrainedModelHealth: React.FC<TrainedModelHealthProps> = ({ } return ( <EuiToolTip content={modelHealth.tooltipText}> - <EuiHealth color={modelHealth.healthColor}>{modelHealth.healthText}</EuiHealth> + {onClickAction ? ( + <EuiButtonEmpty + data-test-subj="enterpriseSearchTrainedModelHealthPopoverButton" + iconSide="right" + flush="both" + iconType="boxesHorizontal" + onClick={() => onClickAction()} + > + <EuiHealth color={modelHealth.healthColor}>{modelHealth.healthText}</EuiHealth> + </EuiButtonEmpty> + ) : ( + <EuiHealth color={modelHealth.healthColor}>{modelHealth.healthText}</EuiHealth> + )} </EuiToolTip> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx index 6cdd06f1586a..e8876a7c5681 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_index/search_index.tsx @@ -18,8 +18,6 @@ import { i18n } from '@kbn/i18n'; import { ClientConfigType } from '../../../../../common/types'; import { generateEncodedPath } from '../../../shared/encode_path_params'; -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; import { SEARCH_INDEX_PATH, SEARCH_INDEX_TAB_PATH } from '../../routes'; @@ -71,7 +69,6 @@ export const SearchIndex: React.FC = () => { }>(); const { indexName } = useValues(IndexNameLogic); - const { errorConnectingMessage } = useValues(HttpLogic); /** * Guided Onboarding needs us to mark the add data step as complete as soon as the user has data in an index. @@ -286,32 +283,19 @@ export const SearchIndex: React.FC = () => { }} > <IndexError indexName={indexName} /> - <Content - index={index} - errorConnectingMessage={errorConnectingMessage} - config={config} - tabs={tabs} - tabId={tabId} - /> + <Content index={index} config={config} tabs={tabs} tabId={tabId} /> </EnterpriseSearchContentPageTemplate> ); }; interface ContentProps { config?: ClientConfigType; - errorConnectingMessage: string; index?: ElasticsearchViewIndex; tabId?: string; tabs: EuiTabbedContentTab[]; } -const Content: React.FC<ContentProps> = ({ - config, - errorConnectingMessage, - index, - tabs, - tabId, -}) => { +const Content: React.FC<ContentProps> = ({ index, tabs, tabId }) => { const selectedTab = useMemo(() => tabs.find((tab) => tab.id === tabId), [tabId]); const onTabClick = (tab: EuiTabbedContentTab) => { @@ -329,9 +313,6 @@ const Content: React.FC<ContentProps> = ({ if (isCrawlerIndex(index) && !index.connector) { return <NoConnectorRecord />; } - if (isCrawlerIndex(index) && (Boolean(errorConnectingMessage) || !config?.host)) { - return <ErrorStatePrompt />; - } return ( <> <EuiTabbedContent size="l" tabs={tabs} selectedTab={selectedTab} onTabClick={onTabClick} /> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx index dece1b4beb2f..d44e95b6271e 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/search_indices/search_indices.tsx @@ -11,10 +11,8 @@ import { useValues, useActions } from 'kea'; import { EuiButton, - EuiCallOut, EuiFlexGroup, EuiFlexItem, - EuiSpacer, EuiTitle, EuiSwitch, EuiSearchBar, @@ -26,14 +24,13 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { AddContentEmptyPrompt } from '../../../shared/add_content_empty_prompt'; -import { HttpLogic } from '../../../shared/http/http_logic'; import { KibanaLogic } from '../../../shared/kibana'; -import { EuiButtonTo, EuiLinkTo } from '../../../shared/react_router_helpers'; +import { EuiLinkTo } from '../../../shared/react_router_helpers'; import { handlePageChange } from '../../../shared/table_pagination'; import { NEW_API_PATH } from '../../routes'; import { EnterpriseSearchContentPageTemplate } from '../layout/page_template'; -import { CannotConnect } from '../search_index/components/cannot_connect'; +// import { CannotConnect } from '../search_index/components/cannot_connect'; import { DefaultSettingsFlyout } from '../settings/default_settings_flyout'; import { DeleteIndexModal } from './delete_index_modal'; @@ -53,8 +50,7 @@ export const SearchIndices: React.FC = () => { const [showHiddenIndices, setShowHiddenIndices] = useState(false); const [onlyShowSearchOptimizedIndices, setOnlyShowSearchOptimizedIndices] = useState(false); const [searchQuery, setSearchValue] = useState(''); - const { config, productFeatures } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); + const { productFeatures } = useValues(KibanaLogic); const [showDefaultSettingsFlyout, setShowDefaultSettingsFlyout] = useState<boolean>(false); useEffect(() => { @@ -142,37 +138,6 @@ export const SearchIndices: React.FC = () => { {productFeatures.hasDefaultIngestPipeline && showDefaultSettingsFlyout && ( <DefaultSettingsFlyout closeFlyout={() => setShowDefaultSettingsFlyout(false)} /> )} - {config.host && config.canDeployEntSearch && errorConnectingMessage && ( - <> - <CannotConnect /> - <EuiSpacer /> - </> - )} - {!config.host && config.canDeployEntSearch && ( - <> - <EuiCallOut - title={i18n.translate('xpack.enterpriseSearch.noEntSearchConfigured.title', { - defaultMessage: 'Enterprise Search has not been configured', - })} - iconType="warning" - color="warning" - > - <p> - <FormattedMessage - id="xpack.enterpriseSearch.noEntSearch.noCrawler" - defaultMessage="The Elastic web crawler is not available without Enterprise Search." - /> - </p> - <EuiButtonTo iconType="help" fill to="/setup_guide" color="warning"> - <FormattedMessage - id="xpack.enterpriseSearch.noEntSearch.setupGuideCta" - defaultMessage="Review setup guide" - /> - </EuiButtonTo> - </EuiCallOut> - <EuiSpacer /> - </> - )} {!hasNoIndices ? ( <EuiFlexGroup direction="column"> <EuiFlexItem> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx index 9fcfe7c7fcfa..a32062256eec 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.test.tsx @@ -15,7 +15,6 @@ import React from 'react'; import { shallow } from 'enzyme'; import { SetupGuide } from '../enterprise_search_overview/components/setup_guide'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { SearchIndicesRouter } from './components/search_indices'; @@ -28,15 +27,6 @@ describe('EnterpriseSearchContent', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); }); - it('renders VersionMismatchPage when there are mismatching versions', () => { - setMockValues({ config: { canDeployEntSearch: true, host: 'host' } }); - const wrapper = shallow( - <EnterpriseSearchContent enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" /> - ); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); - it('renders EnterpriseSearchContentConfigured when config.host is set & available', () => { setMockValues({ config: { canDeployEntSearch: true, host: 'some.url' }, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx index 2ec701aa9847..d464923dea2c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/index.tsx @@ -8,17 +8,10 @@ import React from 'react'; import { Redirect } from 'react-router-dom'; -import { useValues } from 'kea'; - import { Route, Routes } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; import { SetupGuide } from '../enterprise_search_overview/components/setup_guide'; -import { ErrorStatePrompt } from '../shared/error_state'; -import { HttpLogic } from '../shared/http'; -import { KibanaLogic } from '../shared/kibana'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { ConnectorsRouter } from './components/connectors/connectors_router'; import { CrawlersRouter } from './components/connectors/crawlers_router'; @@ -27,44 +20,20 @@ import { SearchIndicesRouter } from './components/search_indices'; import { CONNECTORS_PATH, CRAWLERS_PATH, - ERROR_STATE_PATH, ROOT_PATH, SEARCH_INDICES_PATH, SETUP_GUIDE_PATH, } from './routes'; export const EnterpriseSearchContent: React.FC<InitialAppData> = (props) => { - const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (config.host && config.canDeployEntSearch && incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } - - return <EnterpriseSearchContentConfigured {...(props as Required<InitialAppData>)} />; - }; - return ( <Routes> <Route exact path={SETUP_GUIDE_PATH}> <SetupGuide /> </Route> - <Route exact path={ERROR_STATE_PATH}> - {config.host && config.canDeployEntSearch && errorConnectingMessage ? ( - <ErrorStatePrompt /> - ) : ( - <Redirect to={SEARCH_INDICES_PATH} /> - )} + <Route> + <EnterpriseSearchContentConfigured {...(props as Required<InitialAppData>)} /> </Route> - <Route>{showView()}</Route> </Routes> ); }; diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.test.tsx deleted file mode 100644 index b307835534dd..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorConnecting } from '.'; - -describe('ErrorConnecting', () => { - it('renders', () => { - const wrapper = shallow(<ErrorConnecting />); - - const errorStatePrompt = wrapper.find(ErrorStatePrompt); - expect(errorStatePrompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.tsx deleted file mode 100644 index 6fc4ae284220..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/error_connecting.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 { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SendEnterpriseSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; - -export const ErrorConnecting: React.FC = () => ( - <KibanaPageTemplate isEmptyState> - <SendTelemetry action="error" metric="cannot_connect" /> - - <ErrorStatePrompt /> - </KibanaPageTemplate> -); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx index dd67bf33d987..3718a495cd17 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.test.tsx @@ -11,8 +11,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { ErrorStateCallout } from '../../../shared/error_state'; - import { TrialCallout } from '../trial_callout'; import { ElasticsearchProductCard } from './elasticsearch_product_card'; @@ -34,23 +32,6 @@ describe('ProductSelector', () => { expect(wrapper.find(TrialCallout)).toHaveLength(1); }); - it('does not render connection error callout without an error', () => { - setMockValues({ config: { canDeployEntSearch: true, host: 'localhost' } }); - const wrapper = shallow(<ProductSelector />); - - expect(wrapper.find(ErrorStateCallout)).toHaveLength(0); - }); - - it('does render connection error callout with an error', () => { - setMockValues({ - config: { canDeployEntSearch: true, host: 'localhost' }, - errorConnectingMessage: '502 Bad Gateway', - }); - const wrapper = shallow(<ProductSelector />); - - expect(wrapper.find(ErrorStateCallout)).toHaveLength(1); - }); - describe('access checks when host is set', () => { beforeEach(() => { setMockValues({ config: { canDeployEntSearch: true, host: 'localhost' } }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx index 1f25f5f69c2e..7c22f5bfd433 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/product_selector/product_selector.tsx @@ -20,8 +20,6 @@ import { import { i18n } from '@kbn/i18n'; import { ApiKeyPanel } from '../../../shared/api_key/api_key_panel'; -import { ErrorStateCallout } from '../../../shared/error_state'; -import { HttpLogic } from '../../../shared/http'; import { KibanaLogic } from '../../../shared/kibana'; import { SetSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; import { SearchLabsBanner } from '../../../shared/search_labs_banner/search_labs_banner'; @@ -39,11 +37,8 @@ import './product_selector.scss'; import { WelcomeBanner } from './welcome_banner'; export const ProductSelector: React.FC = () => { - const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); const { user } = useValues(KibanaLogic); - const showErrorConnecting = !!(config.host && errorConnectingMessage); // The create index flow does not work without ent-search, when content is updated // to no longer rely on ent-search we can always show the Add Content component @@ -80,12 +75,6 @@ export const ProductSelector: React.FC = () => { <EuiSpacer size="xl" /> <IngestionSelector /> <EuiSpacer /> - {showErrorConnecting && ( - <> - <SendTelemetry action="error" metric="cannot_connect" /> - <ErrorStateCallout /> - </> - )} <EuiSpacer size="xl" /> <EuiTitle> diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx index 6742de0816f8..7754aa0cf11f 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.test.tsx @@ -11,8 +11,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; - import { ProductSelector } from './components/product_selector'; import { SetupGuide } from './components/setup_guide'; @@ -29,17 +27,4 @@ describe('EnterpriseSearchOverview', () => { expect(wrapper.find(SetupGuide)).toHaveLength(1); expect(wrapper.find(ProductSelector)).toHaveLength(1); }); - - it('renders the version error message if versions mismatch and the host is configured', () => { - setMockValues({ - errorConnectingMessage: '', - config: { host: 'localhost' }, - }); - const wrapper = shallow( - <EnterpriseSearchOverview enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" /> - ); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - expect(wrapper.find(ProductSelector)).toHaveLength(0); - }); }); diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx index 64ab8e44a69a..70d4b40bb7f9 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/index.tsx @@ -7,49 +7,22 @@ import React from 'react'; -import { useValues } from 'kea'; - import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { KibanaLogic } from '../shared/kibana'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { ProductSelector } from './components/product_selector'; import { SetupGuide } from './components/setup_guide'; import { ROOT_PATH, SETUP_GUIDE_PATH } from './routes'; -export const EnterpriseSearchOverview: React.FC<InitialAppData> = ({ - enterpriseSearchVersion, - kibanaVersion, -}) => { - const { config } = useValues(KibanaLogic); - - const incompatibleVersions = !!( - config.host && isVersionMismatch(enterpriseSearchVersion, kibanaVersion) - ); - - const showView = () => { - if (incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } - - return <ProductSelector />; - }; - +export const EnterpriseSearchOverview: React.FC<InitialAppData> = ({}) => { return ( <Routes> <Route exact path={SETUP_GUIDE_PATH}> <SetupGuide /> </Route> <Route exact path={ROOT_PATH}> - {showView()} + <ProductSelector /> </Route> </Routes> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx b/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx index 118cb5cb7caf..e41918d8ce29 100644 --- a/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/search_experiences/index.tsx @@ -9,35 +9,17 @@ import React from 'react'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { SearchExperiencesGuide } from './components/search_experiences_guide'; import { ROOT_PATH } from './routes'; -export const SearchExperiences: React.FC<InitialAppData> = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - - const showView = () => { - if (incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } - - return <SearchExperiencesGuide />; - }; - +export const SearchExperiences: React.FC<InitialAppData> = () => { return ( <Routes> <Route exact path={ROOT_PATH}> - {showView()} + <SearchExperiencesGuide /> </Route> </Routes> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx index f33142bae940..e6e5e3e66bbf 100644 --- a/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/semantic_search/index.tsx @@ -12,29 +12,17 @@ import { Switch } from 'react-router-dom'; import { Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { SemanticSearchGuide } from './components/semantic_search_guide/semantic_search_guide'; import { ROOT_PATH } from './routes'; -export const EnterpriseSearchSemanticSearch: React.FC<InitialAppData> = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - +export const EnterpriseSearchSemanticSearch: React.FC<InitialAppData> = () => { return ( <Switch> <Route exact path={ROOT_PATH}> - {incompatibleVersions ? ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ) : ( - <SemanticSearchGuide /> - )} + <SemanticSearchGuide /> </Route> </Switch> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/constants/labels.ts b/x-pack/plugins/enterprise_search/public/applications/shared/constants/labels.ts index f1da7cefa5cc..dd4e13a6df27 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/constants/labels.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/constants/labels.ts @@ -27,6 +27,10 @@ export const BETA_LABEL = i18n.translate('xpack.enterpriseSearch.betaLabel', { defaultMessage: 'Beta', }); +export const TECH_PREVIEW_LABEL = i18n.translate('xpack.enterpriseSearch.techPreviewLabel', { + defaultMessage: 'Tech preview', +}); + export const NATIVE_LABEL = i18n.translate('xpack.enterpriseSearch.nativeLabel', { defaultMessage: 'Elastic managed', }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.scss b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.scss deleted file mode 100644 index 0d9926ab147b..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.scss +++ /dev/null @@ -1,12 +0,0 @@ -.troubleshootingSteps { - text-align: left; - - li { - margin: $euiSizeS auto; - } - - ul, - ol { - margin-bottom: 0; - } -} diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx deleted file mode 100644 index 867702b8326a..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.test.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import '../../__mocks__/shallow_useeffect.mock'; -import { setMockValues, mockKibanaValues } from '../../__mocks__/kea_logic'; - -import React from 'react'; - -import { mountWithIntl } from '../../test_helpers'; - -import { ErrorStatePrompt } from '.'; - -describe('ErrorState', () => { - const values = { - config: {}, - cloud: { isCloudEnabled: true }, - errorConnectingMessage: '502 Bad Gateway', - }; - - beforeAll(() => { - setMockValues(values); - }); - - it('renders an error message', () => { - const wrapper = mountWithIntl(<ErrorStatePrompt />); - expect(wrapper.text()).toContain('502 Bad Gateway'); - }); - - it('renders a cloud specific error on cloud deployments', () => { - setMockValues({ - ...values, - cloud: { isCloudEnabled: true }, - }); - const wrapper = mountWithIntl(<ErrorStatePrompt />); - - expect(wrapper.find('[data-test-subj="CloudError"]').exists()).toBe(true); - expect(wrapper.find('[data-test-subj="SelfManagedError"]').exists()).toBe(false); - }); - - it('renders a different error if not a cloud deployment', () => { - setMockValues({ - ...values, - cloud: { isCloudEnabled: false }, - }); - const wrapper = mountWithIntl(<ErrorStatePrompt />); - - expect(wrapper.find('[data-test-subj="CloudError"]').exists()).toBe(false); - expect(wrapper.find('[data-test-subj="SelfManagedError"]').exists()).toBe(true); - }); - - describe('chrome visiblity', () => { - it('sets chrome visibility to true when not on personal dashboard route', () => { - mockKibanaValues.history.location.pathname = '/overview'; - mountWithIntl(<ErrorStatePrompt />); - - expect(mockKibanaValues.setChromeIsVisible).toHaveBeenCalledWith(true); - }); - - it('sets chrome visibility to false when on personal dashboard route', () => { - mockKibanaValues.history.location.pathname = '/p/sources'; - mountWithIntl(<ErrorStatePrompt />); - - expect(mockKibanaValues.setChromeIsVisible).toHaveBeenCalledWith(false); - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx deleted file mode 100644 index e744d8d9b125..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/error_state_prompt.tsx +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { useEffect } from 'react'; - -import { useValues } from 'kea'; - -import { EuiEmptyPrompt, EuiCode, EuiLink, EuiCodeBlock, EuiCallOut } from '@elastic/eui'; -import { CloudSetup } from '@kbn/cloud-plugin/public'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n-react'; - -import { HttpLogic } from '../http'; -import { KibanaLogic } from '../kibana'; -import { EuiButtonTo } from '../react_router_helpers'; - -import './error_state_prompt.scss'; - -/** - * Personal dashboard urls begin with /p/ - * EX: http://localhost:5601/app/enterprise_search/workplace_search/p/sources - */ -const WORKPLACE_SEARCH_PERSONAL_DASHBOARD_PATH = '/p/'; - -export const ErrorStatePrompt: React.FC = () => { - const { setChromeIsVisible, history } = useValues(KibanaLogic); - const isWorkplaceSearchPersonalDashboardRoute = history.location.pathname.includes( - WORKPLACE_SEARCH_PERSONAL_DASHBOARD_PATH - ); - - useEffect(() => { - // We hide the Kibana chrome for Workplace Search for Personal Dashboard routes. It is reenabled when the user enters the - // Workplace Search organization admin section of the product. If the Enterprise Search API is not working, we never show - // the chrome and this can have adverse effects when the user leaves thispage and returns to Kibana. To get around this, - // we always show the chrome when the error state is shown, unless the user is visiting the Personal Dashboard. - setChromeIsVisible(!isWorkplaceSearchPersonalDashboardRoute); - }, []); - - return ( - <EuiEmptyPrompt - iconType="warning" - iconColor="danger" - title={ - <h2> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.title" - defaultMessage="Unable to connect" - /> - </h2> - } - titleSize="l" - body={<ErrorBody />} - actions={[ - <EuiButtonTo iconType="help" fill to="/setup_guide"> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.setupGuideCta" - defaultMessage="Review setup guide" - /> - </EuiButtonTo>, - ]} - /> - ); -}; - -export const ErrorStateCallout: React.FC = () => { - return ( - <EuiCallOut - title={i18n.translate('xpack.enterpriseSearch.errorConnectingCallout.title', { - defaultMessage: 'Unable to connect to Enterprise Search', - })} - iconType="warning" - color="warning" - > - <ErrorBody /> - <EuiButtonTo iconType="help" fill to="/setup_guide" color="warning"> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingCallout.setupGuideCta" - defaultMessage="Review setup guide" - /> - </EuiButtonTo> - </EuiCallOut> - ); -}; - -const ErrorBody: React.FC = () => { - const { errorConnectingMessage } = useValues(HttpLogic); - const { config, cloud } = useValues(KibanaLogic); - return ( - <> - <p> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.description1" - defaultMessage="We can’t establish a connection to Enterprise Search at the host URL {enterpriseSearchUrl} due to the following error:" - values={{ - enterpriseSearchUrl: ( - <EuiLink target="_blank" href={config.host} css={{ overflowWrap: 'break-word' }}> - {config.host} - </EuiLink> - ), - }} - /> - </p> - <EuiCodeBlock css={{ textAlign: 'left' }}>{errorConnectingMessage}</EuiCodeBlock> - {cloud?.isCloudEnabled ? cloudError(cloud) : nonCloudError()} - </> - ); -}; - -const cloudError = (cloud: Partial<CloudSetup>) => { - const deploymentUrl = cloud?.deploymentUrl; - return ( - <p data-test-subj="CloudError"> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.cloudErrorMessage" - defaultMessage="Does your Cloud deployment have Enterprise Search nodes running? {deploymentSettingsLink}" - values={{ - deploymentSettingsLink: ( - <EuiLink target="_blank" href={`${deploymentUrl}/edit`}> - {i18n.translate( - 'xpack.enterpriseSearch.errorConnectingState.cloudErrorMessageLinkText', - { - defaultMessage: 'Check your deployment settings', - } - )} - </EuiLink> - ), - }} - /> - </p> - ); -}; - -const nonCloudError = () => { - return ( - <ol className="troubleshootingSteps" data-test-subj="SelfManagedError"> - <li> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.description2" - defaultMessage="Ensure the host URL is configured correctly in {configFile}." - values={{ - configFile: <EuiCode>config/kibana.yml</EuiCode>, - }} - /> - </li> - <li> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.description3" - defaultMessage="Confirm that the Enterprise Search server is responsive." - /> - </li> - <li> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.troubleshootAuth" - defaultMessage="Check your user authentication:" - /> - <ul> - <li> - <FormattedMessage - id="xpack.enterpriseSearch.errorConnectingState.troubleshootAuthMessage" - defaultMessage="Contact your administrator to setup an Enterprise Search role mapping to give you access to Enterprise Search" - /> - </li> - </ul> - </li> - </ol> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index 3305e92dd8d9..a6cbf5669173 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -101,7 +101,7 @@ const baseNavItems = [ items: [ { 'data-test-subj': 'searchSideNav-InferenceEndpoints', - href: '/app/enterprise_search/relevance/inference_endpoints', + href: '/app/elasticsearch/relevance/inference_endpoints', id: 'inference_endpoints', items: undefined, name: 'Inference Endpoints', @@ -205,7 +205,7 @@ const mockNavLinks = [ { id: 'searchInferenceEndpoints:inferenceEndpoints', title: 'Inference Endpoints', - url: '/app/enterprise_search/relevance/inference_endpoints', + url: '/app/elasticsearch/relevance/inference_endpoints', }, { id: 'appSearch:engines', diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts index 862f8d03e9c3..0e9f6ee992d7 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/constants.ts @@ -265,6 +265,16 @@ export const INVITATION_LINK = i18n.translate('xpack.enterpriseSearch.roleMappin defaultMessage: 'Enterprise Search Invitation Link', }); +export const INVITATION_LINK_COPY_ARIA_LABEL = i18n.translate( + 'xpack.enterpriseSearch.roleMapping.copyInvitationLink', + { + defaultMessage: 'Copy {invitationLink}', + values: { + invitationLink: INVITATION_LINK, + }, + } +); + export const NO_USERS_TITLE = i18n.translate('xpack.enterpriseSearch.roleMapping.noUsersTitle', { defaultMessage: 'No user added', }); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_invitation_callout.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_invitation_callout.tsx index d6d0ce7b050a..f5d29974f618 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_invitation_callout.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/role_mapping/user_invitation_callout.tsx @@ -13,6 +13,7 @@ import { INVITATION_DESCRIPTION, NEW_INVITATION_LABEL, EXISTING_INVITATION_LABEL, + INVITATION_LINK_COPY_ARIA_LABEL, INVITATION_LINK, } from './constants'; @@ -35,11 +36,23 @@ export const UserInvitationCallout: React.FC<Props> = ({ isNew, invitationCode, <EuiSpacer size="xs" /> <EuiText size="s">{INVITATION_DESCRIPTION}</EuiText> <EuiSpacer size="xs" /> - <EuiLink href={link} target="_blank" external> + <EuiLink + data-test-subj="enterpriseSearchUserInvitationCalloutLink" + href={link} + target="_blank" + external + > {INVITATION_LINK} </EuiLink>{' '} <EuiCopy textToCopy={link}> - {(copy) => <EuiButtonIcon iconType="copy" onClick={copy} />} + {(copy) => ( + <EuiButtonIcon + data-test-subj="enterpriseSearchUserInvitationCalloutButton" + iconType="copy" + onClick={copy} + aria-label={INVITATION_LINK_COPY_ARIA_LABEL} + /> + )} </EuiCopy> <EuiSpacer /> </> diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/schema/add_field_modal/index.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/schema/add_field_modal/index.tsx index 32191abbbae2..b717de04d21d 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/schema/add_field_modal/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/schema/add_field_modal/index.tsx @@ -22,6 +22,7 @@ import { EuiModalHeader, EuiModalHeaderTitle, EuiSpacer, + useGeneratedHtmlId, } from '@elastic/eui'; import { SchemaFieldTypeSelect } from '..'; @@ -78,10 +79,12 @@ export const SchemaAddFieldModal: React.FC<Props> = ({ ? FIELD_NAME_CORRECTED_NOTE(formattedFieldName) : FIELD_NAME_CORRECT_NOTE; + const modalTitleId = useGeneratedHtmlId(); + return ( - <EuiModal onClose={closeAddFieldModal} maxWidth={500}> + <EuiModal onClose={closeAddFieldModal} maxWidth={500} aria-labelledby={modalTitleId}> <EuiModalHeader> - <EuiModalHeaderTitle>{ADD_FIELD_MODAL_TITLE}</EuiModalHeaderTitle> + <EuiModalHeaderTitle id={modalTitleId}>{ADD_FIELD_MODAL_TITLE}</EuiModalHeaderTitle> </EuiModalHeader> <EuiModalBody> <EuiCallOut @@ -130,7 +133,12 @@ export const SchemaAddFieldModal: React.FC<Props> = ({ </EuiForm> </EuiModalBody> <EuiModalFooter> - <EuiButtonEmpty onClick={closeAddFieldModal}>{CANCEL_BUTTON_LABEL}</EuiButtonEmpty> + <EuiButtonEmpty + data-test-subj="enterpriseSearchSchemaAddFieldModalButton" + onClick={closeAddFieldModal} + > + {CANCEL_BUTTON_LABEL} + </EuiButtonEmpty> <EuiButton fill type="submit" diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx deleted file mode 100644 index f6d5ef4aa421..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { mount } from 'enzyme'; - -import { VersionMismatchError } from './version_mismatch_error'; - -describe('VersionMismatchError', () => { - it('renders', () => { - const wrapper = mount( - <VersionMismatchError kibanaVersion="8.1.0" enterpriseSearchVersion="8.0.0" /> - ); - - expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Enterprise Search version: 8.0.0'); - expect(wrapper.find('EuiEmptyPrompt').text()).toContain('Kibana version: 8.1.0'); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx deleted file mode 100644 index 56915663961d..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_error.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { EuiEmptyPrompt, EuiSpacer } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; - -interface Props { - enterpriseSearchVersion?: string; - kibanaVersion?: string; -} - -export const VersionMismatchError: React.FC<Props> = ({ - enterpriseSearchVersion, - kibanaVersion, -}) => { - return ( - <EuiEmptyPrompt - iconType="warning" - iconColor="danger" - title={ - <h2> - {i18n.translate('xpack.enterpriseSearch.versionMismatch.title', { - defaultMessage: 'Incompatible version error', - })} - </h2> - } - titleSize="l" - body={ - <> - {i18n.translate('xpack.enterpriseSearch.versionMismatch.body', { - defaultMessage: - 'Your Kibana and Enterprise Search versions do not match. To access Enterprise Search, use the same major and minor version for each service.', - })} - <EuiSpacer /> - <div> - {i18n.translate('xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText', { - defaultMessage: 'Enterprise Search version: {enterpriseSearchVersion}', - values: { enterpriseSearchVersion }, - })} - </div> - <div> - {i18n.translate('xpack.enterpriseSearch.versionMismatch.kibanaVersionText', { - defaultMessage: 'Kibana version: {kibanaVersion}', - values: { kibanaVersion }, - })} - </div> - </> - } - /> - ); -}; diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.test.tsx deleted file mode 100644 index d86a1187bd4b..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.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 React from 'react'; - -import { shallow } from 'enzyme'; - -import { VersionMismatchError } from './version_mismatch_error'; -import { VersionMismatchPage } from './version_mismatch_page'; - -describe('VersionMismatchPage', () => { - it('renders', () => { - const wrapper = shallow( - <VersionMismatchPage kibanaVersion="8.1.0" enterpriseSearchVersion="8.0.0" /> - ); - expect(wrapper.find(VersionMismatchError).exists()).toBe(true); - expect(wrapper.find(VersionMismatchError).props()).toEqual({ - kibanaVersion: '8.1.0', - enterpriseSearchVersion: '8.0.0', - }); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx deleted file mode 100644 index 0d730f9dee9e..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/version_mismatch_page.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { VersionMismatchError } from './version_mismatch_error'; - -interface Props { - enterpriseSearchVersion?: string; - kibanaVersion?: string; -} - -export const VersionMismatchPage: React.FC<Props> = (props) => ( - <KibanaPageTemplate isEmptyState> - <VersionMismatchError {...props} /> - </KibanaPageTemplate> -); diff --git a/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx index ce678121253f..2d85725dc552 100644 --- a/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/vector_search/index.tsx @@ -12,29 +12,17 @@ import { Switch } from 'react-router-dom'; import { Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { VectorSearchGuide } from './components/vector_search_guide/vector_search_guide'; import { ROOT_PATH } from './routes'; -export const EnterpriseSearchVectorSearch: React.FC<InitialAppData> = (props) => { - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - +export const EnterpriseSearchVectorSearch: React.FC<InitialAppData> = () => { return ( <Switch> <Route exact path={ROOT_PATH}> - {incompatibleVersions ? ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ) : ( - <VectorSearchGuide /> - )} + <VectorSearchGuide /> </Route> </Switch> ); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx index 677116823912..67b7469fcfe3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.test.tsx @@ -15,12 +15,9 @@ import { Redirect } from 'react-router-dom'; import { shallow } from 'enzyme'; -import { VersionMismatchPage } from '../shared/version_mismatch'; - import { WorkplaceSearchHeaderActions } from './components/layout'; import { SourcesRouter } from './views/content_sources'; import { SourceAdded } from './views/content_sources/components/source_added'; -import { ErrorState } from './views/error_state'; import { NotFound } from './views/not_found'; import { Overview } from './views/overview'; import { RoleMappings } from './views/role_mappings'; @@ -34,14 +31,6 @@ import { } from '.'; describe('WorkplaceSearch', () => { - it('renders VersionMismatchPage when there are mismatching versions', () => { - const wrapper = shallow( - <WorkplaceSearch enterpriseSearchVersion="7.15.0" kibanaVersion="7.16.0" /> - ); - - expect(wrapper.find(VersionMismatchPage)).toHaveLength(1); - }); - it('renders WorkplaceSearchUnconfigured when config.host is not set', () => { setMockValues({ config: { host: '' } }); const wrapper = shallow(<WorkplaceSearch />); @@ -55,26 +44,6 @@ describe('WorkplaceSearch', () => { expect(wrapper.find(WorkplaceSearchConfigured)).toHaveLength(1); }); - - it('renders ErrorState when not on SetupGuide', () => { - mockUseRouteMatch.mockReturnValue(false); - setMockValues({ errorConnectingMessage: '502 Bad Gateway' }); - - const wrapper = shallow(<WorkplaceSearch />); - - const errorState = wrapper.find(ErrorState); - expect(errorState).toHaveLength(1); - }); - - it('does not render ErrorState when on SetupGuide', () => { - mockUseRouteMatch.mockReturnValue(true); - setMockValues({ errorConnectingMessage: '502 Bad Gateway' }); - - const wrapper = shallow(<WorkplaceSearch />); - - const errorState = wrapper.find(ErrorState); - expect(errorState).toHaveLength(0); - }); }); describe('WorkplaceSearchUnconfigured', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx index e9332fe81bda..6233208119c4 100644 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/workplace_search/index.tsx @@ -12,11 +12,8 @@ import { useActions, useValues } from 'kea'; import { Routes, Route } from '@kbn/shared-ux-router'; -import { isVersionMismatch } from '../../../common/is_version_mismatch'; import { InitialAppData } from '../../../common/types'; -import { HttpLogic } from '../shared/http'; import { KibanaLogic } from '../shared/kibana'; -import { VersionMismatchPage } from '../shared/version_mismatch'; import { AppLogic } from './app_logic'; import { WorkplaceSearchHeaderActions } from './components/layout'; @@ -39,7 +36,6 @@ import { AccountSettings } from './views/account_settings'; import { ApiKeys } from './views/api_keys'; import { SourcesRouter } from './views/content_sources'; import { SourceAdded } from './views/content_sources/components/source_added'; -import { ErrorState } from './views/error_state'; import { GroupsRouter } from './views/groups'; import { NotFound } from './views/not_found'; import { OAuthAuthorize } from './views/oauth_authorize'; @@ -52,22 +48,9 @@ import { SetupGuide } from './views/setup_guide'; export const WorkplaceSearch: React.FC<InitialAppData> = (props) => { const { config } = useValues(KibanaLogic); - const { errorConnectingMessage } = useValues(HttpLogic); - const { enterpriseSearchVersion, kibanaVersion } = props; - const incompatibleVersions = isVersionMismatch(enterpriseSearchVersion, kibanaVersion); - const isSetupGuidePath = !!useRouteMatch(SETUP_GUIDE_PATH); if (!config.host) { return <WorkplaceSearchUnconfigured />; - } else if (incompatibleVersions) { - return ( - <VersionMismatchPage - enterpriseSearchVersion={enterpriseSearchVersion} - kibanaVersion={kibanaVersion} - /> - ); - } else if (errorConnectingMessage && !isSetupGuidePath) { - return <ErrorState />; } return <WorkplaceSearchConfigured {...props} />; diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx deleted file mode 100644 index 2c3b49230e39..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.test.tsx +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { shallow } from 'enzyme'; - -import { ErrorStatePrompt } from '../../../shared/error_state'; - -import { ErrorState } from '.'; - -describe('ErrorState', () => { - it('renders', () => { - const wrapper = shallow(<ErrorState />); - - const prompt = wrapper.find(ErrorStatePrompt); - expect(prompt).toHaveLength(1); - }); -}); diff --git a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx b/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx deleted file mode 100644 index fc93896d931f..000000000000 --- a/x-pack/plugins/enterprise_search/public/applications/workplace_search/views/error_state/error_state.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; - -import { WORKPLACE_SEARCH_PLUGIN } from '../../../../../common/constants'; -import { ErrorStatePrompt } from '../../../shared/error_state'; -import { SetWorkplaceSearchChrome as SetPageChrome } from '../../../shared/kibana_chrome'; -import { SendWorkplaceSearchTelemetry as SendTelemetry } from '../../../shared/telemetry'; -import { ViewContentHeader } from '../../components/shared/view_content_header'; - -export const ErrorState: React.FC = () => { - return ( - <> - <SetPageChrome /> - <SendTelemetry action="error" metric="cannot_connect" /> - - <KibanaPageTemplate isEmptyState> - <ViewContentHeader title={WORKPLACE_SEARCH_PLUGIN.NAME} /> - <ErrorStatePrompt /> - </KibanaPageTemplate> - </> - ); -}; diff --git a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts index d9f0eefd0fb5..c8b6c414510f 100644 --- a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts +++ b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_config.ts @@ -7,7 +7,11 @@ import { IScopedClusterClient } from '@kbn/core/server'; -import { Connector, CONNECTORS_INDEX } from '@kbn/search-connectors'; +import { + Connector, + CONNECTORS_INDEX, + MANAGED_CONNECTOR_INDEX_PREFIX, +} from '@kbn/search-connectors'; import { createIndex } from '../indices/create_index'; import { indexOrAliasExists } from '../indices/exists_index'; @@ -20,10 +24,10 @@ export const generateConfig = async (client: IScopedClusterClient, connector: Co if (connector.index_name) { associatedIndex = connector.index_name; } else { - associatedIndex = await generatedIndexName( - client, - connector.name || connector.service_type || 'my-connector' // pass a default name to generate a readable index name rather than gibberish - ); + const indexPrefix = connector.is_native ? MANAGED_CONNECTOR_INDEX_PREFIX : ''; // managed connectors need to be prefixed with `content-` + const connectorReference = connector.name || connector.service_type || 'my-connector'; // pass a default name to generate a readable index name rather than gibberish + + associatedIndex = await generatedIndexName(client, indexPrefix + connectorReference); } if (!indexOrAliasExists(client, associatedIndex)) { diff --git a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts index 56f849c55140..374e32861253 100644 --- a/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts +++ b/x-pack/plugins/enterprise_search/server/lib/connectors/generate_connector_name.ts @@ -9,22 +9,34 @@ import { v4 as uuidv4 } from 'uuid'; import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import { MANAGED_CONNECTOR_INDEX_PREFIX } from '@kbn/search-connectors'; + import { ErrorCode } from '../../../common/types/error_codes'; import { toAlphanumeric } from '../../../common/utils/to_alphanumeric'; import { indexOrAliasExists } from '../indices/exists_index'; +const addIndexPrefix = (indexName: string, isManagedConnector: boolean): string => { + const indexPrefix = isManagedConnector ? MANAGED_CONNECTOR_INDEX_PREFIX : 'connector-'; + return `${indexPrefix}${indexName}`; +}; + +const addConnectorPrefix = (indexName: string): string => { + return `connector-${indexName}`; +}; + export const generateConnectorName = async ( client: IScopedClusterClient, connectorType: string, - userConnectorName?: string + userConnectorName?: string, + isManagedConnector: boolean = false ): Promise<{ apiKeyName: string; connectorName: string; indexName: string }> => { const prefix = toAlphanumeric(connectorType); if (!prefix || prefix.length === 0) { throw new Error('Connector type or connectorName is required'); } if (userConnectorName) { - let indexName = `connector-${userConnectorName}`; + let indexName = addIndexPrefix(userConnectorName, isManagedConnector); const resultSameName = await indexOrAliasExists(client, indexName); // index with same name doesn't exist if (!resultSameName) { @@ -36,12 +48,14 @@ export const generateConnectorName = async ( } // if the index name already exists, we will generate until it doesn't for 20 times for (let i = 0; i < 20; i++) { - indexName = `connector-${userConnectorName}-${uuidv4().split('-')[1].slice(0, 4)}`; + const randomizedConnectorName = `${userConnectorName}-${uuidv4().split('-')[1].slice(0, 4)}`; + + indexName = addIndexPrefix(randomizedConnectorName, isManagedConnector); const result = await indexOrAliasExists(client, indexName); if (!result) { return { - apiKeyName: indexName, + apiKeyName: addConnectorPrefix(randomizedConnectorName), connectorName: userConnectorName, indexName, }; @@ -49,14 +63,15 @@ export const generateConnectorName = async ( } } else { for (let i = 0; i < 20; i++) { - const connectorName = `${prefix}-${uuidv4().split('-')[1].slice(0, 4)}`; - const indexName = `connector-${connectorName}`; + const randomizedConnectorName = `${prefix}-${uuidv4().split('-')[1].slice(0, 4)}`; + const indexName = addIndexPrefix(randomizedConnectorName, isManagedConnector); const result = await indexOrAliasExists(client, indexName); + if (!result) { return { - apiKeyName: indexName, - connectorName, + apiKeyName: addConnectorPrefix(randomizedConnectorName), + connectorName: randomizedConnectorName, indexName, }; } diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts index 610858046389..8a5f96f54edb 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/connectors.ts @@ -842,17 +842,19 @@ export function registerConnectorRoutes({ router, log }: RouteDependencies) { body: schema.object({ connectorName: schema.maybe(schema.string()), connectorType: schema.string(), + isManagedConnector: schema.maybe(schema.boolean()), }), }, }, elasticsearchErrorHandler(log, async (context, request, response) => { const { client } = (await context.core).elasticsearch; - const { connectorType, connectorName } = request.body; + const { connectorType, connectorName, isManagedConnector } = request.body; try { const generatedNames = await generateConnectorName( client, connectorType ?? 'custom', - connectorName + connectorName, + isManagedConnector ); return response.ok({ body: generatedNames, diff --git a/x-pack/plugins/entity_manager/public/lib/entity_client.ts b/x-pack/plugins/entity_manager/public/lib/entity_client.ts index 9db1c37888d4..43530b27df7f 100644 --- a/x-pack/plugins/entity_manager/public/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/public/lib/entity_client.ts @@ -13,8 +13,9 @@ import { isHttpFetchError, } from '@kbn/server-route-repository-client'; import { type KueryNode, nodeTypes, toKqlExpression } from '@kbn/es-query'; -import type { EntityInstance, EntityMetadata } from '@kbn/entities-schema'; +import type { EntityDefinition, EntityInstance, EntityMetadata } from '@kbn/entities-schema'; import { castArray } from 'lodash'; +import type { EntityDefinitionWithState } from '../../server/lib/entities/types'; import { DisableManagedEntityResponse, EnableManagedEntityResponse, @@ -87,6 +88,24 @@ export class EntityClient { } } + async getEntityDefinition( + id: string + ): Promise<{ definitions: EntityDefinition[] | EntityDefinitionWithState[] }> { + try { + return await this.repositoryClient('GET /internal/entities/definition/{id?}', { + params: { + path: { id }, + query: { page: 1, perPage: 1 }, + }, + }); + } catch (err) { + if (isHttpFetchError(err) && err.body?.statusCode === 403) { + throw new EntityManagerUnauthorizedError(err.body.message); + } + throw err; + } + } + asKqlFilter( entityInstance: { entity: Pick<EntityInstance['entity'], 'identity_fields'>; diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/cron_job.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/cron_job.ts index 7849dcdc73f5..06bc9dba9fce 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/cron_job.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/cron_job.ts @@ -13,7 +13,7 @@ import { commonEcsMetadata } from '../common/ecs_metadata'; export const builtInKubernetesCronJobEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_cron_job_ecs`, - filter: 'kubernetes.cronjob.uid : *', + filter: 'kubernetes.cronjob.name : *', managed: true, version: '0.1.0', name: 'Kubernetes CronJob from ECS data', @@ -21,7 +21,7 @@ export const builtInKubernetesCronJobEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes cron job entities from the Kubernetes integration data streams', type: 'k8s.cronjob.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.cronjob.uid'], + identityFields: ['kubernetes.cronjob.name'], displayNameTemplate: '{{kubernetes.cronjob.name}}', latest: { timestampField: '@timestamp', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/daemon_set.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/daemon_set.ts index 5b57cdd6ae2f..c69a1c5c7e62 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/daemon_set.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/daemon_set.ts @@ -13,7 +13,7 @@ import { commonEcsMetadata } from '../common/ecs_metadata'; export const builtInKubernetesDaemonSetEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_daemon_set_ecs`, - filter: 'kubernetes.daemonset.uid : *', + filter: 'kubernetes.daemonset.name : *', managed: true, version: '0.1.0', name: 'Kubernetes DaemonSet from ECS data', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/deployment.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/deployment.ts index d33c14db7e2c..f8e8f920e2f4 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/deployment.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/deployment.ts @@ -13,7 +13,7 @@ import { commonEcsIndexPatterns } from '../common/ecs_index_patterns'; export const builtInKubernetesDeploymentEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_deployment_ecs`, - filter: 'kubernetes.deployment.uid : *', + filter: 'kubernetes.deployment.name : *', managed: true, version: '0.1.0', name: 'Kubernetes Deployment from ECS data', @@ -21,7 +21,7 @@ export const builtInKubernetesDeploymentEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes deployment entities from the Kubernetes integration data streams', type: 'k8s.deployment.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.deployment.uid'], + identityFields: ['kubernetes.deployment.name'], displayNameTemplate: '{{kubernetes.deployment.name}}', latest: { timestampField: '@timestamp', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/job.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/job.ts index 92c6d1325155..4efc41dc9ea8 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/job.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/job.ts @@ -13,7 +13,7 @@ import { commonEcsMetadata } from '../common/ecs_metadata'; export const builtInKubernetesJobEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_job_ecs`, - filter: 'kubernetes.job.uid : *', + filter: 'kubernetes.job.name : *', managed: true, version: '0.1.0', name: 'Kubernetes Job from ECS data', @@ -21,7 +21,7 @@ export const builtInKubernetesJobEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes job entities from the Kubernetes integration data streams', type: 'k8s.job.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.job.uid'], + identityFields: ['kubernetes.job.name'], displayNameTemplate: '{{kubernetes.job.name}}', latest: { timestampField: '@timestamp', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/node.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/node.ts index f3fdcdfaf04b..033bd8313928 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/node.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/node.ts @@ -13,7 +13,7 @@ import { commonEcsMetadata } from '../common/ecs_metadata'; export const builtInKubernetesNodeEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_node_ecs`, - filer: 'kubernetes.node.uid : *', + filer: 'kubernetes.node.name : *', managed: true, version: '0.1.0', name: 'Kubernetes Node from ECS data', @@ -21,7 +21,7 @@ export const builtInKubernetesNodeEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes node entities from the Kubernetes integration data streams', type: 'k8s.node.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.node.uid'], + identityFields: ['kubernetes.node.name'], displayNameTemplate: '{{kubernetes.node.name}}', latest: { timestampField: '@timestamp', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/pod.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/pod.ts index 7aa53da6e5a7..32029617d992 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/pod.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/pod.ts @@ -21,7 +21,7 @@ export const builtInKubernetesPodEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes pod entities from the Kubernetes integration data streams', type: 'k8s.pod.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.pod.name'], + identityFields: ['kubernetes.pod.uid'], displayNameTemplate: '{{kubernetes.pod.name}}', latest: { timestampField: '@timestamp', @@ -30,5 +30,12 @@ export const builtInKubernetesPodEcsEntityDefinition: EntityDefinition = frequency: '5m', }, }, - metadata: commonEcsMetadata, + metadata: [ + ...commonEcsMetadata, + { + source: 'kubernetes.pod.name', + destination: 'kubernetes.pod.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/replica_set.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/replica_set.ts index cc059c14979d..e9f534be8f1d 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/replica_set.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/replica_set.ts @@ -13,6 +13,7 @@ import { commonEcsIndexPatterns } from '../common/ecs_index_patterns'; export const builtInKubernetesReplicaSetEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_replica_set_ecs`, + filer: 'kubernetes.replicaset.name : *', managed: true, version: '0.1.0', name: 'Kubernetes ReplicaSet from ECS data', @@ -20,7 +21,7 @@ export const builtInKubernetesReplicaSetEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes replica set entities from the Kubernetes integration data streams', type: 'k8s.replicaset.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.replicaset.uid'], + identityFields: ['kubernetes.replicaset.name'], displayNameTemplate: '{{kubernetes.replicaset.name}}', latest: { timestampField: '@timestamp', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/stateful_set.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/stateful_set.ts index 79f9d4489216..927c8a259276 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/stateful_set.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/ecs/stateful_set.ts @@ -13,7 +13,7 @@ import { commonEcsIndexPatterns } from '../common/ecs_index_patterns'; export const builtInKubernetesStatefulSetEcsEntityDefinition: EntityDefinition = entityDefinitionSchema.parse({ id: `${BUILT_IN_ID_PREFIX}kubernetes_stateful_set_ecs`, - filter: 'kubernetes.statefulset.uid : *', + filter: 'kubernetes.statefulset.name : *', managed: true, version: '0.1.0', name: 'Kubernetes StatefulSet from ECS data', @@ -21,7 +21,7 @@ export const builtInKubernetesStatefulSetEcsEntityDefinition: EntityDefinition = 'This definition extracts Kubernetes stateful set entities from the Kubernetes integration data streams', type: 'k8s.statefulset.ecs', indexPatterns: commonEcsIndexPatterns, - identityFields: ['kubernetes.statefulset.uid'], + identityFields: ['kubernetes.statefulset.name'], displayNameTemplate: '{{kubernetes.statefulset.name}}', latest: { timestampField: '@timestamp', diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cluster.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cluster.ts index 0ec244ec617f..71024cfb166f 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cluster.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cluster.ts @@ -30,5 +30,12 @@ export const builtInKubernetesClusterSemConvEntityDefinition: EntityDefinition = frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.cluster.name', + destination: 'k8s.cluster.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cron_job.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cron_job.ts index 6d677943976d..fff257bcf8e5 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cron_job.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/cron_job.ts @@ -30,5 +30,12 @@ export const builtInKubernetesCronJobSemConvEntityDefinition: EntityDefinition = frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.cronjob.name', + destination: 'k8s.cronjob.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/daemon_set.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/daemon_set.ts index a4b61933ad31..cf89dcc30e67 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/daemon_set.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/daemon_set.ts @@ -30,5 +30,12 @@ export const builtInKubernetesDaemonSetSemConvEntityDefinition: EntityDefinition frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.daemonset.name', + destination: 'k8s.daemonset.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/deployment.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/deployment.ts index bdb3cb1cef59..05a89d67ead3 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/deployment.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/deployment.ts @@ -30,5 +30,12 @@ export const builtInKubernetesDeploymentSemConvEntityDefinition: EntityDefinitio frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.deployment.name', + destination: 'k8s.deployment.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/job.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/job.ts index b2e48cf7494f..557afa54ca55 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/job.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/job.ts @@ -30,5 +30,12 @@ export const builtInKubernetesJobSemConvEntityDefinition: EntityDefinition = frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.job.name', + destination: 'k8s.job.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/node.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/node.ts index 456f03042107..35bbed42e6a4 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/node.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/node.ts @@ -22,7 +22,7 @@ export const builtInKubernetesNodeSemConvEntityDefinition: EntityDefinition = type: 'k8s.node.otel', indexPatterns: commonOtelIndexPatterns, identityFields: ['k8s.node.uid'], - displayNameTemplate: '{{k8s.node.uid}}', + displayNameTemplate: '{{k8s.node.name}}', latest: { timestampField: '@timestamp', lookbackPeriod: '10m', @@ -30,5 +30,12 @@ export const builtInKubernetesNodeSemConvEntityDefinition: EntityDefinition = frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.node.name', + destination: 'k8s.node.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/pod.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/pod.ts index 6dc879d761dd..05d22163fbac 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/pod.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/pod.ts @@ -30,5 +30,12 @@ export const builtInKubernetesPodSemConvEntityDefinition: EntityDefinition = frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.pod.name', + destination: 'k8s.pod.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/replica_set.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/replica_set.ts index 47bad6bf8a64..ff4e33d789da 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/replica_set.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/replica_set.ts @@ -19,9 +19,9 @@ export const builtInKubernetesReplicaSetSemConvEntityDefinition: EntityDefinitio name: 'Kubernetes ReplicaSet from SemConv data', description: 'This definition extracts Kubernetes replica set entities using data collected with OpenTelemetry', - type: 'kubernetes_replica_set_semconv', + type: 'k8s.replicaset.otel', indexPatterns: commonOtelIndexPatterns, - identityFields: ['k8s.replicaset.name'], + identityFields: ['k8s.replicaset.uid'], displayNameTemplate: '{{k8s.replicaset.name}}', latest: { timestampField: '@timestamp', @@ -30,5 +30,12 @@ export const builtInKubernetesReplicaSetSemConvEntityDefinition: EntityDefinitio frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.replicaset.name', + destination: 'k8s.replicaset.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/stateful_set.ts b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/stateful_set.ts index c61d7e5d965c..9c8b385f05c7 100644 --- a/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/stateful_set.ts +++ b/x-pack/plugins/entity_manager/server/lib/entities/built_in/kubernetes/semconv/stateful_set.ts @@ -30,5 +30,12 @@ export const builtInKubernetesStatefulSetSemConvEntityDefinition: EntityDefiniti frequency: '5m', }, }, - metadata: commonOtelMetadata, + metadata: [ + ...commonOtelMetadata, + { + source: 'k8s.statefulset.name', + destination: 'k8s.statefulset.name', + aggregation: { type: 'top_value', sort: { '@timestamp': 'desc' } }, + }, + ], }); diff --git a/x-pack/plugins/entity_manager/server/lib/entity_client.ts b/x-pack/plugins/entity_manager/server/lib/entity_client.ts index 7045bee1fc53..35abe63c5fd2 100644 --- a/x-pack/plugins/entity_manager/server/lib/entity_client.ts +++ b/x-pack/plugins/entity_manager/server/lib/entity_client.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { without } from 'lodash'; import { EntityV2, EntityDefinition, EntityDefinitionUpdate } from '@kbn/entities-schema'; import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; @@ -23,10 +24,27 @@ import { stopTransforms } from './entities/stop_transforms'; import { deleteIndices } from './entities/delete_index'; import { EntityDefinitionWithState } from './entities/types'; import { EntityDefinitionUpdateConflict } from './entities/errors/entity_definition_update_conflict'; -import { EntitySource, getEntityInstancesQuery } from './queries'; +import { EntitySource, SortBy, getEntityInstancesQuery } from './queries'; import { mergeEntitiesList, runESQLQuery } from './queries/utils'; import { UnknownEntityType } from './entities/errors/unknown_entity_type'; +interface SearchCommon { + start: string; + end: string; + sort?: SortBy; + metadataFields?: string[]; + filters?: string[]; + limit?: number; +} + +export type SearchByType = SearchCommon & { + type: string; +}; + +export type SearchBySources = SearchCommon & { + sources: EntitySource[]; +}; + export class EntityClient { constructor( private options: { @@ -191,17 +209,11 @@ export class EntityClient { type, start, end, + sort, metadataFields = [], filters = [], limit = 10, - }: { - type: string; - start: string; - end: string; - metadataFields?: string[]; - filters?: string[]; - limit?: number; - }) { + }: SearchByType) { const sources = await this.getEntitySources({ type }); if (sources.length === 0) { throw new UnknownEntityType(`No sources found for entity type [${type}]`); @@ -213,6 +225,7 @@ export class EntityClient { end, metadataFields, filters, + sort, limit, }); } @@ -221,21 +234,22 @@ export class EntityClient { sources, start, end, + sort, metadataFields = [], filters = [], limit = 10, - }: { - sources: EntitySource[]; - start: string; - end: string; - metadataFields?: string[]; - filters?: string[]; - limit?: number; - }) { + }: SearchBySources) { const entities = await Promise.all( sources.map(async (source) => { - const mandatoryFields = [source.timestamp_field, ...source.identity_fields]; + const mandatoryFields = [ + ...source.identity_fields, + ...(source.timestamp_field ? [source.timestamp_field] : []), + ...(source.display_name ? [source.display_name] : []), + ]; const metaFields = [...metadataFields, ...source.metadata_fields]; + + // operations on an unmapped field result in a failing query so we verify + // field capabilities beforehand const { fields } = await this.options.esClient.fieldCaps({ index: source.index_patterns, fields: [...mandatoryFields, ...metaFields], @@ -244,15 +258,25 @@ export class EntityClient { const sourceHasMandatoryFields = mandatoryFields.every((field) => !!fields[field]); if (!sourceHasMandatoryFields) { // we can't build entities without id fields so we ignore the source. - // filters should likely behave similarly. + // TODO filters should likely behave similarly. we should also throw + const missingFields = mandatoryFields.filter((field) => !fields[field]); this.options.logger.info( - `Ignoring source for type [${source.type}] with index_patterns [${source.index_patterns}] because some mandatory fields [${mandatoryFields}] are not mapped` + `Ignoring source for type [${source.type}] with index_patterns [${ + source.index_patterns + }] because some mandatory fields [${missingFields.join(', ')}] are not mapped` ); return []; } // but metadata field not being available is fine const availableMetadataFields = metaFields.filter((field) => fields[field]); + if (availableMetadataFields.length < metaFields.length) { + this.options.logger.info( + `Ignoring unmapped fields [${without(metaFields, ...availableMetadataFields).join( + ', ' + )}]` + ); + } const query = getEntityInstancesQuery({ source: { @@ -262,6 +286,7 @@ export class EntityClient { }, start, end, + sort, limit, }); this.options.logger.debug(`Entity query: ${query}`); @@ -271,14 +296,10 @@ export class EntityClient { esClient: this.options.esClient, }); - return rawEntities.map((entity) => { - entity['entity.id'] = source.identity_fields.map((field) => entity[field]).join(':'); - entity['entity.type'] = source.type; - return entity; - }); + return rawEntities; }) ).then((results) => results.flat()); - return mergeEntitiesList(entities).slice(0, limit); + return mergeEntitiesList(sources, entities).slice(0, limit); } } diff --git a/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts b/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts index 539d20c46479..d8b3c9347cdd 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/index.test.ts @@ -18,19 +18,21 @@ describe('getEntityInstancesQuery', () => { metadata_fields: ['host.name'], filters: [], timestamp_field: 'custom_timestamp_field', + display_name: 'service.id', }, limit: 5, start: '2024-11-20T19:00:00.000Z', end: '2024-11-20T20:00:00.000Z', + sort: { field: 'entity.id', direction: 'DESC' }, }); expect(query).toEqual( - 'FROM logs-*,metrics-*|' + - 'WHERE custom_timestamp_field >= "2024-11-20T19:00:00.000Z"|' + - 'WHERE custom_timestamp_field <= "2024-11-20T20:00:00.000Z"|' + - 'WHERE service.name IS NOT NULL|' + - 'STATS entity.last_seen_timestamp=MAX(custom_timestamp_field),metadata.host.name=VALUES(host.name) BY service.name|' + - 'SORT entity.last_seen_timestamp DESC|' + + 'FROM logs-*, metrics-* | ' + + 'WHERE service.name IS NOT NULL | ' + + 'WHERE custom_timestamp_field >= "2024-11-20T19:00:00.000Z" AND custom_timestamp_field <= "2024-11-20T20:00:00.000Z" | ' + + 'STATS host.name = VALUES(host.name), entity.last_seen_timestamp = MAX(custom_timestamp_field), service.id = MAX(service.id) BY service.name | ' + + 'EVAL entity.type = "service", entity.id = service.name, entity.display_name = COALESCE(service.id, entity.id) | ' + + 'SORT entity.id DESC | ' + 'LIMIT 5' ); }); diff --git a/x-pack/plugins/entity_manager/server/lib/queries/index.ts b/x-pack/plugins/entity_manager/server/lib/queries/index.ts index 9fc7ae00c9aa..83c25d756c17 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/index.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/index.ts @@ -9,29 +9,35 @@ import { z } from '@kbn/zod'; export const entitySourceSchema = z.object({ type: z.string(), - timestamp_field: z.optional(z.string()).default('@timestamp'), + timestamp_field: z.optional(z.string()), index_patterns: z.array(z.string()), identity_fields: z.array(z.string()), metadata_fields: z.array(z.string()), filters: z.array(z.string()), + display_name: z.optional(z.string()), }); +export interface SortBy { + field: string; + direction: 'ASC' | 'DESC'; +} + export type EntitySource = z.infer<typeof entitySourceSchema>; const sourceCommand = ({ source }: { source: EntitySource }) => { - let query = `FROM ${source.index_patterns}`; + let query = `FROM ${source.index_patterns.join(', ')}`; const esMetadataFields = source.metadata_fields.filter((field) => ['_index', '_id'].includes(field) ); if (esMetadataFields.length) { - query += ` METADATA ${esMetadataFields.join(',')}`; + query += ` METADATA ${esMetadataFields.join(', ')}`; } return query; }; -const filterCommands = ({ +const whereCommand = ({ source, start, end, @@ -40,32 +46,65 @@ const filterCommands = ({ start: string; end: string; }) => { - const commands = [ - `WHERE ${source.timestamp_field} >= "${start}"`, - `WHERE ${source.timestamp_field} <= "${end}"`, + const filters = [ + source.identity_fields.map((field) => `${field} IS NOT NULL`).join(' AND '), + ...source.filters, ]; - source.identity_fields.forEach((field) => { - commands.push(`WHERE ${field} IS NOT NULL`); - }); - - source.filters.forEach((filter) => { - commands.push(`WHERE ${filter}`); - }); + if (source.timestamp_field) { + filters.push( + `${source.timestamp_field} >= "${start}" AND ${source.timestamp_field} <= "${end}"` + ); + } - return commands; + return filters.map((filter) => `WHERE ${filter}`).join(' | '); }; const statsCommand = ({ source }: { source: EntitySource }) => { - const aggs = [ - // default 'last_seen' attribute - `entity.last_seen_timestamp=MAX(${source.timestamp_field})`, - ...source.metadata_fields - .filter((field) => !source.identity_fields.some((idField) => idField === field)) - .map((field) => `metadata.${field}=VALUES(${field})`), - ]; + const aggs = source.metadata_fields + .filter((field) => !source.identity_fields.some((idField) => idField === field)) + .map((field) => `${field} = VALUES(${field})`); + + if (source.timestamp_field) { + aggs.push(`entity.last_seen_timestamp = MAX(${source.timestamp_field})`); + } + + if (source.display_name) { + // ideally we want the latest value but there's no command yet + // so we use MAX for now + aggs.push(`${source.display_name} = MAX(${source.display_name})`); + } + + return `STATS ${aggs.join(', ')} BY ${source.identity_fields.join(', ')}`; +}; + +const evalCommand = ({ source }: { source: EntitySource }) => { + const id = + source.identity_fields.length === 1 + ? source.identity_fields[0] + : `CONCAT(${source.identity_fields.join(', ":", ')})`; + + const displayName = source.display_name + ? `COALESCE(${source.display_name}, entity.id)` + : 'entity.id'; + + return `EVAL ${[ + `entity.type = "${source.type}"`, + `entity.id = ${id}`, + `entity.display_name = ${displayName}`, + ].join(', ')}`; +}; + +const sortCommand = ({ source, sort }: { source: EntitySource; sort?: SortBy }) => { + if (sort) { + return `SORT ${sort.field} ${sort.direction}`; + } + + if (source.timestamp_field) { + return `SORT entity.last_seen_timestamp DESC`; + } - return `STATS ${aggs.join(',')} BY ${source.identity_fields.join(',')}`; + return `SORT entity.id ASC`; }; export function getEntityInstancesQuery({ @@ -73,19 +112,22 @@ export function getEntityInstancesQuery({ limit, start, end, + sort, }: { source: EntitySource; limit: number; start: string; end: string; + sort?: SortBy; }): string { const commands = [ sourceCommand({ source }), - ...filterCommands({ source, start, end }), + whereCommand({ source, start, end }), statsCommand({ source }), - `SORT entity.last_seen_timestamp DESC`, + evalCommand({ source }), + sortCommand({ source, sort }), `LIMIT ${limit}`, ]; - return commands.join('|'); + return commands.join(' | '); } diff --git a/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts b/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts index 5d5702567172..df5c8a2a4a82 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/utils.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { EntitySource } from '.'; import { mergeEntitiesList } from './utils'; describe('mergeEntitiesList', () => { @@ -15,20 +16,23 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', + 'entity.display_name': 'foo', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', + 'entity.display_name': 'foo', }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList([], entities); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', + 'entity.display_name': 'foo', }); }); @@ -38,33 +42,46 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-1', - 'metadata.agent.name': 'agent-1', - 'metadata.service.environment': ['dev', 'staging'], - 'metadata.only_in_record_1': 'foo', + 'entity.display_name': 'foo', + 'host.name': 'host-1', + 'agent.name': 'agent-1', + 'service.environment': ['dev', 'staging'], + only_in_record_1: 'foo', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-2', 'host-3'], - 'metadata.agent.name': 'agent-2', - 'metadata.service.environment': 'prod', - 'metadata.only_in_record_2': 'bar', + 'entity.display_name': 'foo', + 'host.name': ['host-2', 'host-3'], + 'agent.name': 'agent-2', + 'service.environment': 'prod', + only_in_record_2: 'bar', }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList( + [ + { + metadata_fields: ['host.name', 'agent.name', 'service.environment', 'only_in_record_1'], + }, + { + metadata_fields: ['host.name', 'agent.name', 'service.environment', 'only_in_record_2'], + }, + ] as EntitySource[], + entities + ); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2', 'host-3'], - 'metadata.agent.name': ['agent-1', 'agent-2'], - 'metadata.service.environment': ['dev', 'staging', 'prod'], - 'metadata.only_in_record_1': 'foo', - 'metadata.only_in_record_2': 'bar', + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2', 'host-3'], + 'agent.name': ['agent-1', 'agent-2'], + 'service.environment': ['dev', 'staging', 'prod'], + only_in_record_1: 'foo', + only_in_record_2: 'bar', }); }); @@ -74,29 +91,78 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-1', + 'entity.display_name': 'foo', + 'host.name': 'host-1', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-2', + 'entity.display_name': 'foo', + 'host.name': 'host-2', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T16:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-3', + 'entity.display_name': 'foo', + 'host.name': 'host-3', + }, + { + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': 'host-3', }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList( + [ + { + metadata_fields: ['host.name'], + }, + { + metadata_fields: ['host.name'], + }, + ] as EntitySource[], + entities + ); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2', 'host-3'], + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2', 'host-3'], + }); + }); + + it('works without entity.last_seen_timestamp', () => { + const entities = [ + { + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': 'host-1', + }, + { + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': 'host-2', + }, + ]; + + const mergedEntities = mergeEntitiesList( + [{ metadata_fields: ['host.name'] }, { metadata_fields: ['host.name'] }] as EntitySource[], + entities + ); + expect(mergedEntities.length).toEqual(1); + expect(mergedEntities[0]).toEqual({ + 'entity.id': 'foo', + 'entity.type': 'service', + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2'], }); }); @@ -106,29 +172,43 @@ describe('mergeEntitiesList', () => { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T18:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-1', + 'entity.display_name': 'foo', + 'host.name': 'host-1', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': 'host-2', + 'entity.display_name': 'foo', + 'host.name': 'host-2', }, { 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T16:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2'], + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2'], }, ]; - const mergedEntities = mergeEntitiesList(entities); + const mergedEntities = mergeEntitiesList( + [ + { + metadata_fields: ['host.name'], + }, + { + metadata_fields: ['host.name'], + }, + ] as EntitySource[], + entities + ); expect(mergedEntities.length).toEqual(1); expect(mergedEntities[0]).toEqual({ 'entity.id': 'foo', 'entity.last_seen_timestamp': '2024-11-20T20:00:00.000Z', 'entity.type': 'service', - 'metadata.host.name': ['host-1', 'host-2'], + 'entity.display_name': 'foo', + 'host.name': ['host-1', 'host-2'], }); }); }); diff --git a/x-pack/plugins/entity_manager/server/lib/queries/utils.ts b/x-pack/plugins/entity_manager/server/lib/queries/utils.ts index 68f5b0f11aff..a18f6fb83714 100644 --- a/x-pack/plugins/entity_manager/server/lib/queries/utils.ts +++ b/x-pack/plugins/entity_manager/server/lib/queries/utils.ts @@ -5,24 +5,33 @@ * 2.0. */ +import { compact, uniq } from 'lodash'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; import { EntityV2 } from '@kbn/entities-schema'; import { ESQLSearchResponse } from '@kbn/es-types'; -import { uniq } from 'lodash'; - -function mergeEntities(entity1: EntityV2, entity2: EntityV2): EntityV2 { - const merged: EntityV2 = { - ...entity1, - 'entity.last_seen_timestamp': new Date( - Math.max( - Date.parse(entity1['entity.last_seen_timestamp']), - Date.parse(entity2['entity.last_seen_timestamp']) - ) - ).toISOString(), - }; +import { EntitySource } from '.'; + +function getLatestDate(date1?: string, date2?: string) { + if (!date1 && !date2) return; + + return new Date( + Math.max(date1 ? Date.parse(date1) : 0, date2 ? Date.parse(date2) : 0) + ).toISOString(); +} + +function mergeEntities(metadataFields: string[], entity1: EntityV2, entity2: EntityV2): EntityV2 { + const merged: EntityV2 = { ...entity1 }; + + const latestTimestamp = getLatestDate( + entity1['entity.last_seen_timestamp'], + entity2['entity.last_seen_timestamp'] + ); + if (latestTimestamp) { + merged['entity.last_seen_timestamp'] = latestTimestamp; + } for (const [key, value] of Object.entries(entity2).filter(([_key]) => - _key.startsWith('metadata.') + metadataFields.includes(_key) )) { if (merged[key]) { merged[key] = uniq([ @@ -36,7 +45,10 @@ function mergeEntities(entity1: EntityV2, entity2: EntityV2): EntityV2 { return merged; } -export function mergeEntitiesList(entities: EntityV2[]): EntityV2[] { +export function mergeEntitiesList(sources: EntitySource[], entities: EntityV2[]): EntityV2[] { + const metadataFields = uniq( + sources.flatMap((source) => compact([source.timestamp_field, ...source.metadata_fields])) + ); const instances: { [key: string]: EntityV2 } = {}; for (let i = 0; i < entities.length; i++) { @@ -44,7 +56,7 @@ export function mergeEntitiesList(entities: EntityV2[]): EntityV2[] { const id = entity['entity.id']; if (instances[id]) { - instances[id] = mergeEntities(instances[id], entity); + instances[id] = mergeEntities(metadataFields, instances[id], entity); } else { instances[id] = entity; } diff --git a/x-pack/plugins/entity_manager/server/routes/enablement/check.ts b/x-pack/plugins/entity_manager/server/routes/enablement/check.ts index 5373ac9df50f..100b0ac382dc 100644 --- a/x-pack/plugins/entity_manager/server/routes/enablement/check.ts +++ b/x-pack/plugins/entity_manager/server/routes/enablement/check.ts @@ -45,13 +45,11 @@ import { createEntityManagerServerRoute } from '../create_entity_manager_server_ */ export const checkEntityDiscoveryEnabledRoute = createEntityManagerServerRoute({ endpoint: 'GET /internal/entities/managed/enablement', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint leverages the security plugin to evaluate the privileges needed as part of its core flow', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint leverages the security plugin to evaluate the privileges needed as part of its core flow', }, }, handler: async ({ response, logger, server }) => { diff --git a/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts b/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts index a71a317045c4..1c8755c682f7 100644 --- a/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts +++ b/x-pack/plugins/entity_manager/server/routes/enablement/disable.ts @@ -44,13 +44,11 @@ import { createEntityManagerServerRoute } from '../create_entity_manager_server_ */ export const disableEntityDiscoveryRoute = createEntityManagerServerRoute({ endpoint: 'DELETE /internal/entities/managed/enablement', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint leverages the security plugin to evaluate the privileges needed as part of its core flow', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint leverages the security plugin to evaluate the privileges needed as part of its core flow', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts b/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts index 562b798a598a..6ddb65804b90 100644 --- a/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts +++ b/x-pack/plugins/entity_manager/server/routes/enablement/enable.ts @@ -63,13 +63,11 @@ import { startTransforms } from '../../lib/entities/start_transforms'; */ export const enableEntityDiscoveryRoute = createEntityManagerServerRoute({ endpoint: 'PUT /internal/entities/managed/enablement', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint leverages the security plugin to evaluate the privileges needed as part of its core flow', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint leverages the security plugin to evaluate the privileges needed as part of its core flow', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/entities/create.ts b/x-pack/plugins/entity_manager/server/routes/entities/create.ts index a22916f3e69f..fc0f4c6e9a1e 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/create.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/create.ts @@ -50,13 +50,11 @@ import { canManageEntityDefinition } from '../../lib/auth'; */ export const createEntityDefinitionRoute = createEntityManagerServerRoute({ endpoint: 'POST /internal/entities/definition', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/entities/delete.ts b/x-pack/plugins/entity_manager/server/routes/entities/delete.ts index ff5b9624dbb3..ec5b4ada3039 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/delete.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/delete.ts @@ -52,13 +52,11 @@ import { canDeleteEntityDefinition } from '../../lib/auth/privileges'; */ export const deleteEntityDefinitionRoute = createEntityManagerServerRoute({ endpoint: 'DELETE /internal/entities/definition/{id}', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/entities/get.ts b/x-pack/plugins/entity_manager/server/routes/entities/get.ts index f22e0890e60a..738ed0f44064 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/get.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/get.ts @@ -50,13 +50,11 @@ import { createEntityManagerServerRoute } from '../create_entity_manager_server_ */ export const getEntityDefinitionRoute = createEntityManagerServerRoute({ endpoint: 'GET /internal/entities/definition/{id?}', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/entities/reset.ts b/x-pack/plugins/entity_manager/server/routes/entities/reset.ts index ab4ba29fa148..5da7a608aed8 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/reset.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/reset.ts @@ -25,13 +25,11 @@ import { stopTransforms } from '../../lib/entities/stop_transforms'; export const resetEntityDefinitionRoute = createEntityManagerServerRoute({ endpoint: 'POST /internal/entities/definition/{id}/_reset', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/entities/update.ts b/x-pack/plugins/entity_manager/server/routes/entities/update.ts index f1118028cda9..4f23486375f9 100644 --- a/x-pack/plugins/entity_manager/server/routes/entities/update.ts +++ b/x-pack/plugins/entity_manager/server/routes/entities/update.ts @@ -54,13 +54,11 @@ import { canManageEntityDefinition } from '../../lib/auth'; */ export const updateEntityDefinitionRoute = createEntityManagerServerRoute({ endpoint: 'PATCH /internal/entities/definition/{id}', - options: { - security: { - authz: { - enabled: false, - reason: - 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', - }, + security: { + authz: { + enabled: false, + reason: + 'This endpoint mainly manages Elasticsearch resources using the requesting users credentials', }, }, params: z.object({ diff --git a/x-pack/plugins/entity_manager/server/routes/v2/search.ts b/x-pack/plugins/entity_manager/server/routes/v2/search.ts index 0b975da748a8..451ff7cfff43 100644 --- a/x-pack/plugins/entity_manager/server/routes/v2/search.ts +++ b/x-pack/plugins/entity_manager/server/routes/v2/search.ts @@ -22,20 +22,34 @@ export const searchEntitiesRoute = createEntityManagerServerRoute({ .optional(z.string()) .default(() => moment().subtract(5, 'minutes').toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[start] should be a date in ISO format', }), end: z .optional(z.string()) .default(() => moment().toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[end] should be a date in ISO format', }), + sort: z.optional( + z.object({ + field: z.string(), + direction: z.enum(['ASC', 'DESC']), + }) + ), limit: z.optional(z.number()).default(10), }), }), handler: async ({ request, response, params, logger, getScopedClient }) => { try { - const { type, start, end, limit, filters, metadata_fields: metadataFields } = params.body; + const { + type, + start, + end, + limit, + filters, + sort, + metadata_fields: metadataFields, + } = params.body; const client = await getScopedClient({ request }); const entities = await client.searchEntities({ @@ -44,6 +58,7 @@ export const searchEntitiesRoute = createEntityManagerServerRoute({ metadataFields, start, end, + sort, limit, }); @@ -69,25 +84,32 @@ export const searchEntitiesPreviewRoute = createEntityManagerServerRoute({ .optional(z.string()) .default(() => moment().subtract(5, 'minutes').toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[start] should be a date in ISO format', }), end: z .optional(z.string()) .default(() => moment().toISOString()) .refine((val) => moment(val).isValid(), { - message: 'start should be a date in ISO format', + message: '[end] should be a date in ISO format', }), + sort: z.optional( + z.object({ + field: z.string(), + direction: z.enum(['ASC', 'DESC']), + }) + ), limit: z.optional(z.number()).default(10), }), }), - handler: async ({ request, response, params, logger, getScopedClient }) => { - const { sources, start, end, limit } = params.body; + handler: async ({ request, response, params, getScopedClient }) => { + const { sources, start, end, limit, sort } = params.body; const client = await getScopedClient({ request }); const entities = await client.searchEntitiesBySources({ sources, start, end, + sort, limit, }); diff --git a/x-pack/plugins/features/common/alerting_kibana_privilege.ts b/x-pack/plugins/features/common/alerting_kibana_privilege.ts new file mode 100644 index 000000000000..4a435b5c651c --- /dev/null +++ b/x-pack/plugins/features/common/alerting_kibana_privilege.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Interface for registering an alerting privilege. + * Alerting privilege registration allows plugins to + * specify for which rule types and consumers the feature + * has access to. + */ + +export type AlertingKibanaPrivilege = ReadonlyArray<{ + ruleTypeId: string; + consumers: readonly string[]; +}>; diff --git a/x-pack/plugins/features/common/feature_kibana_privileges.ts b/x-pack/plugins/features/common/feature_kibana_privileges.ts index 1939d0b5e4e4..a7d39669ef00 100644 --- a/x-pack/plugins/features/common/feature_kibana_privileges.ts +++ b/x-pack/plugins/features/common/feature_kibana_privileges.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { AlertingKibanaPrivilege } from './alerting_kibana_privilege'; import { FeatureKibanaPrivilegesReference } from './feature_kibana_privileges_reference'; /** @@ -97,47 +98,47 @@ export interface FeatureKibanaPrivileges { alerting?: { rule?: { /** - * List of rule types which users should have full read/write access to when granted this privilege. + * List of rule types and consumers for which users should have full read/write access to when granted this privilege. * @example * ```ts * { - * all: ['my-alert-type-within-my-feature'] + * all: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - all?: readonly string[]; + all?: AlertingKibanaPrivilege; /** - * List of rule types which users should have read-only access to when granted this privilege. + * List of rule types and consumers for which users should have read-only access to when granted this privilege. * @example * ```ts * { - * read: ['my-alert-type'] + * read: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - read?: readonly string[]; + read?: AlertingKibanaPrivilege; }; alert?: { /** - * List of rule types for which users should have full read/write access their alert data to when granted this privilege. + * List of rule types and consumers for which users should have full read/write access their alert data to when granted this privilege. * @example * ```ts * { - * all: ['my-alert-type-within-my-feature'] + * all: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - all?: readonly string[]; + all?: AlertingKibanaPrivilege; /** - * List of rule types for which users should have read-only access to their alert data when granted this privilege. + * List of rule types and consumers for which users should have read-only access to their alert data when granted this privilege. * @example * ```ts * { - * read: ['my-alert-type'] + * read: [{ ruleTypeId: 'my-alert-type-within-my-feature', consumers: ['my-consumer-within-my-feature'] }] * } * ``` */ - read?: readonly string[]; + read?: AlertingKibanaPrivilege; }; }; diff --git a/x-pack/plugins/features/common/kibana_feature.ts b/x-pack/plugins/features/common/kibana_feature.ts index 3a5d9fc2a0e5..dba79a1663fc 100644 --- a/x-pack/plugins/features/common/kibana_feature.ts +++ b/x-pack/plugins/features/common/kibana_feature.ts @@ -11,6 +11,7 @@ import { LicenseType } from '@kbn/licensing-plugin/common/types'; import { FeatureKibanaPrivileges } from './feature_kibana_privileges'; import { SubFeatureConfig, SubFeature as KibanaSubFeature } from './sub_feature'; import { ReservedKibanaPrivilege } from './reserved_kibana_privilege'; +import { AlertingKibanaPrivilege } from './alerting_kibana_privilege'; /** * Enum for allowed feature scope values. @@ -107,11 +108,12 @@ export interface KibanaFeatureConfig { catalogue?: readonly string[]; /** - * If your feature grants access to specific Alert Types, you can specify them here to control visibility based on the current space. - * Include both Alert Types registered by the feature and external Alert Types such as built-in - * Alert Types and Alert Types provided by other features to which you wish to grant access. + * If your feature grants access to specific rule types, you can specify them here to control visibility based on the current space. + * Include both rule types registered by the feature and external rule types such as built-in + * rule types and rule types provided by other features to which you wish to grant access. For each rule type + * you can specify the consumers the feature has access to. */ - alerting?: readonly string[]; + alerting?: AlertingKibanaPrivilege; /** * If your feature grants access to specific case types, you can specify them here to control visibility based on the current space. diff --git a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap index b8df9e9c2117..b5614562f18a 100644 --- a/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap +++ b/x-pack/plugins/features/server/__snapshots__/oss_features.test.ts.snap @@ -881,6 +881,9 @@ exports[`buildOSSFeatures with a basic license returns the indexPatterns feature Array [ Object { "privilege": Object { + "api": Array [ + "indexPatterns:manage", + ], "app": Array [ "kibana", ], @@ -1520,6 +1523,9 @@ exports[`buildOSSFeatures with a enterprise license returns the indexPatterns fe Array [ Object { "privilege": Object { + "api": Array [ + "indexPatterns:manage", + ], "app": Array [ "kibana", ], diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts index c7d501bb17cf..c4e542a7ebcd 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.test.ts @@ -62,11 +62,11 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, }, @@ -96,10 +96,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -134,11 +134,11 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, }, @@ -171,10 +171,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -205,12 +205,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], - read: ['alerting-read-type-alerts'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type-alerts', consumers: ['foo'] }], }, }, cases: { @@ -239,10 +239,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -278,12 +278,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-type'], - read: ['alerting-read-type-alerts'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type-alerts', consumers: ['foo'] }], }, }, cases: { @@ -323,10 +323,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -355,10 +355,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -390,7 +390,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -436,10 +436,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -471,10 +471,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -506,10 +506,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -538,10 +538,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -573,7 +573,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -619,10 +619,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -654,10 +654,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -689,10 +689,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -721,10 +721,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -757,7 +757,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -804,12 +804,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, alert: { - all: ['alerting-all-sub-type'], - read: ['alerting-another-read-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -843,11 +843,11 @@ describe('featurePrivilegeIterator', () => { alerting: { rule: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -887,12 +887,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -921,10 +921,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -956,7 +956,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -994,12 +994,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-read-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1032,11 +1032,11 @@ describe('featurePrivilegeIterator', () => { alerting: { rule: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - all: ['alerting-read-type'], - read: ['alerting-read-type'], + all: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1076,10 +1076,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1108,10 +1108,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1144,7 +1144,7 @@ describe('featurePrivilegeIterator', () => { }, alerting: { alert: { - all: ['alerting-all-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -1191,12 +1191,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, alert: { - all: ['alerting-all-sub-type'], - read: ['alerting-another-read-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1228,10 +1228,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1390,8 +1390,8 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-sub-type', consumers: ['foo'] }], }, }, cases: { @@ -1438,8 +1438,8 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-sub-type', consumers: ['foo'] }], }, alert: { all: [], @@ -1476,8 +1476,8 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-sub-type'], - read: ['alerting-read-sub-type'], + all: [{ ruleTypeId: 'alerting-all-sub-type', consumers: ['foo'] }], + read: [{ ruleTypeId: 'alerting-read-sub-type', consumers: ['foo'] }], }, alert: { all: [], @@ -1521,10 +1521,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1553,10 +1553,10 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1612,12 +1612,12 @@ describe('featurePrivilegeIterator', () => { }, alerting: { rule: { - all: ['alerting-all-type'], + all: [{ ruleTypeId: 'alerting-all-type', consumers: ['foo'] }], read: [], }, alert: { all: [], - read: ['alerting-another-read-type'], + read: [{ ruleTypeId: 'alerting-another-read-type', consumers: ['foo'] }], }, }, cases: { @@ -1650,11 +1650,11 @@ describe('featurePrivilegeIterator', () => { alerting: { rule: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, alert: { all: [], - read: ['alerting-read-type'], + read: [{ ruleTypeId: 'alerting-read-type', consumers: ['foo'] }], }, }, cases: { diff --git a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts index a9d7336ea0a2..45518004430a 100644 --- a/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts +++ b/x-pack/plugins/features/server/feature_privilege_iterator/feature_privilege_iterator.ts @@ -8,6 +8,7 @@ import _ from 'lodash'; import type { LicenseType } from '@kbn/licensing-plugin/server'; +import { AlertingKibanaPrivilege } from '../../common/alerting_kibana_privilege'; import type { FeatureKibanaPrivileges, KibanaFeature } from '..'; import { subFeaturePrivilegeIterator } from './sub_feature_privilege_iterator'; @@ -108,26 +109,46 @@ function mergeWithSubFeatures( subFeaturePrivilege.savedObject.read ); + /** + * Merges all alerting rule types and consumers + * from features and sub features. + * Removes duplicated values. + */ + const mergeAlertingEntries = (entries: AlertingKibanaPrivilege): AlertingKibanaPrivilege => { + const alertingMap = new Map<string, Set<string>>(); + + for (const entry of entries) { + const consumers = alertingMap.get(entry.ruleTypeId) ?? new Set(); + entry.consumers.forEach((consumer) => consumers.add(consumer)); + alertingMap.set(entry.ruleTypeId, consumers); + } + + return Array.from(alertingMap).map(([ruleTypeId, consumers]) => ({ + ruleTypeId, + consumers: Array.from(consumers), + })); + }; + mergedConfig.alerting = { rule: { - all: mergeArrays( - mergedConfig.alerting?.rule?.all ?? [], - subFeaturePrivilege.alerting?.rule?.all ?? [] - ), - read: mergeArrays( - mergedConfig.alerting?.rule?.read ?? [], - subFeaturePrivilege.alerting?.rule?.read ?? [] - ), + all: mergeAlertingEntries([ + ...(mergedConfig.alerting?.rule?.all ?? []), + ...(subFeaturePrivilege.alerting?.rule?.all ?? []), + ]), + read: mergeAlertingEntries([ + ...(mergedConfig.alerting?.rule?.read ?? []), + ...(subFeaturePrivilege.alerting?.rule?.read ?? []), + ]), }, alert: { - all: mergeArrays( - mergedConfig.alerting?.alert?.all ?? [], - subFeaturePrivilege.alerting?.alert?.all ?? [] - ), - read: mergeArrays( - mergedConfig.alerting?.alert?.read ?? [], - subFeaturePrivilege.alerting?.alert?.read ?? [] - ), + all: mergeAlertingEntries([ + ...(mergedConfig.alerting?.alert?.all ?? []), + ...(subFeaturePrivilege.alerting?.alert?.all ?? []), + ]), + read: mergeAlertingEntries([ + ...(mergedConfig.alerting?.alert?.read ?? []), + ...(subFeaturePrivilege.alerting?.alert?.read ?? []), + ]), }, }; diff --git a/x-pack/plugins/features/server/feature_registry.test.ts b/x-pack/plugins/features/server/feature_registry.test.ts index 08da08e0a19b..9ed7a207560b 100644 --- a/x-pack/plugins/features/server/feature_registry.test.ts +++ b/x-pack/plugins/features/server/feature_registry.test.ts @@ -868,404 +868,688 @@ describe('FeatureRegistry', () => { ); }); - it(`prevents privileges from specifying alerting/rule entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: { - all: { - alerting: { - rule: { - all: ['foo', 'bar'], - read: ['baz'], + describe('alerting', () => { + it(`prevents privileges from specifying rule types that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: { + all: { + alerting: { + rule: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], + read: [{ ruleTypeId: 'baz', consumers: ['test-feature'] }], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], - }, - read: { - alerting: { - rule: { - read: ['foo', 'bar', 'baz'], + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + rule: { + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.all has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all has unknown ruleTypeId: foo"` + ); + }); - it(`prevents privileges from specifying alerting/alert entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: { - all: { - alerting: { - alert: { - all: ['foo', 'bar'], - read: ['baz'], + it(`prevents privileges from specifying rule types entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: { + all: { + alerting: { + alert: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], + read: [{ ruleTypeId: 'baz', consumers: ['test-feature'] }], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], - }, - read: { - alerting: { - alert: { - read: ['foo', 'bar', 'baz'], + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + alert: { + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.all has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all has unknown ruleTypeId: foo"` + ); + }); - it(`prevents features from specifying alerting/rule entries that don't exist at the privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: { - all: { - alerting: { - rule: { - all: ['foo'], + it(`prevents features from specifying rule types that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: { + all: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - read: { - alerting: { - rule: { - all: ['foo'], + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], + }, + ui: [], + alerting: { + rule: { + all: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + }, + ], + }, + ], + }, + ], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); + + it(`prevents features from specifying rule types entries that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: { + all: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + read: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - subFeatures: [ - { - name: 'my sub feature', - privilegeGroups: [ - { - groupType: 'independent', - privileges: [ - { - id: 'cool-sub-feature-privilege', - name: 'cool privilege', - includeIn: 'none', - savedObject: { - all: [], - read: [], - }, - ui: [], - alerting: { - rule: { - all: ['bar'], + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], }, + ui: [], + alerting: { + alert: { + all: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + }, + }, + }, + ], + }, + ], + }, + ], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); + + it(`prevents reserved privileges from specifying rule types that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], }, }, - ], + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, ], }, - ], - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved has unknown ruleTypeId: foo"` + ); + }); - it(`prevents features from specifying alerting/alert entries that don't exist at the privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: { - all: { - alerting: { - alert: { - all: ['foo'], + it(`prevents reserved privileges from specifying rule types entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + alert: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], + ], }, - read: { - alerting: { - alert: { - all: ['foo'], + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved has unknown ruleTypeId: foo"` + ); + }); + + it(`prevents features from specifying rule types that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, - }, - savedObject: { - all: [], - read: [], - }, - ui: [], - app: [], + ], }, - }, - subFeatures: [ - { - name: 'my sub feature', - privilegeGroups: [ + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); + + it(`prevents features from specifying rule types entries that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + { ruleTypeId: 'baz', consumers: ['test-feature'] }, + ], + privileges: null, + reserved: { + description: 'something', + privileges: [ { - groupType: 'independent', - privileges: [ - { - id: 'cool-sub-feature-privilege', - name: 'cool privilege', - includeIn: 'none', - savedObject: { - all: [], - read: [], - }, - ui: [], - alerting: { - alert: { - all: ['bar'], - }, + id: 'reserved', + privilege: { + alerting: { + alert: { + all: [ + { ruleTypeId: 'foo', consumers: ['test-feature'] }, + { ruleTypeId: 'bar', consumers: ['test-feature'] }, + ], }, }, - ], + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, }, ], }, - ], - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting rule types which are not granted to any privileges: baz"` + ); + }); - it(`prevents reserved privileges from specifying alerting/rule entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - rule: { - all: ['foo', 'bar', 'baz'], - }, + it(`prevents privileges from specifying rule types without consumers`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'foo', consumers: [] }], + privileges: { + all: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: [] }], }, - savedObject: { - all: [], - read: [], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + rule: { + read: [{ ruleTypeId: 'foo', consumers: [] }], }, - ui: [], - app: [], }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ], - }, - }; + }, + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.reserved has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"[alerting.0.consumers]: array size is [0], but cannot be smaller than [1]"` + ); + }); - it(`prevents reserved privileges from specifying alerting/alert entries that don't exist at the root level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['bar'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - alert: { - all: ['foo', 'bar', 'baz'], - }, + it(`prevents privileges from specifying consumers entries that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: { + all: { + alerting: { + rule: { + all: [{ ruleTypeId: 'bar', consumers: ['not-exist'] }], + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], }, - savedObject: { - all: [], - read: [], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + rule: { + read: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], }, - ui: [], - app: [], }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ], - }, - }; + }, + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature privilege test-feature.reserved has unknown alerting entries: foo, baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.all.bar has unknown consumer: not-exist"` + ); + }); - it(`prevents features from specifying alerting/rule entries that don't exist at the reserved privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - rule: { - all: ['foo', 'bar'], - }, + it(`prevents features from specifying consumers that don't exist at the privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'foo', consumers: ['test-feature', 'should-exist', 'foo'] }], + privileges: { + all: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], }, - savedObject: { - all: [], - read: [], + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + read: { + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], }, - ui: [], - app: [], }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], + }, + }, + subFeatures: [ + { + name: 'my sub feature', + privilegeGroups: [ + { + groupType: 'independent', + privileges: [ + { + id: 'cool-sub-feature-privilege', + name: 'cool privilege', + includeIn: 'none', + savedObject: { + all: [], + read: [], + }, + ui: [], + alerting: { + alert: { + all: [{ ruleTypeId: 'foo', consumers: ['foo'] }], + }, + }, + }, + ], + }, + ], }, ], - }, - }; + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); - }); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting consumers which are not granted to any privileges: should-exist"` + ); + }); - it(`prevents features from specifying alerting/alert entries that don't exist at the reserved privilege level`, () => { - const feature: KibanaFeatureConfig = { - id: 'test-feature', - name: 'Test Feature', - app: [], - category: { id: 'foo', label: 'foo' }, - alerting: ['foo', 'bar', 'baz'], - privileges: null, - reserved: { - description: 'something', - privileges: [ - { - id: 'reserved', - privilege: { - alerting: { - alert: { - all: ['foo', 'bar'], + it(`prevents reserved privileges from specifying consumers that don't exist at the root level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'bar', consumers: ['test-feature'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [{ ruleTypeId: 'bar', consumers: ['not-exist'] }], + }, + }, + savedObject: { + all: [], + read: [], }, + ui: [], + app: [], }, - savedObject: { - all: [], - read: [], + }, + ], + }, + }; + + const featureRegistry = new FeatureRegistry(); + + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature privilege test-feature.reserved.bar has unknown consumer: not-exist"` + ); + }); + + it(`prevents features from specifying consumers that don't exist at the reserved privilege level`, () => { + const feature: KibanaFeatureConfig = { + id: 'test-feature', + name: 'Test Feature', + app: [], + category: { id: 'foo', label: 'foo' }, + alerting: [{ ruleTypeId: 'foo', consumers: ['test-feature', 'should-exist'] }], + privileges: null, + reserved: { + description: 'something', + privileges: [ + { + id: 'reserved', + privilege: { + alerting: { + rule: { + all: [{ ruleTypeId: 'foo', consumers: ['test-feature'] }], + }, + }, + savedObject: { + all: [], + read: [], + }, + ui: [], + app: [], }, - ui: [], - app: [], }, - }, - ], - }, - }; + ], + }, + }; - const featureRegistry = new FeatureRegistry(); + const featureRegistry = new FeatureRegistry(); - expect(() => - featureRegistry.registerKibanaFeature(feature) - ).toThrowErrorMatchingInlineSnapshot( - `"Feature test-feature specifies alerting entries which are not granted to any privileges: baz"` - ); + expect(() => + featureRegistry.registerKibanaFeature(feature) + ).toThrowErrorMatchingInlineSnapshot( + `"Feature test-feature specifies alerting consumers which are not granted to any privileges: should-exist"` + ); + }); }); it(`prevents privileges from specifying cases entries that don't exist at the root level`, () => { @@ -2068,11 +2352,15 @@ describe('FeatureRegistry', () => { all: { ui: [], savedObject: { all: [], read: [] }, - alerting: { alert: { all: ['one'] } }, + alerting: { + alert: { + all: [{ ruleTypeId: 'one', consumers: ['featureE'] }], + }, + }, }, read: { ui: [], savedObject: { all: [], read: [] } }, }, - alerting: ['one'], + alerting: [{ ruleTypeId: 'one', consumers: ['featureE'] }], }, ]; features.forEach((f) => registry.registerKibanaFeature(f)); diff --git a/x-pack/plugins/features/server/feature_schema.ts b/x-pack/plugins/features/server/feature_schema.ts index ce444c41e477..3923eb31dbec 100644 --- a/x-pack/plugins/features/server/feature_schema.ts +++ b/x-pack/plugins/features/server/feature_schema.ts @@ -11,6 +11,7 @@ import { difference } from 'lodash'; import { Capabilities as UICapabilities } from '@kbn/core/server'; import { KibanaFeatureConfig, KibanaFeatureScope } from '../common'; import { FeatureKibanaPrivileges, ElasticsearchFeatureConfig } from '.'; +import { AlertingKibanaPrivilege } from '../common/alerting_kibana_privilege'; // Each feature gets its own property on the UICapabilities object, // but that object has a few built-in properties which should not be overwritten. @@ -63,7 +64,13 @@ const managementSchema = schema.recordOf( listOfCapabilitiesSchema ); const catalogueSchema = listOfCapabilitiesSchema; -const alertingSchema = schema.arrayOf(schema.string()); +const alertingSchema = schema.arrayOf( + schema.object({ + ruleTypeId: schema.string(), + consumers: schema.arrayOf(schema.string(), { minSize: 1 }), + }) +); + const casesSchema = schema.arrayOf(schema.string()); const appCategorySchema = schema.object({ @@ -331,7 +338,14 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { const unseenCatalogue = new Set(catalogue); - const unseenAlertTypes = new Set(alerting); + const alertingMap = new Map( + alerting.map(({ ruleTypeId, consumers }) => [ruleTypeId, new Set(consumers)]) + ); + + const unseenAlertingRyleTypeIds = new Set(alertingMap.keys()); + const unseenAlertingConsumers = new Set( + alerting.flatMap(({ consumers }) => Array.from(consumers.values())) + ); const unseenCasesTypes = new Set(cases); @@ -362,20 +376,40 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { } function validateAlertingEntry(privilegeId: string, entry: FeatureKibanaPrivileges['alerting']) { - const all: string[] = [...(entry?.rule?.all ?? []), ...(entry?.alert?.all ?? [])]; - const read: string[] = [...(entry?.rule?.read ?? []), ...(entry?.alert?.read ?? [])]; + const seenRuleTypeIds = new Set<string>(); + const seenConsumers = new Set<string>(); + + const validateAlertingPrivilege = (alertingPrivilege?: AlertingKibanaPrivilege) => { + for (const { ruleTypeId, consumers } of alertingPrivilege ?? []) { + if (!alertingMap.has(ruleTypeId)) { + throw new Error( + `Feature privilege ${feature.id}.${privilegeId} has unknown ruleTypeId: ${ruleTypeId}` + ); + } + + const alertingMapConsumers = alertingMap.get(ruleTypeId)!; + + for (const consumer of consumers) { + if (!alertingMapConsumers.has(consumer)) { + throw new Error( + `Feature privilege ${feature.id}.${privilegeId}.${ruleTypeId} has unknown consumer: ${consumer}` + ); + } - all.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); - read.forEach((privilegeAlertTypes) => unseenAlertTypes.delete(privilegeAlertTypes)); + seenConsumers.add(consumer); + } - const unknownAlertingEntries = difference([...all, ...read], alerting); - if (unknownAlertingEntries.length > 0) { - throw new Error( - `Feature privilege ${ - feature.id - }.${privilegeId} has unknown alerting entries: ${unknownAlertingEntries.join(', ')}` - ); - } + seenRuleTypeIds.add(ruleTypeId); + } + }; + + validateAlertingPrivilege(entry?.rule?.all); + validateAlertingPrivilege(entry?.rule?.read); + validateAlertingPrivilege(entry?.alert?.all); + validateAlertingPrivilege(entry?.alert?.read); + + seenRuleTypeIds.forEach((ruleTypeId: string) => unseenAlertingRyleTypeIds.delete(ruleTypeId)); + seenConsumers.forEach((consumer: string) => unseenAlertingConsumers.delete(consumer)); } function validateCasesEntry(privilegeId: string, entry: FeatureKibanaPrivileges['cases']) { @@ -510,12 +544,22 @@ export function validateKibanaFeature(feature: KibanaFeatureConfig) { ); } - if (unseenAlertTypes.size > 0) { + if (unseenAlertingRyleTypeIds.size > 0) { + throw new Error( + `Feature ${ + feature.id + } specifies alerting rule types which are not granted to any privileges: ${Array.from( + unseenAlertingRyleTypeIds.keys() + ).join(',')}` + ); + } + + if (unseenAlertingConsumers.size > 0) { throw new Error( `Feature ${ feature.id - } specifies alerting entries which are not granted to any privileges: ${Array.from( - unseenAlertTypes.values() + } specifies alerting consumers which are not granted to any privileges: ${Array.from( + unseenAlertingConsumers.keys() ).join(',')}` ); } diff --git a/x-pack/plugins/features/server/oss_features.ts b/x-pack/plugins/features/server/oss_features.ts index 19001fe19547..0f243e7e6bda 100644 --- a/x-pack/plugins/features/server/oss_features.ts +++ b/x-pack/plugins/features/server/oss_features.ts @@ -401,6 +401,7 @@ export const buildOSSFeatures = ({ read: [], }, ui: ['save'], + api: ['indexPatterns:manage'], }, read: { app: ['kibana'], diff --git a/x-pack/plugins/fields_metadata/public/hooks/use_fields_metadata/use_fields_metadata.test.ts b/x-pack/plugins/fields_metadata/public/hooks/use_fields_metadata/use_fields_metadata.test.ts index eaae7c5542c0..8f69c11a1043 100644 --- a/x-pack/plugins/fields_metadata/public/hooks/use_fields_metadata/use_fields_metadata.test.ts +++ b/x-pack/plugins/fields_metadata/public/hooks/use_fields_metadata/use_fields_metadata.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { createUseFieldsMetadataHook, UseFieldsMetadataParams } from './use_fields_metadata'; import { FindFieldsMetadataResponsePayload } from '../../../common/latest'; @@ -46,12 +46,12 @@ describe('useFieldsMetadata', () => { it('should return the fieldsMetadata value from the API', async () => { fieldsMetadataClient.find.mockResolvedValue(mockedFieldsMetadataResponse); - const { result, waitForNextUpdate } = renderHook(() => useFieldsMetadata()); + const { result } = renderHook(() => useFieldsMetadata()); expect(result.current.loading).toBe(true); expect(result.current.fieldsMetadata).toEqual(undefined); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { fieldsMetadata, loading, error } = result.current; expect(fieldsMetadata).toEqual(fields); @@ -68,21 +68,17 @@ describe('useFieldsMetadata', () => { dataset: 'dataset_name', }; - const { waitForNextUpdate } = renderHook(() => useFieldsMetadata(params)); + renderHook(() => useFieldsMetadata(params)); - await waitForNextUpdate(); - - expect(fieldsMetadataClient.find).toHaveBeenCalledWith(params); + await waitFor(() => expect(fieldsMetadataClient.find).toHaveBeenCalledWith(params)); }); it('should return an error if the API call fails', async () => { const error = new Error('Fetch fields metadata Failed'); fieldsMetadataClient.find.mockRejectedValueOnce(error); - const { result, waitForNextUpdate } = renderHook(() => useFieldsMetadata()); - - await waitForNextUpdate(); + const { result } = renderHook(() => useFieldsMetadata()); - expect(result.current.error?.message).toMatch(error.message); + await waitFor(() => expect(result.current.error?.message).toMatch(error.message)); }); }); diff --git a/x-pack/plugins/fleet/common/constants/agent_policy.ts b/x-pack/plugins/fleet/common/constants/agent_policy.ts index b89577ed7c36..c3baf3b6e175 100644 --- a/x-pack/plugins/fleet/common/constants/agent_policy.ts +++ b/x-pack/plugins/fleet/common/constants/agent_policy.ts @@ -38,7 +38,5 @@ export const LICENSE_FOR_SCHEDULE_UPGRADE = 'platinum'; export const DEFAULT_MAX_AGENT_POLICIES_WITH_INACTIVITY_TIMEOUT = 750; -export const AGENTLESS_POLICY_ID = 'agentless'; // the policy id defined here: https://github.com/elastic/project-controller/blob/main/internal/project/security/security_kibana_config.go#L86 - export const AGENT_LOG_LEVELS = ['error', 'warning', 'info', 'debug'] as const; export const DEFAULT_LOG_LEVEL = 'info' as const; diff --git a/x-pack/plugins/fleet/common/constants/index.ts b/x-pack/plugins/fleet/common/constants/index.ts index 8ebfe005960c..f51e85f22c52 100644 --- a/x-pack/plugins/fleet/common/constants/index.ts +++ b/x-pack/plugins/fleet/common/constants/index.ts @@ -25,6 +25,7 @@ export * from './message_signing_keys'; export * from './locators'; export * from './secrets'; export * from './uninstall_token'; +export * from './space_awareness'; // TODO: This is the default `index.max_result_window` ES setting, which dictates // the maximum amount of results allowed to be returned from a search. It's possible diff --git a/x-pack/plugins/fleet/common/constants/mappings.ts b/x-pack/plugins/fleet/common/constants/mappings.ts index 6499da7f86cc..f3d2b200cac5 100644 --- a/x-pack/plugins/fleet/common/constants/mappings.ts +++ b/x-pack/plugins/fleet/common/constants/mappings.ts @@ -72,6 +72,7 @@ export const PACKAGE_POLICIES_MAPPINGS = { properties: {}, }, secret_references: { properties: { id: { type: 'keyword' } } }, + supports_agentless: { type: 'boolean' }, revision: { type: 'integer' }, updated_at: { type: 'date' }, updated_by: { type: 'keyword' }, diff --git a/x-pack/plugins/fleet/common/constants/space_awareness.ts b/x-pack/plugins/fleet/common/constants/space_awareness.ts new file mode 100644 index 000000000000..c89d0f4cddb0 --- /dev/null +++ b/x-pack/plugins/fleet/common/constants/space_awareness.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * The identifier in a saved object's `namespaces` array when it is shared to an unknown space (e.g., one that the end user is not authorized to see). + */ +export const UNKNOWN_SPACE = '?'; diff --git a/x-pack/plugins/fleet/common/experimental_features.ts b/x-pack/plugins/fleet/common/experimental_features.ts index 730bcb393e98..07fd2caf0f06 100644 --- a/x-pack/plugins/fleet/common/experimental_features.ts +++ b/x-pack/plugins/fleet/common/experimental_features.ts @@ -21,7 +21,6 @@ const _allowedExperimentalValues = { kafkaOutput: true, outputSecretsStorage: true, remoteESOutput: true, - agentless: false, enableStrictKQLValidation: true, subfeaturePrivileges: false, advancedPolicySettings: true, diff --git a/x-pack/plugins/fleet/common/services/__snapshots__/simplified_package_policy_helper.test.ts.snap b/x-pack/plugins/fleet/common/services/__snapshots__/simplified_package_policy_helper.test.ts.snap index 7c549b030a33..f2d4067be434 100644 --- a/x-pack/plugins/fleet/common/services/__snapshots__/simplified_package_policy_helper.test.ts.snap +++ b/x-pack/plugins/fleet/common/services/__snapshots__/simplified_package_policy_helper.test.ts.snap @@ -238,6 +238,7 @@ Object { "policy_ids": Array [ "policy123", ], + "supports_agentless": undefined, "vars": undefined, } `; diff --git a/x-pack/plugins/fleet/common/services/agent_status.test.ts b/x-pack/plugins/fleet/common/services/agent_status.test.ts new file mode 100644 index 000000000000..5c64e2d023dd --- /dev/null +++ b/x-pack/plugins/fleet/common/services/agent_status.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Agent } from '../types'; + +import { isStuckInUpdating } from './agent_status'; + +describe('isStuckInUpdating', () => { + it('should return true if agent is active and in failed upgrade state', () => { + const agent = { + active: true, + status: 'online', + upgrade_details: { + state: 'UPG_FAILED', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(true); + }); + + it('should return false if agent is active and in watching upgrade state', () => { + const agent = { + active: true, + status: 'online', + upgrade_details: { + state: 'UPG_WATCHING', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return false if agent is active and in rollback upgrade state', () => { + const agent = { + active: true, + status: 'online', + upgrade_details: { + state: 'UPG_ROLLBACK', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return false if agent is updating and in schedule upgrade state', () => { + const agent = { + active: true, + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + upgrade_details: { + state: 'UPG_SCHEDULED', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return false if agent is updating and in downloading upgrade state', () => { + const agent = { + active: true, + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + upgrade_details: { + state: 'UPG_DOWNLOADING', + }, + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(false); + }); + + it('should return true if agent is updating no upgrade details state', () => { + const agent = { + active: true, + status: 'updating', + upgrade_started_at: '2022-11-21T12:27:24Z', + } as Agent; + + expect(isStuckInUpdating(agent)).toBe(true); + }); +}); diff --git a/x-pack/plugins/fleet/common/services/agent_status.ts b/x-pack/plugins/fleet/common/services/agent_status.ts index 78726667f3b1..42b586d7552a 100644 --- a/x-pack/plugins/fleet/common/services/agent_status.ts +++ b/x-pack/plugins/fleet/common/services/agent_status.ts @@ -60,13 +60,15 @@ export function buildKueryForInactiveAgents() { export const AGENT_UPDATING_TIMEOUT_HOURS = 2; export function isStuckInUpdating(agent: Agent): boolean { + const hasTimedOut = (upgradeStartedAt: string) => + Date.now() - Date.parse(upgradeStartedAt) > AGENT_UPDATING_TIMEOUT_HOURS * 60 * 60 * 1000; return ( (agent.status !== 'offline' && agent.active && isAgentInFailedUpgradeState(agent)) || (agent.status === 'updating' && !!agent.upgrade_started_at && !agent.upgraded_at && - Date.now() - Date.parse(agent.upgrade_started_at) > - AGENT_UPDATING_TIMEOUT_HOURS * 60 * 60 * 1000) + hasTimedOut(agent.upgrade_started_at) && + !agent.upgrade_details?.state) ); } diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts index 0918fcaa08d7..8f96c3ffc197 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.test.ts @@ -469,6 +469,45 @@ describe('Fleet - packageToPackagePolicy', () => { }); }); + it('returns package policy with inputs variables', () => { + const mockPackageWithPolicyTemplates = { + ...mockPackage, + policy_templates: [ + { inputs: [{ type: 'foo' }] }, + { inputs: [{ type: 'bar', vars: [{ default: 'bar-var-value', name: 'var-name' }] }] }, + ], + } as unknown as PackageInfo; + + expect( + packageToPackagePolicy( + mockPackageWithPolicyTemplates, + 'policy-id-1', + 'default', + 'pkgPolicy-1' + ) + ).toEqual({ + policy_id: 'policy-id-1', + policy_ids: ['policy-id-1'], + namespace: 'default', + enabled: true, + inputs: [ + { type: 'foo', enabled: true, streams: [] }, + { + type: 'bar', + enabled: true, + streams: [], + vars: { 'var-name': { value: 'bar-var-value' } }, + }, + ], + name: 'pkgPolicy-1', + package: { + name: 'mock-package', + title: 'Mock package', + version: '0.0.0', + }, + }); + }); + it('returns package policy with multiple policy templates (aka has integrations', () => { expect( packageToPackagePolicy( diff --git a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts index a830cfd90300..6aed76b0a115 100644 --- a/x-pack/plugins/fleet/common/services/package_to_package_policy.ts +++ b/x-pack/plugins/fleet/common/services/package_to_package_policy.ts @@ -147,9 +147,7 @@ export const packageToPackagePolicyInputs = ( return stream; }); - // If non-integration package, collect input-level vars, otherwise skip them, - // we do not support input-level vars for packages with integrations yet) - if (packageInput.vars?.length && !hasIntegrations) { + if (packageInput.vars?.length) { varsForInput = packageInput.vars.reduce(varsReducer, {}); } diff --git a/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts b/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts index 14c7b3888f77..5e39f9495948 100644 --- a/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts +++ b/x-pack/plugins/fleet/common/services/simplified_package_policy_helper.ts @@ -49,6 +49,7 @@ export interface SimplifiedPackagePolicy { description?: string; vars?: SimplifiedVars; inputs?: SimplifiedInputs; + supports_agentless?: boolean | null; } export interface FormattedPackagePolicy extends Omit<PackagePolicy, 'inputs' | 'vars'> { @@ -154,18 +155,19 @@ export function simplifiedPackagePolicytoNewPackagePolicy( description, inputs = {}, vars: packageLevelVars, + supports_agentless: supportsAgentless, } = data; - const packagePolicy = packageToPackagePolicy( - packageInfo, - policyId && isEmpty(policyIds) ? policyId : policyIds, - namespace, - name, - description - ); - - if (outputId) { - packagePolicy.output_id = outputId; - } + const packagePolicy = { + ...packageToPackagePolicy( + packageInfo, + policyId && isEmpty(policyIds) ? policyId : policyIds, + namespace, + name, + description + ), + supports_agentless: supportsAgentless, + output_id: outputId, + }; if (packagePolicy.package && options?.experimental_data_stream_features) { packagePolicy.package.experimental_data_stream_features = diff --git a/x-pack/plugins/fleet/common/types/models/agent_policy.ts b/x-pack/plugins/fleet/common/types/models/agent_policy.ts index 841b98b239b2..fb19953a1f73 100644 --- a/x-pack/plugins/fleet/common/types/models/agent_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/agent_policy.ts @@ -272,7 +272,6 @@ export interface FleetServerPolicy { export interface AgentlessApiResponse { id: string; - region_id: string; } // Definitions for agent policy outputs endpoints diff --git a/x-pack/plugins/fleet/common/types/models/package_policy.ts b/x-pack/plugins/fleet/common/types/models/package_policy.ts index 354834d2571d..5c98729ff6cd 100644 --- a/x-pack/plugins/fleet/common/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/common/types/models/package_policy.ts @@ -93,6 +93,7 @@ export interface NewPackagePolicy { [key: string]: any; }; overrides?: { inputs?: { [key: string]: any } } | null; + supports_agentless?: boolean | null; } export interface UpdatePackagePolicy extends NewPackagePolicy { diff --git a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts index b990e5367bb4..57e0cc4f735f 100644 --- a/x-pack/plugins/fleet/common/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/common/types/rest_spec/agent.ts @@ -220,6 +220,8 @@ export interface GetAgentStatusResponse { export interface GetAgentIncomingDataRequest { query: { agentsIds: string[]; + pkgName?: string; + pkgVersion?: string; previewData?: boolean; }; } diff --git a/x-pack/plugins/fleet/cypress/e2e/agents/agentless.cy.ts b/x-pack/plugins/fleet/cypress/e2e/agents/agentless.cy.ts new file mode 100644 index 000000000000..2003a9f165d3 --- /dev/null +++ b/x-pack/plugins/fleet/cypress/e2e/agents/agentless.cy.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ADD_PACKAGE_POLICY_BTN } from '../../screens/fleet'; +import { login } from '../../tasks/login'; + +describe('View agentless policy details', () => { + beforeEach(() => { + login(); + cy.intercept('/api/fleet/agent_policies/policy-1', { + item: { + id: 'policy-1', + name: 'Agentless policy for cspm-1', + description: '', + namespace: 'default', + monitoring_enabled: ['logs', 'metrics'], + status: 'active', + supports_agentless: true, + package_policies: [ + { + id: 'cspm-1', + name: 'cspm-1', + policy_id: 'policy-1', + policy_ids: ['policy-1'], + inputs: [], + }, + ], + }, + }); + }); + + it('should not show the add integration button if the policy support agentless', () => { + cy.visit('/app/fleet/policies/policy-1'); + cy.getBySel(ADD_PACKAGE_POLICY_BTN).should('not.exist'); + }); +}); diff --git a/x-pack/plugins/fleet/dev_docs/space_awareness.md b/x-pack/plugins/fleet/dev_docs/space_awareness.md index fc4ce3a0acd0..90371d1f8bb0 100644 --- a/x-pack/plugins/fleet/dev_docs/space_awareness.md +++ b/x-pack/plugins/fleet/dev_docs/space_awareness.md @@ -15,7 +15,7 @@ xpack.fleet.enableExperimental: ['useSpaceAwareness', 'subfeaturePrivileges'] After the feature flag is enabled you will have to do another step to opt-in for the feature, that call will migrate the current space agnostic saved objects to new space aware saved objects. ```shell -curl -u elastic:changeme -XPOST "http://localhost:5601/internal/fleet/enable_space_awareness" -H "kbn-xsrf: reporting" -H 'elastic-api-version: 1' +curl -u elastic:changeme -XPOST "http://localhost:5601/internal/fleet/enable_space_awareness" -H "kbn-xsrf: reporting" -H 'elastic-api-version: 1' -H 'x-elastic-internal-origin: 1' ``` ## Space aware entities in Fleet diff --git a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts index da4d0e2c2594..9d2f6ba4ccf0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/hooks/use_apm_service_href.test.ts @@ -20,7 +20,8 @@ jest.mock('../../../hooks/use_locator', () => { }); const apmLocatorMock = useLocatorModule.useLocator('APM_LOCATOR')?.getUrl; -describe('useApmServiceHref hook', () => { +// FLAKY: https://github.com/elastic/kibana/issues/201876 +describe.skip('useApmServiceHref hook', () => { afterEach(() => { jest.clearAllMocks(); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx index e404b30a37ce..61846bdbd7e2 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.test.tsx @@ -18,6 +18,8 @@ import type { AgentPolicy, NewAgentPolicy } from '../../../../../../../common/ty import { useLicense } from '../../../../../../hooks/use_license'; +import { useFleetStatus } from '../../../../hooks'; + import type { LicenseService } from '../../../../../../../common/services'; import { generateNewAgentPolicyWithDefaults } from '../../../../../../../common/services'; @@ -26,8 +28,13 @@ import type { ValidationResults } from '../agent_policy_validation'; import { AgentPolicyAdvancedOptionsContent } from '.'; jest.mock('../../../../../../hooks/use_license'); +jest.mock('../../../../hooks', () => ({ + ...jest.requireActual('../../../../hooks'), + useFleetStatus: jest.fn(), +})); const mockedUseLicence = useLicense as jest.MockedFunction<typeof useLicense>; +const mockedUseFleetStatus = useFleetStatus as jest.MockedFunction<typeof useFleetStatus>; describe('Agent policy advanced options content', () => { let testRender: TestRenderer; @@ -40,6 +47,10 @@ describe('Agent policy advanced options content', () => { hasAtLeast: () => true, isPlatinum: () => true, } as unknown as LicenseService); + const useSpaceAwareness = () => + mockedUseFleetStatus.mockReturnValue({ + isSpaceAwarenessEnabled: true, + } as any); const render = ({ isProtected = false, @@ -47,6 +58,7 @@ describe('Agent policy advanced options content', () => { policyId = 'agent-policy-1', newAgentPolicy = false, packagePolicy = [createPackagePolicyMock()], + spaceIds = ['default'], } = {}) => { if (newAgentPolicy) { mockAgentPolicy = generateNewAgentPolicyWithDefaults(); @@ -56,6 +68,7 @@ describe('Agent policy advanced options content', () => { package_policies: packagePolicy, id: policyId, is_managed: isManaged, + space_ids: spaceIds, }; } @@ -72,6 +85,7 @@ describe('Agent policy advanced options content', () => { }; beforeEach(() => { + mockedUseFleetStatus.mockReturnValue({} as any); testRender = createFleetTestRendererMock(); }); afterEach(() => { @@ -173,4 +187,39 @@ describe('Agent policy advanced options content', () => { expect(renderResult.queryByText('This policy has no custom fields')).toBeInTheDocument(); }); }); + + describe('Space selector', () => { + beforeEach(() => { + usePlatinumLicense(); + }); + + describe('when space awareness is disabled', () => { + it('should not be rendered', () => { + render(); + expect(renderResult.queryByTestId('spaceSelectorInput')).not.toBeInTheDocument(); + }); + }); + + describe('when space awareness is enabled', () => { + beforeEach(() => { + useSpaceAwareness(); + }); + + describe('when the user has access to all policy spaces', () => { + it('should render the space selection input with the Create space link', () => { + render(); + expect(renderResult.queryByTestId('spaceSelectorInput')).toBeInTheDocument(); + expect(renderResult.queryByTestId('spaceSelectorInputLink')).toBeInTheDocument(); + }); + }); + + describe('when the user does not have access to all policy spaces', () => { + it('should render the space selection input without the Create space link', () => { + render({ spaceIds: ['default', '?'] }); + expect(renderResult.queryByTestId('spaceSelectorInput')).toBeInTheDocument(); + expect(renderResult.queryByTestId('spaceSelectorInputLink')).not.toBeInTheDocument(); + }); + }); + }); + }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx index 305148584f54..b0889f825727 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/components/agent_policy_advanced_fields/index.tsx @@ -34,6 +34,7 @@ import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, dataTypes, DEFAULT_MAX_AGENT_POLICIES_WITH_INACTIVITY_TIMEOUT, + UNKNOWN_SPACE, } from '../../../../../../../common/constants'; import type { NewAgentPolicy, AgentPolicy } from '../../../../types'; import { @@ -127,7 +128,12 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> = const isManagedorAgentlessPolicy = agentPolicy.is_managed === true || agentPolicy?.supports_agentless === true; - const agentPolicyFormContect = useAgentPolicyFormContext(); + const userHasAccessToAllPolicySpaces = useMemo( + () => 'space_ids' in agentPolicy && !agentPolicy.space_ids?.includes(UNKNOWN_SPACE), + [agentPolicy] + ); + + const agentPolicyFormContext = useAgentPolicyFormContext(); const AgentTamperProtectionSectionContent = useMemo( () => ( @@ -309,13 +315,14 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> = description={ <FormattedMessage id="xpack.fleet.agentPolicyForm.spaceDescription" - defaultMessage="Select one or more spaces for this policy or create a new one. {link}" + defaultMessage="Select one or more spaces for this policy or create a new one. {link}{tooltip}" values={{ - link: ( + link: userHasAccessToAllPolicySpaces && ( <EuiLink target="_blank" href={getAbsolutePath('/app/management/kibana/spaces/create')} external + data-test-subj="spaceSelectorInputLink" > <FormattedMessage id="xpack.fleet.agentPolicyForm.createSpaceLink" @@ -323,18 +330,30 @@ export const AgentPolicyAdvancedOptionsContent: React.FunctionComponent<Props> = /> </EuiLink> ), + tooltip: !userHasAccessToAllPolicySpaces && ( + <EuiIconTip + type="iInCircle" + color="subdued" + content={i18n.translate('xpack.fleet.agentPolicyForm.spaceTooltip', { + defaultMessage: 'Access to all policy spaces is required for edit.', + })} + /> + ), }} /> } + data-test-subj="spaceSelectorInput" > <SpaceSelector - isDisabled={disabled || agentPolicy.is_managed === true} + isDisabled={ + disabled || agentPolicy.is_managed === true || !userHasAccessToAllPolicySpaces + } value={ 'space_ids' in agentPolicy && agentPolicy.space_ids - ? agentPolicy.space_ids + ? agentPolicy.space_ids.filter((id) => id !== UNKNOWN_SPACE) : [spaceId || 'default'] } - setInvalidSpaceError={agentPolicyFormContect?.setInvalidSpaceError} + setInvalidSpaceError={agentPolicyFormContext?.setInvalidSpaceError} onChange={(newValue) => { if (newValue.length === 0) { return; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_panel.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_panel.test.tsx index 5accdf37e95e..0222e8a238b9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_panel.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/components/package_policy_input_panel.test.tsx @@ -360,11 +360,8 @@ describe('PackagePolicyInputPanel', () => { beforeEach(() => { useAgentlessMock.mockReturnValue({ isAgentlessEnabled: true, - isAgentlessPackagePolicy: jest.fn(), isAgentlessAgentPolicy: jest.fn(), isAgentlessIntegration: jest.fn(), - isAgentlessApiEnabled: true, - isDefaultAgentlessPolicyEnabled: false, }); }); @@ -395,11 +392,8 @@ describe('PackagePolicyInputPanel', () => { beforeEach(() => { useAgentlessMock.mockReturnValue({ isAgentlessEnabled: false, - isAgentlessPackagePolicy: jest.fn(), isAgentlessAgentPolicy: jest.fn(), isAgentlessIntegration: jest.fn(), - isAgentlessApiEnabled: true, - isDefaultAgentlessPolicyEnabled: false, }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx index 7ec72369f338..17c1b24dec81 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/components/steps/step_configure_package.test.tsx @@ -17,7 +17,8 @@ import { validatePackagePolicy } from '../../services'; import { StepConfigurePackagePolicy } from './step_configure_package'; -describe('StepConfigurePackage', () => { +// FLAKY: https://github.com/elastic/kibana/issues/201598 +describe.skip('StepConfigurePackage', () => { let packageInfo: PackageInfo; let packagePolicy: NewPackagePolicy; const mockUpdatePackagePolicy = jest.fn().mockImplementation((val: any) => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx index 1642abe05d72..d6d4c3abd63f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/multi_page_layout/components/confirm_incoming_data_with_preview.tsx @@ -131,11 +131,11 @@ export const ConfirmIncomingDataWithPreview: React.FunctionComponent<Props> = ({ setAgentDataConfirmed, troubleshootLink, }) => { - const { incomingData, dataPreview, isLoading, hasReachedTimeout } = usePollingIncomingData( + const { incomingData, dataPreview, isLoading, hasReachedTimeout } = usePollingIncomingData({ agentIds, - true, - MAX_AGENT_DATA_PREVIEW_COUNT - ); + previewData: true, + stopPollingAfterPreviewLength: MAX_AGENT_DATA_PREVIEW_COUNT, + }); const { enrolledAgents, numAgentsWithData } = useGetAgentIncomingData(incomingData, packageInfo); const isGuidedOnboardingActive = useIsGuidedOnboardingActive(packageInfo?.name); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx index 3dbe300b119b..4c4c7b311cb0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/form.tsx @@ -178,8 +178,7 @@ export function useOnSubmit({ const [hasAgentPolicyError, setHasAgentPolicyError] = useState<boolean>(false); const hasErrors = validationResults ? validationHasErrors(validationResults) : false; - const { isAgentlessIntegration, isAgentlessAgentPolicy, isAgentlessPackagePolicy } = - useAgentless(); + const { isAgentlessIntegration, isAgentlessAgentPolicy } = useAgentless(); // Update agent policy method const updateAgentPolicies = useCallback( @@ -316,9 +315,7 @@ export function useOnSubmit({ (agentCount !== 0 || (agentPolicies.length === 0 && selectedPolicyTab !== SelectedPolicyTab.NEW)) && !( - isAgentlessIntegration(packageInfo) || - isAgentlessPackagePolicy(packagePolicy) || - isAgentlessAgentPolicy(overrideCreatedAgentPolicy) + isAgentlessIntegration(packageInfo) || isAgentlessAgentPolicy(overrideCreatedAgentPolicy) ) && formState !== 'CONFIRM' ) { @@ -365,9 +362,7 @@ export function useOnSubmit({ : packagePolicy.policy_ids; const shouldForceInstallOnAgentless = - isAgentlessAgentPolicy(createdPolicy) || - isAgentlessIntegration(packageInfo) || - isAgentlessPackagePolicy(packagePolicy); + isAgentlessAgentPolicy(createdPolicy) || isAgentlessIntegration(packageInfo); const forceInstall = force || shouldForceInstallOnAgentless; @@ -390,8 +385,7 @@ export function useOnSubmit({ const hasGoogleCloudShell = data?.item ? getCloudShellUrlFromPackagePolicy(data.item) : false; // Check if agentless is configured in ESS and Serverless until Agentless API migrates to Serverless - const isAgentlessConfigured = - isAgentlessAgentPolicy(createdPolicy) || (data && isAgentlessPackagePolicy(data.item)); + const isAgentlessConfigured = isAgentlessAgentPolicy(createdPolicy); // Removing this code will disabled the Save and Continue button. We need code below update form state and trigger correct modal depending on agent count if (hasFleetAddAgentsPrivileges && !isAgentlessConfigured) { @@ -479,7 +473,6 @@ export function useOnSubmit({ selectedPolicyTab, packagePolicy, isAgentlessAgentPolicy, - isAgentlessPackagePolicy, hasFleetAddAgentsPrivileges, withSysMonitoring, newAgentPolicy, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts index 0953f2367d05..1564d934b960 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.test.ts @@ -11,8 +11,7 @@ import { createPackagePolicyMock } from '../../../../../../../../common/mocks'; import type { RegistryPolicyTemplate, PackageInfo } from '../../../../../../../../common/types'; import { SetupTechnology } from '../../../../../../../../common/types'; -import { ExperimentalFeaturesService } from '../../../../../services'; -import { sendGetOneAgentPolicy, useStartServices, useConfig } from '../../../../../hooks'; +import { useStartServices, useConfig } from '../../../../../hooks'; import { SelectedPolicyTab } from '../../components'; import { generateNewAgentPolicyWithDefaults } from '../../../../../../../../common/services/generate_new_agent_policy'; @@ -30,12 +29,7 @@ jest.mock('../../../../../../../../common/services/generate_new_agent_policy'); type MockFn = jest.MockedFunction<any>; describe('useAgentless', () => { - const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); - beforeEach(() => { - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: false, - } as any); (useConfig as MockFn).mockReturnValue({ agentless: undefined, } as any); @@ -48,33 +42,25 @@ describe('useAgentless', () => { jest.clearAllMocks(); }); - it('should not return isAgentless when agentless is not enabled', () => { + it('should return isAgentlessEnabled as falsy when agentless is not enabled', () => { const { result } = renderHook(() => useAgentless()); expect(result.current.isAgentlessEnabled).toBeFalsy(); - expect(result.current.isAgentlessApiEnabled).toBeFalsy(); - expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy(); }); - it('should return isAgentlessEnabled as falsy if agentless.enabled is true and experimental feature agentless is truthy without cloud or serverless', () => { + it('should return isAgentlessEnabled as falsy if agentless.enabled true without cloud or serverless', () => { (useConfig as MockFn).mockReturnValue({ agentless: { enabled: true, }, } as any); - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: false, - } as any); - const { result } = renderHook(() => useAgentless()); expect(result.current.isAgentlessEnabled).toBeFalsy(); - expect(result.current.isAgentlessApiEnabled).toBeFalsy(); - expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy(); }); - it('should return isAgentlessEnabled and isAgentlessApiEnabled as truthy with isCloudEnabled', () => { + it('should return isAgentlessEnabled as truthy with isCloudEnabled', () => { (useConfig as MockFn).mockReturnValue({ agentless: { enabled: true, @@ -91,14 +77,9 @@ describe('useAgentless', () => { const { result } = renderHook(() => useAgentless()); expect(result.current.isAgentlessEnabled).toBeTruthy(); - expect(result.current.isAgentlessApiEnabled).toBeTruthy(); - expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy(); }); - it('should return isAgentlessEnabled and isDefaultAgentlessPolicyEnabled as truthy with isServerlessEnabled and experimental feature agentless is truthy', () => { - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: true, - } as any); + it('should return isAgentlessEnabled truthy with isServerlessEnabled', () => { (useStartServices as MockFn).mockReturnValue({ cloud: { isServerlessEnabled: true, @@ -106,18 +87,18 @@ describe('useAgentless', () => { }, }); + (useConfig as MockFn).mockReturnValue({ + agentless: { + enabled: true, + }, + } as any); + const { result } = renderHook(() => useAgentless()); expect(result.current.isAgentlessEnabled).toBeTruthy(); - expect(result.current.isAgentlessApiEnabled).toBeFalsy(); - expect(result.current.isDefaultAgentlessPolicyEnabled).toBeTruthy(); }); - it('should return isAgentlessEnabled as falsy and isDefaultAgentlessPolicyEnabled as falsy with isServerlessEnabled and experimental feature agentless is falsy', () => { - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: false, - } as any); - + it('should return isAgentlessEnabled as falsy with isServerlessEnabled and without agentless config', () => { (useStartServices as MockFn).mockReturnValue({ cloud: { isServerlessEnabled: true, @@ -128,14 +109,13 @@ describe('useAgentless', () => { const { result } = renderHook(() => useAgentless()); expect(result.current.isAgentlessEnabled).toBeFalsy(); - expect(result.current.isAgentlessApiEnabled).toBeFalsy(); - expect(result.current.isDefaultAgentlessPolicyEnabled).toBeFalsy(); }); }); describe('useSetupTechnology', () => { const setNewAgentPolicy = jest.fn(); const updateAgentPoliciesMock = jest.fn(); + const updatePackagePolicyMock = jest.fn(); const setSelectedPolicyTabMock = jest.fn(); const newAgentPolicyMock = { name: 'mock_new_agent_policy', @@ -178,20 +158,10 @@ describe('useSetupTechnology', () => { const packagePolicyMock = createPackagePolicyMock(); - const mockedExperimentalFeaturesService = jest.mocked(ExperimentalFeaturesService); - beforeEach(() => { - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: true, - } as any); (useConfig as MockFn).mockReturnValue({ agentless: undefined, } as any); - (sendGetOneAgentPolicy as MockFn).mockResolvedValue({ - data: { - item: { id: 'agentless-policy-id' }, - }, - }); (useStartServices as MockFn).mockReturnValue({ cloud: { isServerlessEnabled: true, @@ -207,108 +177,20 @@ describe('useSetupTechnology', () => { }); it('should initialize with default values when agentless is disabled', () => { - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: false, - } as any); - - const { result } = renderHook(() => - useSetupTechnology({ - setNewAgentPolicy, - newAgentPolicy: newAgentPolicyMock, - updateAgentPolicies: updateAgentPoliciesMock, - setSelectedPolicyTab: setSelectedPolicyTabMock, - packagePolicy: packagePolicyMock, - }) - ); - - expect(sendGetOneAgentPolicy).not.toHaveBeenCalled(); - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); - }); - - it('should set the default selected setup technology to agent-based when creating a non agentless-only package policy', async () => { - (useConfig as MockFn).mockReturnValue({ - agentless: { - enabled: true, - api: { - url: 'https://agentless.api.url', - }, - }, - } as any); - (useStartServices as MockFn).mockReturnValue({ - cloud: { - isCloudEnabled: true, - }, - }); - const { result } = renderHook(() => useSetupTechnology({ setNewAgentPolicy, newAgentPolicy: newAgentPolicyMock, updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, - packageInfo: packageInfoMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); }); - it('should set the default selected setup technology to agentless when creating an agentless-only package policy', async () => { - (useConfig as MockFn).mockReturnValue({ - agentless: { - enabled: true, - api: { - url: 'https://agentless.api.url', - }, - }, - } as any); - (useStartServices as MockFn).mockReturnValue({ - cloud: { - isCloudEnabled: true, - }, - }); - const agentlessOnlyPackageInfoMock = { - policy_templates: [ - { - deployment_modes: { - default: { enabled: false }, - agentless: { enabled: true }, - }, - }, - ], - } as PackageInfo; - - const { result } = renderHook(() => - useSetupTechnology({ - setNewAgentPolicy, - newAgentPolicy: newAgentPolicyMock, - updateAgentPolicies: updateAgentPoliciesMock, - setSelectedPolicyTab: setSelectedPolicyTabMock, - packageInfo: agentlessOnlyPackageInfoMock, - packagePolicy: packagePolicyMock, - }) - ); - - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); - }); - - it('should fetch agentless policy if agentless feature is enabled and isServerless is true', async () => { - renderHook(() => - useSetupTechnology({ - setNewAgentPolicy, - newAgentPolicy: newAgentPolicyMock, - updateAgentPolicies: updateAgentPoliciesMock, - setSelectedPolicyTab: setSelectedPolicyTabMock, - packagePolicy: packagePolicyMock, - }) - ); - - await waitFor(() => { - expect(sendGetOneAgentPolicy).toHaveBeenCalled(); - }); - }); - it('should set agentless setup technology if agent policy supports agentless in edit page', async () => { (useConfig as MockFn).mockReturnValue({ agentless: { @@ -332,13 +214,14 @@ describe('useSetupTechnology', () => { packagePolicy: packagePolicyMock, isEditPage: true, agentPolicies: [{ id: 'agentless-policy-id', supports_agentless: true } as any], + updatePackagePolicy: updatePackagePolicyMock, }) ); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); }); - it('should create agentless policy if agentless feature is enabled and isCloud is true and agentless.api.url', async () => { + it('should create agentless policy if isCloud and agentless.enabled', async () => { (useConfig as MockFn).mockReturnValue({ agentless: { enabled: true, @@ -359,6 +242,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -368,6 +252,7 @@ describe('useSetupTechnology', () => { result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); }); await waitFor(() => { + expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: true }); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); expect(setNewAgentPolicy).toHaveBeenCalledWith({ name: 'Agentless policy for endpoint-1', @@ -398,6 +283,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }; const { result, rerender } = renderHook((props = initialProps) => useSetupTechnology(props), { @@ -411,6 +297,7 @@ describe('useSetupTechnology', () => { }); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); + expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: true }); expect(setNewAgentPolicy).toHaveBeenCalledWith({ inactivity_timeout: 3600, name: 'Agentless policy for endpoint-1', @@ -426,9 +313,11 @@ describe('useSetupTechnology', () => { ...packagePolicyMock, name: 'endpoint-2', }, + updatePackagePolicy: updatePackagePolicyMock, }); await waitFor(() => { + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); expect(setNewAgentPolicy).toHaveBeenCalledWith({ name: 'Agentless policy for endpoint-2', inactivity_timeout: 3600, @@ -437,7 +326,7 @@ describe('useSetupTechnology', () => { }); }); - it('should not create agentless policy if agentless feature is enabled and isCloud is true and agentless.api.url is not defined', async () => { + it('should not create agentless policy isCloud is true and agentless.api.url is not defined', async () => { (useConfig as MockFn).mockReturnValue({} as any); (useStartServices as MockFn).mockReturnValue({ cloud: { @@ -452,6 +341,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -464,10 +354,18 @@ describe('useSetupTechnology', () => { await waitFor(() => expect(setNewAgentPolicy).toHaveBeenCalledTimes(0)); }); - it('should not fetch agentless policy if agentless is enabled but serverless is disabled', async () => { + it('should update new agent policy and selected policy tab when setup technology is agent-based', async () => { + (useConfig as MockFn).mockReturnValue({ + agentless: { + enabled: true, + api: { + url: 'https://agentless.api.url', + }, + }, + } as any); (useStartServices as MockFn).mockReturnValue({ cloud: { - isServerlessEnabled: false, + isCloudEnabled: true, }, }); @@ -478,48 +376,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, - }) - ); - - expect(sendGetOneAgentPolicy).not.toHaveBeenCalled(); - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); - }); - - it('should update agent policy and selected policy tab when setup technology is agentless', async () => { - const { result } = renderHook(() => - useSetupTechnology({ - setNewAgentPolicy, - newAgentPolicy: newAgentPolicyMock, - updateAgentPolicies: updateAgentPoliciesMock, - setSelectedPolicyTab: setSelectedPolicyTabMock, - packagePolicy: packagePolicyMock, - }) - ); - - act(() => { - result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); - }); - - await waitFor(() => { - expect(updateAgentPoliciesMock).toHaveBeenCalledWith([ - { - inactivity_timeout: 3600, - name: 'Agentless policy for endpoint-1', - supports_agentless: true, - }, - ]); - expect(setSelectedPolicyTabMock).toHaveBeenCalledWith(SelectedPolicyTab.EXISTING); - }); - }); - - it('should update new agent policy and selected policy tab when setup technology is agent-based', async () => { - const { result } = renderHook(() => - useSetupTechnology({ - setNewAgentPolicy, - newAgentPolicy: newAgentPolicyMock, - updateAgentPolicies: updateAgentPoliciesMock, - setSelectedPolicyTab: setSelectedPolicyTabMock, - packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -530,12 +387,14 @@ describe('useSetupTechnology', () => { }); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); + expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: true }); act(() => { result.current.handleSetupTechnologyChange(SetupTechnology.AGENT_BASED); }); expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: false }); await waitFor(() => { expect(setNewAgentPolicy).toHaveBeenCalledWith(newAgentPolicyMock); @@ -543,30 +402,6 @@ describe('useSetupTechnology', () => { }); }); - it('should not update agent policy and selected policy tab when agentless is disabled', async () => { - mockedExperimentalFeaturesService.get.mockReturnValue({ - agentless: false, - } as any); - - const { result } = renderHook(() => - useSetupTechnology({ - setNewAgentPolicy, - newAgentPolicy: newAgentPolicyMock, - updateAgentPolicies: updateAgentPoliciesMock, - setSelectedPolicyTab: setSelectedPolicyTabMock, - packagePolicy: packagePolicyMock, - }) - ); - - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); - - act(() => { - result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); - }); - - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); - }); - it('should not update agent policy and selected policy tab when setup technology matches the current one ', async () => { const { result } = renderHook(() => useSetupTechnology({ @@ -575,6 +410,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -588,11 +424,25 @@ describe('useSetupTechnology', () => { expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + expect(updatePackagePolicyMock).not.toHaveBeenCalled(); expect(setNewAgentPolicy).not.toHaveBeenCalled(); expect(setSelectedPolicyTabMock).not.toHaveBeenCalled(); }); it('should revert the agent policy name to the original value when switching from agentless back to agent-based', async () => { + (useConfig as MockFn).mockReturnValue({ + agentless: { + enabled: true, + api: { + url: 'https://agentless.api.url', + }, + }, + } as any); + (useStartServices as MockFn).mockReturnValue({ + cloud: { + isServerlessEnabled: true, + }, + }); const { result } = renderHook(() => useSetupTechnology({ setNewAgentPolicy, @@ -600,6 +450,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -609,7 +460,9 @@ describe('useSetupTechnology', () => { result.current.handleSetupTechnologyChange(SetupTechnology.AGENTLESS); }); - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS); + await waitFor(() => + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENTLESS) + ); await waitFor(() => { expect(setNewAgentPolicy).toHaveBeenCalledWith({ @@ -617,14 +470,18 @@ describe('useSetupTechnology', () => { supports_agentless: true, inactivity_timeout: 3600, }); + expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: true }); }); act(() => { result.current.handleSetupTechnologyChange(SetupTechnology.AGENT_BASED); }); - expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); - expect(setNewAgentPolicy).toHaveBeenCalledWith(newAgentPolicyMock); + await waitFor(() => { + expect(result.current.selectedSetupTechnology).toBe(SetupTechnology.AGENT_BASED); + expect(setNewAgentPolicy).toHaveBeenCalledWith(newAgentPolicyMock); + expect(updatePackagePolicyMock).toHaveBeenCalledWith({ supports_agentless: false }); + }); }); it('should have global_data_tags with the integration team when creating agentless policy with global_data_tags', async () => { @@ -650,6 +507,7 @@ describe('useSetupTechnology', () => { setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, packageInfo: packageInfoMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -694,6 +552,7 @@ describe('useSetupTechnology', () => { setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, packageInfo: packageInfoMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -743,6 +602,7 @@ describe('useSetupTechnology', () => { setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, packageInfo: packageInfoMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -788,6 +648,7 @@ describe('useSetupTechnology', () => { updateAgentPolicies: updateAgentPoliciesMock, setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); @@ -834,6 +695,7 @@ describe('useSetupTechnology', () => { setSelectedPolicyTab: setSelectedPolicyTabMock, packagePolicy: packagePolicyMock, packageInfo: packageInfoMock, + updatePackagePolicy: updatePackagePolicyMock, }) ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts index 6bd3288af2e0..85f5cbdc5fae 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology.ts @@ -8,7 +8,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useConfig } from '../../../../../hooks'; -import { ExperimentalFeaturesService } from '../../../../../services'; import { generateNewAgentPolicyWithDefaults } from '../../../../../../../../common/services/generate_new_agent_policy'; import type { AgentPolicy, @@ -17,10 +16,9 @@ import type { PackageInfo, } from '../../../../../types'; import { SetupTechnology } from '../../../../../types'; -import { sendGetOneAgentPolicy, useStartServices } from '../../../../../hooks'; +import { useStartServices } from '../../../../../hooks'; import { SelectedPolicyTab } from '../../components'; import { - AGENTLESS_POLICY_ID, AGENTLESS_GLOBAL_TAG_NAME_ORGANIZATION, AGENTLESS_GLOBAL_TAG_NAME_DIVISION, AGENTLESS_GLOBAL_TAG_NAME_TEAM, @@ -33,23 +31,15 @@ import { export const useAgentless = () => { const config = useConfig(); - const { agentless: agentlessExperimentalFeatureEnabled } = ExperimentalFeaturesService.get(); const { cloud } = useStartServices(); const isServerless = !!cloud?.isServerlessEnabled; const isCloud = !!cloud?.isCloudEnabled; - const isAgentlessApiEnabled = (isCloud || isServerless) && config.agentless?.enabled; - const isDefaultAgentlessPolicyEnabled = - !isAgentlessApiEnabled && isServerless && agentlessExperimentalFeatureEnabled; - - const isAgentlessEnabled = isAgentlessApiEnabled || isDefaultAgentlessPolicyEnabled; + const isAgentlessEnabled = (isCloud || isServerless) && config.agentless?.enabled === true; const isAgentlessAgentPolicy = (agentPolicy: AgentPolicy | undefined) => { if (!agentPolicy) return false; - return ( - isAgentlessEnabled && - (agentPolicy?.id === AGENTLESS_POLICY_ID || !!agentPolicy?.supports_agentless) - ); + return isAgentlessEnabled && !!agentPolicy?.supports_agentless; }; // When an integration has at least a policy template enabled for agentless @@ -60,17 +50,10 @@ export const useAgentless = () => { return false; }; - // TODO: remove this check when CSPM implements the above flag and rely only on `isAgentlessIntegration` - const isAgentlessPackagePolicy = (packagePolicy: NewPackagePolicy) => { - return isAgentlessEnabled && packagePolicy.policy_ids.includes(AGENTLESS_POLICY_ID); - }; return { - isAgentlessApiEnabled, - isDefaultAgentlessPolicyEnabled, isAgentlessEnabled, isAgentlessAgentPolicy, isAgentlessIntegration, - isAgentlessPackagePolicy, }; }; @@ -78,6 +61,7 @@ export function useSetupTechnology({ setNewAgentPolicy, newAgentPolicy, updateAgentPolicies, + updatePackagePolicy, setSelectedPolicyTab, packageInfo, packagePolicy, @@ -87,14 +71,14 @@ export function useSetupTechnology({ setNewAgentPolicy: (policy: NewAgentPolicy) => void; newAgentPolicy: NewAgentPolicy; updateAgentPolicies: (policies: AgentPolicy[]) => void; + updatePackagePolicy: (policy: Partial<NewPackagePolicy>) => void; setSelectedPolicyTab: (tab: SelectedPolicyTab) => void; packageInfo?: PackageInfo; packagePolicy: NewPackagePolicy; isEditPage?: boolean; agentPolicies?: AgentPolicy[]; }) { - const { isAgentlessEnabled, isAgentlessApiEnabled, isDefaultAgentlessPolicyEnabled } = - useAgentless(); + const { isAgentlessEnabled } = useAgentless(); // this is a placeholder for the new agent-BASED policy that will be used when the user switches from agentless to agent-based and back const newAgentBasedPolicy = useRef<NewAgentPolicy>(newAgentPolicy); @@ -119,7 +103,7 @@ export function useSetupTechnology({ setSelectedSetupTechnology(SetupTechnology.AGENTLESS); return; } - if (isAgentlessApiEnabled && selectedSetupTechnology === SetupTechnology.AGENTLESS) { + if (isAgentlessEnabled && selectedSetupTechnology === SetupTechnology.AGENTLESS) { const nextNewAgentlessPolicy = { ...newAgentlessPolicy, name: getAgentlessAgentPolicyNameFromPackagePolicyName(packagePolicy.name), @@ -130,42 +114,35 @@ export function useSetupTechnology({ updateAgentPolicies([nextNewAgentlessPolicy] as AgentPolicy[]); } } + if ( + selectedSetupTechnology === SetupTechnology.AGENTLESS && + !packagePolicy.supports_agentless + ) { + updatePackagePolicy({ + supports_agentless: true, + }); + } else if ( + selectedSetupTechnology !== SetupTechnology.AGENTLESS && + packagePolicy.supports_agentless + ) { + updatePackagePolicy({ + supports_agentless: false, + }); + } }, [ - isAgentlessApiEnabled, + isAgentlessEnabled, isEditPage, newAgentlessPolicy, packagePolicy.name, + packagePolicy.supports_agentless, selectedSetupTechnology, updateAgentPolicies, setNewAgentPolicy, agentPolicies, setSelectedSetupTechnology, + updatePackagePolicy, ]); - // tech debt: remove this useEffect when Serverless uses the Agentless API - // https://github.com/elastic/security-team/issues/9781 - useEffect(() => { - const fetchAgentlessPolicy = async () => { - const { data, error } = await sendGetOneAgentPolicy(AGENTLESS_POLICY_ID); - const isAgentlessAvailable = !error && data && data.item; - - if (isAgentlessAvailable) { - setNewAgentlessPolicy(data.item); - } - }; - - if (isDefaultAgentlessPolicyEnabled) { - fetchAgentlessPolicy(); - } - }, [isDefaultAgentlessPolicyEnabled]); - - useEffect(() => { - if (isEditPage) { - return; - } - setSelectedSetupTechnology(defaultSetupTechnology); - }, [packageInfo, defaultSetupTechnology, isEditPage]); - const handleSetupTechnologyChange = useCallback( (setupTechnology: SetupTechnology, policyTemplateName?: string) => { if (!isAgentlessEnabled || setupTechnology === selectedSetupTechnology) { @@ -173,7 +150,7 @@ export function useSetupTechnology({ } if (setupTechnology === SetupTechnology.AGENTLESS) { - if (isAgentlessApiEnabled) { + if (isAgentlessEnabled) { const agentlessPolicy = { ...newAgentlessPolicy, ...getAdditionalAgentlessPolicyInfo(policyTemplateName, packageInfo), @@ -184,18 +161,17 @@ export function useSetupTechnology({ setSelectedPolicyTab(SelectedPolicyTab.NEW); updateAgentPolicies([agentlessPolicy] as AgentPolicy[]); } - // tech debt: remove this when Serverless uses the Agentless API - // https://github.com/elastic/security-team/issues/9781 - if (isDefaultAgentlessPolicyEnabled) { - setNewAgentPolicy(newAgentlessPolicy as AgentPolicy); - updateAgentPolicies([newAgentlessPolicy] as AgentPolicy[]); - setSelectedPolicyTab(SelectedPolicyTab.EXISTING); - } + updatePackagePolicy({ + supports_agentless: true, + }); } else if (setupTechnology === SetupTechnology.AGENT_BASED) { setNewAgentPolicy({ ...newAgentBasedPolicy.current, supports_agentless: false, }); + updatePackagePolicy({ + supports_agentless: false, + }); setSelectedPolicyTab(SelectedPolicyTab.NEW); updateAgentPolicies([newAgentBasedPolicy.current] as AgentPolicy[]); } @@ -204,13 +180,12 @@ export function useSetupTechnology({ [ isAgentlessEnabled, selectedSetupTechnology, - isAgentlessApiEnabled, - isDefaultAgentlessPolicyEnabled, + updatePackagePolicy, setNewAgentPolicy, newAgentlessPolicy, + packageInfo, setSelectedPolicyTab, updateAgentPolicies, - packageInfo, ] ); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx index e3b195947564..a79db9ea1edd 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.test.tsx @@ -13,17 +13,12 @@ import type { MockedFleetStartServices, TestRenderer } from '../../../../../../m import { createFleetTestRendererMock } from '../../../../../../mock'; import { FLEET_ROUTING_PATHS, pagePathGetters, PLUGIN_ID } from '../../../../constants'; import type { CreatePackagePolicyRouteState } from '../../../../types'; - -import { ExperimentalFeaturesService } from '../../../../../../services'; - import { sendCreatePackagePolicy, sendCreateAgentPolicy, sendGetAgentStatus, - sendGetOneAgentPolicy, useIntraAppState, useStartServices, - useGetAgentPolicies, useGetPackageInfoByKeyQuery, useConfig, } from '../../../../hooks'; @@ -138,10 +133,6 @@ jest.mock('react-router-dom', () => ({ }), })); -import { AGENTLESS_POLICY_ID } from '../../../../../../../common/constants'; - -import { useAllNonManagedAgentPolicies } from '../components/steps/components/use_policies'; - import { CreatePackagePolicySinglePage } from '.'; import { SETUP_TECHNOLOGY_SELECTOR_TEST_SUBJ } from './components/setup_technology_selector'; @@ -692,108 +683,6 @@ describe('When on the package policy create page', () => { }); }); - describe('With agentless policy and Serverless available', () => { - beforeEach(async () => { - (useStartServices as jest.MockedFunction<any>).mockReturnValue({ - ...useStartServices(), - cloud: { - ...useStartServices().cloud, - isServerlessEnabled: true, - }, - }); - jest.spyOn(ExperimentalFeaturesService, 'get').mockReturnValue({ agentless: true } as any); - (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue( - getMockPackageInfo({ requiresRoot: false, dataStreamRequiresRoot: false }) - ); - - (sendGetOneAgentPolicy as jest.MockedFunction<any>).mockResolvedValue({ - data: { item: { id: AGENTLESS_POLICY_ID, name: 'Agentless CSPM', namespace: 'default' } }, - }); - (useGetAgentPolicies as jest.MockedFunction<any>).mockReturnValue({ - data: { - items: [{ id: AGENTLESS_POLICY_ID, name: 'Agentless CSPM', namespace: 'default' }], - }, - error: undefined, - isLoading: false, - resendRequest: jest.fn(), - }); - (useAllNonManagedAgentPolicies as jest.MockedFunction<any>).mockReturnValue([ - { id: AGENTLESS_POLICY_ID, name: 'Agentless CSPM', namespace: 'default' }, - ]); - - await act(async () => { - render(); - }); - }); - - test('should not force create package policy when not in serverless', async () => { - jest.spyOn(ExperimentalFeaturesService, 'get').mockReturnValue({ agentless: false } as any); - (useStartServices as jest.MockedFunction<any>).mockReturnValue({ - ...useStartServices(), - cloud: { - ...useStartServices().cloud, - isServerlessEnabled: false, - }, - }); - await act(async () => { - fireEvent.click(renderResult.getByText('Existing hosts')!); - }); - - await act(async () => { - fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!); - }); - - expect(sendCreateAgentPolicy as jest.MockedFunction<any>).not.toHaveBeenCalled(); - expect(sendCreatePackagePolicy as jest.MockedFunction<any>).toHaveBeenCalledWith({ - ...newPackagePolicy, - force: false, - policy_ids: [AGENTLESS_POLICY_ID], - }); - - await waitFor(() => { - expect(renderResult.getByText('Nginx integration added')).toBeInTheDocument(); - }); - }); - - test('should force create package policy', async () => { - await act(async () => { - fireEvent.click(renderResult.getByText('Existing hosts')!); - }); - - await act(async () => { - fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!); - }); - - expect(sendCreateAgentPolicy as jest.MockedFunction<any>).not.toHaveBeenCalled(); - expect(sendCreatePackagePolicy as jest.MockedFunction<any>).toHaveBeenCalledWith({ - ...newPackagePolicy, - force: true, - policy_ids: [AGENTLESS_POLICY_ID], - }); - - await waitFor(() => { - expect(renderResult.getByText('Nginx integration added')).toBeInTheDocument(); - }); - }); - - test('should not show confirmation modal', async () => { - (sendGetAgentStatus as jest.MockedFunction<any>).mockResolvedValueOnce({ - data: { results: { active: 1 } }, - }); - - await act(async () => { - fireEvent.click(renderResult.getByText('Existing hosts')!); - }); - - await act(async () => { - fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!); - }); - - expect(sendCreateAgentPolicy as jest.MockedFunction<any>).not.toHaveBeenCalled(); - expect(sendCreatePackagePolicy as jest.MockedFunction<any>).toHaveBeenCalled(); - }); - }); - describe('With agentless Cloud available', () => { beforeEach(async () => { (useConfig as jest.MockedFunction<any>).mockReturnValue({ @@ -819,10 +708,6 @@ describe('When on the package policy create page', () => { }, }); - (sendCreatePackagePolicy as jest.MockedFunction<any>).mockResolvedValue({ - data: { item: { id: 'policy-1', inputs: [], policy_ids: ['agentless-policy-1'] } }, - }); - jest.spyOn(ExperimentalFeaturesService, 'get').mockReturnValue({ agentless: true } as any); (useGetPackageInfoByKeyQuery as jest.Mock).mockReturnValue( getMockPackageInfo({ requiresRoot: false, @@ -840,9 +725,6 @@ describe('When on the package policy create page', () => { fireEvent.click(renderResult.getByText(/Save and continue/).closest('button')!); }); - // tech debt: this should be converted to use MSW to mock the API calls - // https://github.com/elastic/security-team/issues/9816 - expect(sendGetOneAgentPolicy).not.toHaveBeenCalled(); expect(sendCreateAgentPolicy).toHaveBeenCalledWith( expect.objectContaining({ monitoring_enabled: ['logs', 'metrics'], diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx index 93631f63d0e0..3941c92a76c3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/create_package_policy_page/single_page_layout/index.tsx @@ -355,6 +355,7 @@ export const CreatePackagePolicySinglePage: CreatePackagePolicyParams = ({ newAgentPolicy, setNewAgentPolicy, updateAgentPolicies, + updatePackagePolicy, setSelectedPolicyTab, packageInfo, packagePolicy, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx index 83e18d77f2a0..3fe016d5e35f 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/package_policies/package_policies_table.tsx @@ -400,45 +400,46 @@ export const PackagePoliciesTable: React.FunctionComponent<Props> = ({ }} {...rest} search={{ - toolsRight: agentPolicy.is_managed - ? [] - : [ - <EuiButtonWithTooltip - key="addPackagePolicyButton" - fill - isDisabled={!canWriteIntegrationPolicies} - iconType="plusInCircle" - onClick={() => { - application.navigateToApp(INTEGRATIONS_PLUGIN_ID, { - path: pagePathGetters.integrations_all({})[1], - state: { forAgentPolicyId: agentPolicy.id }, - }); - }} - data-test-subj="addPackagePolicyButton" - tooltip={ - !canWriteIntegrationPolicies - ? { - content: missingSecurityConfiguration ? ( - <FormattedMessage - id="xpack.fleet.epm.addPackagePolicyButtonSecurityRequiredTooltip" - defaultMessage="To add Elastic Agent Integrations, you must have security enabled and have the All privilege for Fleet. Contact your administrator." - /> - ) : ( - <FormattedMessage - id="xpack.fleet.epm.addPackagePolicyButtonPrivilegesRequiredTooltip" - defaultMessage="Elastic Agent Integrations require the All privilege for Agent policies and All privilege for Integrations. Contact your administrator." - /> - ), - } - : undefined - } - > - <FormattedMessage - id="xpack.fleet.policyDetails.addPackagePolicyButtonText" - defaultMessage="Add integration" - /> - </EuiButtonWithTooltip>, - ], + toolsRight: + agentPolicy.is_managed || agentPolicy.supports_agentless + ? [] + : [ + <EuiButtonWithTooltip + key="addPackagePolicyButton" + fill + isDisabled={!canWriteIntegrationPolicies} + iconType="plusInCircle" + onClick={() => { + application.navigateToApp(INTEGRATIONS_PLUGIN_ID, { + path: pagePathGetters.integrations_all({})[1], + state: { forAgentPolicyId: agentPolicy.id }, + }); + }} + data-test-subj="addPackagePolicyButton" + tooltip={ + !canWriteIntegrationPolicies + ? { + content: missingSecurityConfiguration ? ( + <FormattedMessage + id="xpack.fleet.epm.addPackagePolicyButtonSecurityRequiredTooltip" + defaultMessage="To add Elastic Agent Integrations, you must have security enabled and have the All privilege for Fleet. Contact your administrator." + /> + ) : ( + <FormattedMessage + id="xpack.fleet.epm.addPackagePolicyButtonPrivilegesRequiredTooltip" + defaultMessage="Elastic Agent Integrations require the All privilege for Agent policies and All privilege for Integrations. Contact your administrator." + /> + ), + } + : undefined + } + > + <FormattedMessage + id="xpack.fleet.policyDetails.addPackagePolicyButtonText" + defaultMessage="Add integration" + /> + </EuiButtonWithTooltip>, + ], box: { incremental: true, schema: true, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx index 9de7a3f22adf..e0ea955cf5af 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/details_page/components/settings/index.tsx @@ -39,13 +39,13 @@ import { import { DevtoolsRequestFlyoutButton } from '../../../../../components'; import { ExperimentalFeaturesService } from '../../../../../services'; import { generateUpdateAgentPolicyDevToolsRequest } from '../../../services'; +import { UNKNOWN_SPACE } from '../../../../../../../../common/constants'; -const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => - pick(agentPolicy, [ +const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => { + const partialPolicy = pick(agentPolicy, [ 'name', 'description', 'namespace', - 'space_ids', 'monitoring_enabled', 'unenroll_timeout', 'inactivity_timeout', @@ -61,6 +61,13 @@ const pickAgentPolicyKeysToSend = (agentPolicy: AgentPolicy) => 'monitoring_http', 'monitoring_diagnostics', ]); + return { + ...partialPolicy, + ...(!agentPolicy.space_ids?.includes(UNKNOWN_SPACE) && { + space_ids: agentPolicy.space_ids, + }), + }; +}; const FormWrapper = styled.div` max-width: 1200px; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx index 1f2bdecf9e5a..56f6a747dd57 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agent_policy/edit_package_policy_page/hooks/use_package_policy_steps.tsx @@ -134,6 +134,7 @@ export function usePackagePolicySteps({ newAgentPolicy, setNewAgentPolicy, updateAgentPolicies, + updatePackagePolicy, setSelectedPolicyTab, packagePolicy, isEditPage: true, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.test.tsx index 79908819ff86..03f7b2b33a83 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.test.tsx @@ -21,6 +21,7 @@ jest.mock('../../../../../../hooks/use_fleet_status', () => ({ FleetStatusProvider: (props: any) => { return props.children; }, + useFleetStatus: jest.fn().mockReturnValue({ spaceId: 'default' }), })); jest.mock('../../../../../../hooks/use_request/epm'); @@ -30,7 +31,7 @@ jest.mock('../../../../../../hooks/use_locator', () => { useDashboardLocator: jest.fn().mockImplementation(() => { return { id: 'DASHBOARD_APP_LOCATOR', - getRedirectUrl: jest.fn().mockResolvedValue('app/dashboards#/view/elastic_agent-a0001'), + getRedirectUrl: jest.fn().mockReturnValue('app/dashboards#/view/elastic_agent-a0001'), }; }), }; @@ -43,6 +44,10 @@ describe('AgentDashboardLink', () => { data: { item: { status: 'installed', + installationInfo: { + install_status: 'installed', + installed_kibana_space_id: 'default', + }, }, }, } as ReturnType<typeof useGetPackageInfoByKeyQuery>); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx index 6832f81961dd..c6a7c6b1a7d4 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx @@ -10,21 +10,49 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButton, EuiToolTip } from '@elastic/eui'; import styled from 'styled-components'; -import { useGetPackageInfoByKeyQuery, useLink, useDashboardLocator } from '../../../../hooks'; +import type { GetInfoResponse } from '../../../../../../../common/types'; +import { + useGetPackageInfoByKeyQuery, + useLink, + useDashboardLocator, + useFleetStatus, +} from '../../../../hooks'; import type { Agent, AgentPolicy } from '../../../../types'; import { FLEET_ELASTIC_AGENT_PACKAGE, DASHBOARD_LOCATORS_IDS, } from '../../../../../../../common/constants'; +import { getDashboardIdForSpace } from '../../services/dashboard_helpers'; + +function isKibanaAssetsInstalledInSpace(spaceId: string | undefined, res?: GetInfoResponse) { + if (res?.item?.status !== 'installed') { + return false; + } + + const installationInfo = res.item.installationInfo; + + if (!installationInfo || installationInfo.install_status !== 'installed') { + return false; + } + return ( + installationInfo.installed_kibana_space_id === spaceId || + (spaceId && installationInfo.additional_spaces_installed_kibana?.[spaceId]) + ); +} function useAgentDashboardLink(agent: Agent) { const { isLoading, data } = useGetPackageInfoByKeyQuery(FLEET_ELASTIC_AGENT_PACKAGE); + const { spaceId } = useFleetStatus(); - const isInstalled = data?.item.status === 'installed'; + const isInstalled = isKibanaAssetsInstalledInSpace(spaceId, data); const dashboardLocator = useDashboardLocator(); const link = dashboardLocator?.getRedirectUrl({ - dashboardId: DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_METRICS, + dashboardId: getDashboardIdForSpace( + spaceId, + data, + DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_METRICS + ), query: { language: 'kuery', query: `elastic_agent.id:${agent.id}`, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration.tsx index db14401edfad..84895a021df3 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration.tsx @@ -97,114 +97,122 @@ export const AgentDetailsIntegration: React.FunctionComponent<{ agent: Agent; agentPolicy: AgentPolicy; packagePolicy: PackagePolicy; + linkToLogs: boolean; 'data-test-subj'?: string; -}> = memo(({ agent, agentPolicy, packagePolicy, 'data-test-subj': dataTestSubj }) => { - const { getHref } = useLink(); - const theme = useEuiTheme(); +}> = memo( + ({ agent, agentPolicy, packagePolicy, linkToLogs = true, 'data-test-subj': dataTestSubj }) => { + const { getHref } = useLink(); + const theme = useEuiTheme(); - const [isAttentionBadgeNeededForPolicyResponse, setIsAttentionBadgeNeededForPolicyResponse] = - useState(false); + const [isAttentionBadgeNeededForPolicyResponse, setIsAttentionBadgeNeededForPolicyResponse] = + useState(false); - const policyResponseExtensionView = useUIExtension( - packagePolicy.package?.name ?? '', - 'package-policy-response' - ); - - const policyResponseExtensionViewWrapper = useMemo(() => { - return ( - policyResponseExtensionView && ( - <ExtensionWrapper> - <policyResponseExtensionView.Component - agent={agent} - onShowNeedsAttentionBadge={setIsAttentionBadgeNeededForPolicyResponse} - /> - </ExtensionWrapper> - ) - ); - }, [agent, policyResponseExtensionView]); - - const packageErrors = useMemo(() => { - if (!agent.components) { - return []; - } - return getInputUnitsByPackage(agent.components, packagePolicy).filter( - (u) => u.status === 'DEGRADED' || u.status === 'FAILED' + const policyResponseExtensionView = useUIExtension( + packagePolicy.package?.name ?? '', + 'package-policy-response' ); - }, [agent.components, packagePolicy]); - const showNeedsAttentionBadge = isAttentionBadgeNeededForPolicyResponse || !!packageErrors.length; + const policyResponseExtensionViewWrapper = useMemo(() => { + return ( + policyResponseExtensionView && ( + <ExtensionWrapper> + <policyResponseExtensionView.Component + agent={agent} + onShowNeedsAttentionBadge={setIsAttentionBadgeNeededForPolicyResponse} + /> + </ExtensionWrapper> + ) + ); + }, [agent, policyResponseExtensionView]); + + const packageErrors = useMemo(() => { + if (!agent.components) { + return []; + } + return getInputUnitsByPackage(agent.components, packagePolicy).filter( + (u) => u.status === 'DEGRADED' || u.status === 'FAILED' + ); + }, [agent.components, packagePolicy]); - const genericErrorsListExtensionView = useUIExtension( - packagePolicy.package?.name ?? '', - 'package-generic-errors-list' - ); + const showNeedsAttentionBadge = + isAttentionBadgeNeededForPolicyResponse || !!packageErrors.length; - const genericErrorsListExtensionViewWrapper = useMemo(() => { - return ( - genericErrorsListExtensionView && ( - <ExtensionWrapper> - <genericErrorsListExtensionView.Component packageErrors={packageErrors} /> - </ExtensionWrapper> - ) + const genericErrorsListExtensionView = useUIExtension( + packagePolicy.package?.name ?? '', + 'package-generic-errors-list' ); - }, [packageErrors, genericErrorsListExtensionView]); - return ( - <CollapsablePanel - id={packagePolicy.id} - data-test-subj={dataTestSubj} - title={ - <EuiTitle size="xs"> - <h3> - <EuiFlexGroup gutterSize="s" alignItems="center"> - <EuiFlexItem grow={false}> - {packagePolicy.package ? ( - <PackageIcon - packageName={packagePolicy.package.name} - version={packagePolicy.package.version} - size="l" - tryApi={true} - /> - ) : ( - <PackageIcon size="l" packageName="default" version="0" /> - )} - </EuiFlexItem> - <EuiFlexItem className="eui-textTruncate"> - <EuiLink - className="eui-textTruncate" - data-test-subj="agentPolicyDetailsLink" - href={getHref('edit_integration', { - policyId: agentPolicy.id, - packagePolicyId: packagePolicy.id, - })} - > - {packagePolicy.name} - </EuiLink> - </EuiFlexItem> - {showNeedsAttentionBadge && ( + const genericErrorsListExtensionViewWrapper = useMemo(() => { + return ( + genericErrorsListExtensionView && ( + <ExtensionWrapper> + <genericErrorsListExtensionView.Component packageErrors={packageErrors} /> + </ExtensionWrapper> + ) + ); + }, [packageErrors, genericErrorsListExtensionView]); + + return ( + <CollapsablePanel + id={packagePolicy.id} + data-test-subj={dataTestSubj} + title={ + <EuiTitle size="xs"> + <h3> + <EuiFlexGroup gutterSize="s" alignItems="center"> <EuiFlexItem grow={false}> - <EuiBadge - color={theme.euiTheme.colors.danger} - iconType="warning" - iconSide="left" - data-test-subj={dataTestSubj ? `${dataTestSubj}-needsAttention` : undefined} - > - <FormattedMessage - id="xpack.fleet.agentDetailsIntegrations.needsAttention.label" - defaultMessage="Needs attention" + {packagePolicy.package ? ( + <PackageIcon + packageName={packagePolicy.package.name} + version={packagePolicy.package.version} + size="l" + tryApi={true} /> - </EuiBadge> + ) : ( + <PackageIcon size="l" packageName="default" version="0" /> + )} </EuiFlexItem> - )} - </EuiFlexGroup> - </h3> - </EuiTitle> - } - > - <AgentDetailsIntegrationInputs agent={agent} packagePolicy={packagePolicy} /> - {policyResponseExtensionViewWrapper} - {genericErrorsListExtensionViewWrapper} - <EuiSpacer /> - </CollapsablePanel> - ); -}); + <EuiFlexItem className="eui-textTruncate"> + <EuiLink + className="eui-textTruncate" + data-test-subj="agentPolicyDetailsLink" + href={getHref('edit_integration', { + policyId: agentPolicy.id, + packagePolicyId: packagePolicy.id, + })} + > + {packagePolicy.name} + </EuiLink> + </EuiFlexItem> + {showNeedsAttentionBadge && ( + <EuiFlexItem grow={false}> + <EuiBadge + color={theme.euiTheme.colors.danger} + iconType="warning" + iconSide="left" + data-test-subj={dataTestSubj ? `${dataTestSubj}-needsAttention` : undefined} + > + <FormattedMessage + id="xpack.fleet.agentDetailsIntegrations.needsAttention.label" + defaultMessage="Needs attention" + /> + </EuiBadge> + </EuiFlexItem> + )} + </EuiFlexGroup> + </h3> + </EuiTitle> + } + > + <AgentDetailsIntegrationInputs + agent={agent} + packagePolicy={packagePolicy} + linkToLogs={linkToLogs} + /> + {policyResponseExtensionViewWrapper} + {genericErrorsListExtensionViewWrapper} + <EuiSpacer size="s" /> + </CollapsablePanel> + ); + } +); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration_inputs.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration_inputs.tsx index 71b1a1ad6fe3..7630b61c08be 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration_inputs.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integration_inputs.tsx @@ -66,8 +66,9 @@ const StyledEuiTreeView = styled(EuiTreeView)` export const AgentDetailsIntegrationInputs: React.FunctionComponent<{ agent: Agent; packagePolicy: PackagePolicy; + linkToLogs?: boolean; 'data-test-subj'?: string; -}> = memo(({ agent, packagePolicy, 'data-test-subj': dataTestSubj }) => { +}> = memo(({ agent, packagePolicy, linkToLogs = true, 'data-test-subj': dataTestSubj }) => { const { getHref } = useLink(); const inputStatusMap = useMemo( @@ -138,21 +139,25 @@ export const AgentDetailsIntegrationInputs: React.FunctionComponent<{ defaultMessage: 'View logs', })} > - <StyledEuiLink - href={getHref('agent_details', { - agentId: agent.id, - tabId: 'logs', - logQuery: getLogsQueryByInputType(current.type), - })} - aria-label={i18n.translate( - 'xpack.fleet.agentDetailsIntegrations.viewLogsButton', - { - defaultMessage: 'View logs', - } - )} - > - {displayInputType(current.type)} - </StyledEuiLink> + {linkToLogs ? ( + <StyledEuiLink + href={getHref('agent_details', { + agentId: agent.id, + tabId: 'logs', + logQuery: getLogsQueryByInputType(current.type), + })} + aria-label={i18n.translate( + 'xpack.fleet.agentDetailsIntegrations.viewLogsButton', + { + defaultMessage: 'View logs', + } + )} + > + {displayInputType(current.type)} + </StyledEuiLink> + ) : ( + <>{displayInputType(current.type)}</> + )} </EuiToolTip> ), id: current.type, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx index 5a7b135b4644..0a1df537e7bc 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations.tsx @@ -15,7 +15,8 @@ import { AgentDetailsIntegration } from './agent_details_integration'; export const AgentDetailsIntegrations: React.FunctionComponent<{ agent: Agent; agentPolicy?: AgentPolicy; -}> = memo(({ agent, agentPolicy }) => { + linkToLogs?: boolean; +}> = memo(({ agent, agentPolicy, linkToLogs = true }) => { if (!agentPolicy || !agentPolicy.package_policies) { return null; } @@ -31,6 +32,7 @@ export const AgentDetailsIntegrations: React.FunctionComponent<{ agent={agent} agentPolicy={agentPolicy} packagePolicy={packagePolicy} + linkToLogs={linkToLogs} data-test-subj={`${testSubj}-accordion`} /> </EuiFlexItem> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx index 255b2efb9402..b56494311f6a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_policy_outputs_summary.test.tsx @@ -15,7 +15,8 @@ import type { OutputsForAgentPolicy } from '../../../../../../../common/types'; import { AgentPolicyOutputsSummary } from './agent_policy_outputs_summary'; -describe('MultipleAgentPolicySummaryLine', () => { +// FLAKY: https://github.com/elastic/kibana/issues/200819 +describe.skip('MultipleAgentPolicySummaryLine', () => { let testRenderer: TestRenderer; const outputsForPolicy: OutputsForAgentPolicy = { agentPolicyId: 'policy-1', diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx index 4c34cb8824af..40017125a223 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_status_filter.test.tsx @@ -35,7 +35,8 @@ const renderComponent = (props: React.ComponentProps<typeof AgentStatusFilter>) ); }; -describe('AgentStatusFilter', () => { +// FLAKY: https://github.com/elastic/kibana/issues/200788 +describe.skip('AgentStatusFilter', () => { it('Renders all statuses', () => { const { getByText } = renderComponent({ selectedStatus: [], diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx index 25c394e2606b..3e5025807157 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx @@ -5,49 +5,69 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useQuery } from '@tanstack/react-query'; -import { DASHBOARD_LOCATORS_IDS } from '../../../../../../../common/constants'; +import { + DASHBOARD_LOCATORS_IDS, + FLEET_ELASTIC_AGENT_PACKAGE, +} from '../../../../../../../common/constants'; -import { useDashboardLocator, useStartServices } from '../../../../hooks'; +import { + useDashboardLocator, + useFleetStatus, + useGetPackageInfoByKeyQuery, + useStartServices, +} from '../../../../hooks'; + +import { getDashboardIdForSpace } from '../../services/dashboard_helpers'; const useDashboardExists = (dashboardId: string) => { - const [dashboardExists, setDashboardExists] = React.useState<boolean>(false); - const [loading, setLoading] = React.useState<boolean>(true); const { dashboard: dashboardPlugin } = useStartServices(); - useEffect(() => { - const fetchDashboard = async () => { + const { data, isLoading } = useQuery({ + queryKey: ['dashboard_exists', dashboardId], + queryFn: async () => { try { const findDashboardsService = await dashboardPlugin.findDashboardsService(); const [dashboard] = await findDashboardsService.findByIds([dashboardId]); - setLoading(false); - setDashboardExists(dashboard?.status === 'success'); + return dashboard?.status === 'success'; } catch (e) { - setLoading(false); - setDashboardExists(false); + return false; } - }; - - fetchDashboard(); - }, [dashboardId, dashboardPlugin]); - - return { dashboardExists, loading }; + }, + }); + return { dashboardExists: data ?? false, loading: isLoading }; }; export const DashboardsButtons: React.FunctionComponent = () => { + const { data } = useGetPackageInfoByKeyQuery(FLEET_ELASTIC_AGENT_PACKAGE); + const { spaceId } = useFleetStatus(); + const dashboardLocator = useDashboardLocator(); const getDashboardHref = (dashboardId: string) => { return dashboardLocator?.getRedirectUrl({ dashboardId }) || ''; }; - const { dashboardExists, loading: dashboardLoading } = useDashboardExists( + const elasticAgentOverviewDashboardId = getDashboardIdForSpace( + spaceId, + data, DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_OVERVIEW ); + const elasticAgentInfoDashboardId = getDashboardIdForSpace( + spaceId, + data, + DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_INFO + ); + + const { dashboardExists, loading: dashboardLoading } = useDashboardExists( + elasticAgentOverviewDashboardId + ); + if (dashboardLoading || !dashboardExists) { return null; } @@ -58,7 +78,7 @@ export const DashboardsButtons: React.FunctionComponent = () => { <EuiFlexItem grow={false}> <EuiButtonEmpty iconType="dashboardApp" - href={getDashboardHref(DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_OVERVIEW)} + href={getDashboardHref(elasticAgentOverviewDashboardId)} data-test-subj="ingestOverviewLinkButton" > <FormattedMessage @@ -70,7 +90,7 @@ export const DashboardsButtons: React.FunctionComponent = () => { <EuiFlexItem grow={false}> <EuiButtonEmpty iconType="dashboardApp" - href={getDashboardHref(DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_INFO)} + href={getDashboardHref(elasticAgentInfoDashboardId)} data-test-subj="agentInfoLinkButton" > <FormattedMessage diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx index fa8e263c1617..c7b71af5f97b 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/components/agent_health.tsx @@ -8,6 +8,7 @@ import React, { useMemo, useState } from 'react'; import styled from 'styled-components'; import { FormattedMessage, FormattedRelative } from '@kbn/i18n-react'; +import type { EuiBadgeProps } from '@elastic/eui'; import { EuiBadge, EuiButton, @@ -34,67 +35,75 @@ import { useAgentRefresh } from '../agent_details_page/hooks'; import { AgentUpgradeAgentModal } from './agent_upgrade_modal'; -interface Props { +type Props = EuiBadgeProps & { agent: Agent; fromDetails?: boolean; -} - -const Status = { - Healthy: ( - <EuiBadge color="success"> - <FormattedMessage id="xpack.fleet.agentHealth.healthyStatusText" defaultMessage="Healthy" /> - </EuiBadge> - ), - Offline: ( - <EuiBadge color="default"> - <FormattedMessage id="xpack.fleet.agentHealth.offlineStatusText" defaultMessage="Offline" /> - </EuiBadge> - ), - Inactive: ( - <EuiBadge color={euiVars.euiColorDarkShade}> - <FormattedMessage id="xpack.fleet.agentHealth.inactiveStatusText" defaultMessage="Inactive" /> - </EuiBadge> - ), - Unenrolled: ( - <EuiBadge color={euiVars.euiColorDisabled}> - <FormattedMessage - id="xpack.fleet.agentHealth.unenrolledStatusText" - defaultMessage="Unenrolled" - /> - </EuiBadge> - ), - Unhealthy: ( - <EuiBadge color="warning"> - <FormattedMessage - id="xpack.fleet.agentHealth.unhealthyStatusText" - defaultMessage="Unhealthy" - /> - </EuiBadge> - ), - Updating: ( - <EuiBadge color="primary"> - <FormattedMessage id="xpack.fleet.agentHealth.updatingStatusText" defaultMessage="Updating" /> - </EuiBadge> - ), }; -function getStatusComponent(status: Agent['status']): React.ReactElement { +function getStatusComponent({ + status, + ...restOfProps +}: { + status: Agent['status']; +} & EuiBadgeProps): React.ReactElement { switch (status) { case 'error': case 'degraded': - return Status.Unhealthy; + return ( + <EuiBadge color="warning" {...restOfProps}> + <FormattedMessage + id="xpack.fleet.agentHealth.unhealthyStatusText" + defaultMessage="Unhealthy" + /> + </EuiBadge> + ); case 'inactive': - return Status.Inactive; + return ( + <EuiBadge color={euiVars.euiColorDarkShade} {...restOfProps}> + <FormattedMessage + id="xpack.fleet.agentHealth.inactiveStatusText" + defaultMessage="Inactive" + /> + </EuiBadge> + ); case 'offline': - return Status.Offline; + return ( + <EuiBadge color="default" {...restOfProps}> + <FormattedMessage + id="xpack.fleet.agentHealth.offlineStatusText" + defaultMessage="Offline" + /> + </EuiBadge> + ); case 'unenrolling': case 'enrolling': case 'updating': - return Status.Updating; + return ( + <EuiBadge color="primary" {...restOfProps}> + <FormattedMessage + id="xpack.fleet.agentHealth.updatingStatusText" + defaultMessage="Updating" + /> + </EuiBadge> + ); case 'unenrolled': - return Status.Unenrolled; + return ( + <EuiBadge color={euiVars.euiColorDisabled} {...restOfProps}> + <FormattedMessage + id="xpack.fleet.agentHealth.unenrolledStatusText" + defaultMessage="Unenrolled" + /> + </EuiBadge> + ); default: - return Status.Healthy; + return ( + <EuiBadge color="success" {...restOfProps}> + <FormattedMessage + id="xpack.fleet.agentHealth.healthyStatusText" + defaultMessage="Healthy" + /> + </EuiBadge> + ); } } @@ -102,7 +111,11 @@ const WrappedEuiCallOut = styled(EuiCallOut)` white-space: wrap !important; `; -export const AgentHealth: React.FunctionComponent<Props> = ({ agent, fromDetails }) => { +export const AgentHealth: React.FunctionComponent<Props> = ({ + agent, + fromDetails, + ...restOfProps +}) => { const { last_checkin: lastCheckIn, last_checkin_message: lastCheckInMessage } = agent; const msLastCheckIn = new Date(lastCheckIn || 0).getTime(); const lastCheckInMessageText = lastCheckInMessage ? ( @@ -172,14 +185,16 @@ export const AgentHealth: React.FunctionComponent<Props> = ({ agent, fromDetails > {isStuckInUpdating(agent) && !fromDetails ? ( <div className="eui-textNoWrap"> - {getStatusComponent(agent.status)} + {getStatusComponent({ status: agent.status, ...restOfProps })}   <EuiIcon type="warning" color="warning" /> </div> ) : ( <> - {getStatusComponent(agent.status)} - {previousToOfflineStatus ? getStatusComponent(previousToOfflineStatus) : null} + {getStatusComponent({ status: agent.status, ...restOfProps })} + {previousToOfflineStatus + ? getStatusComponent({ status: previousToOfflineStatus, ...restOfProps }) + : null} </> )} </EuiToolTip> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helper.test.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helper.test.ts new file mode 100644 index 000000000000..cdf654cbeb70 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helper.test.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { GetInfoResponse } from '../../../../../../common'; + +import { getDashboardIdForSpace } from './dashboard_helpers'; + +const PKG_INFO = { + item: { + status: 'installed', + installationInfo: { + install_status: 'installed', + installed_kibana_space_id: 'default', + additional_spaces_installed_kibana: { + test: [ + { + id: 'test-destination-1', + originId: 'test-id-1', + }, + ], + }, + }, + }, +} as unknown as GetInfoResponse; + +describe('getDashboardIdForSpace', () => { + it('return the same id if package is installed in the same space', () => { + expect(() => getDashboardIdForSpace('default', PKG_INFO, 'test-id-1')); + }); + + it('return the destination ID if package is installed in an additionnal space', () => { + expect(() => getDashboardIdForSpace('test', PKG_INFO, 'test-id-1')); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts new file mode 100644 index 000000000000..bc46118b93fe --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; + +import type { GetInfoResponse } from '../../../../../../common'; + +export function getDashboardIdForSpace( + spaceId: string = DEFAULT_SPACE_ID, + res: GetInfoResponse | undefined, + dashboardId: string +) { + if (res?.item?.status !== 'installed') { + return dashboardId; + } + + const installationInfo = res.item.installationInfo; + + if (!installationInfo || installationInfo?.installed_kibana_space_id === spaceId) { + return dashboardId; + } + + return ( + installationInfo.additional_spaces_installed_kibana?.[spaceId]?.find( + ({ originId }) => originId === dashboardId + )?.id ?? dashboardId + ); +} diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/fleet_index_debugger.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/fleet_index_debugger.tsx index 887e58a5c618..80e07bfa1114 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/fleet_index_debugger.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/fleet_index_debugger.tsx @@ -31,7 +31,7 @@ import { ENROLLMENT_API_KEYS_INDEX } from '../../../constants'; import { CodeBlock } from './code_block'; const fetchIndex = async (index?: string) => { - if (!index) return; + if (!index) return null; const response = await sendRequest({ method: 'post', path: debugRoutesService.getIndexPath(), diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx index 4c4cdddd1f10..7f18ed6d1dc5 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_debugger.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useState, useRef } from 'react'; +import React, { useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { EuiFlexGroup, @@ -38,7 +38,7 @@ import { CodeBlock } from './code_block'; import { SavedObjectNamesCombo } from './saved_object_names_combo'; const fetchSavedObjects = async (type?: string, name?: string) => { - if (!type || !name) return; + if (!type || !name) return []; const response = await sendRequest({ method: 'post', @@ -101,12 +101,9 @@ export const SavedObjectDebugger: React.FunctionComponent = () => { const [name, setName] = useState<string | undefined>(); const [namesStatus, setNamesStatus] = useState(); - const childRef = useRef<{ refetchNames: Function }>(); - const onTypeChange = (e: any) => { setType(e.target.value); setName(undefined); - childRef.current!.refetchNames(); }; const { data: savedObjectResult, status } = useQuery(['debug-saved-objects', type, name], () => @@ -154,11 +151,10 @@ export const SavedObjectDebugger: React.FunctionComponent = () => { > <EuiFormRow> <SavedObjectNamesCombo - name={name!} + name={name} setName={setName} type={type} setNamesStatus={setNamesStatus} - ref={childRef} /> </EuiFormRow> </EuiFlexItem> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx index d7ddd8e2dd6a..6db9040f328a 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/components/saved_object_names_combo.tsx @@ -5,12 +5,13 @@ * 2.0. */ -import React, { forwardRef, useImperativeHandle } from 'react'; -import { useQuery } from '@tanstack/react-query'; +import React, { useEffect } from 'react'; import { EuiComboBox } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useQuery } from '@tanstack/react-query'; + import { sendRequest } from '../../../hooks'; import { debugRoutesService } from '../../../../../../common/services'; import { API_VERSIONS } from '../../../../../../common/constants'; @@ -30,62 +31,62 @@ const fetchSavedObjectNames = async (type: string) => { }; interface SavedObjectNamesComboProps { - name: string; + name?: string; setName: Function; type: string; setNamesStatus: Function; } -export const SavedObjectNamesCombo = forwardRef( - ({ name, setName, type, setNamesStatus }: SavedObjectNamesComboProps, ref) => { - const { - data: savedObjectNames, - refetch, - status, - } = useQuery(['debug-saved-object-names', type], () => fetchSavedObjectNames(type), { +export const SavedObjectNamesCombo: React.FunctionComponent<SavedObjectNamesComboProps> = ({ + name, + setName, + type, + setNamesStatus, +}) => { + const { data: savedObjectNames, status } = useQuery( + ['debug-saved-object-names', type], + () => fetchSavedObjectNames(type), + { refetchOnWindowFocus: false, - }); + } + ); - setNamesStatus?.(status); + useEffect(() => { + setNamesStatus(status); + }, [status, setNamesStatus]); - useImperativeHandle(ref, () => ({ - refetchNames: refetch, - })); + const comboBoxOptions = (savedObjectNames ?? []).map((obj: { key: string }) => ({ + label: obj.key, + value: obj.key, + })); - const comboBoxOptions = (savedObjectNames ?? []).map((obj: { key: string }) => ({ - label: obj.key, - value: obj.key, - })); + const selectedOption = comboBoxOptions.find( + (option: { value: string }) => option.value === name + )!; + const selectedOptions = selectedOption ? [selectedOption] : []; - const selectedOption = comboBoxOptions.find( - (option: { value: string }) => option.value === name - )!; - const selectedOptions = selectedOption ? [selectedOption] : []; - - return ( - <EuiComboBox - prepend="Name" - aria-label={i18n.translate( - 'xpack.fleet.debug.savedObjectDebugger.selectedSavedObjectLabel', - { defaultMessage: 'Select a Saved Object' } - )} - placeholder={i18n.translate( - 'xpack.fleet.debug.savedObjectDebugger.selectedSavedObjectLabel', - { defaultMessage: 'Select a Saved Object' } - )} - fullWidth - options={comboBoxOptions} - singleSelection={{ asPlainText: true }} - selectedOptions={selectedOptions} - isLoading={status === 'loading'} - onChange={(newSelectedOptions) => { - if (!newSelectedOptions.length) { - setName(undefined); - } else { - setName(newSelectedOptions[0].value as string); - } - }} - /> - ); - } -); + return ( + <EuiComboBox + prepend="Name" + aria-label={i18n.translate('xpack.fleet.debug.savedObjectDebugger.selectedSavedObjectLabel', { + defaultMessage: 'Select a Saved Object', + })} + placeholder={i18n.translate( + 'xpack.fleet.debug.savedObjectDebugger.selectedSavedObjectLabel', + { defaultMessage: 'Select a Saved Object' } + )} + fullWidth + options={comboBoxOptions} + singleSelection={{ asPlainText: true }} + selectedOptions={selectedOptions} + isLoading={status === 'loading'} + onChange={(newSelectedOptions) => { + if (!newSelectedOptions.length) { + setName(undefined); + } else { + setName(newSelectedOptions[0].value as string); + } + }} + /> + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/index.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/index.tsx index b510c66fb318..8961ed57e9ee 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/debug/index.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/debug/index.tsx @@ -162,7 +162,7 @@ export const DebugPage: React.FunctionComponent<{ <EuiSpacer size="m" /> <EuiPageSection> {panels.map(({ title, id, component }) => ( - <> + <div key={id}> <EuiAccordion id={id} initialIsOpen @@ -177,7 +177,7 @@ export const DebugPage: React.FunctionComponent<{ </EuiAccordion> <EuiHorizontalRule /> - </> + </div> ))} <EuiTitle size="l"> diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_health.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_health.test.tsx index a666dda3bac4..dbb830f1cccf 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_health.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/edit_output_flyout/output_health.test.tsx @@ -38,7 +38,9 @@ const mockUseStartServices = useStartServices as jest.Mock; const mockSendGetOutputHealth = sendGetOutputHealth as jest.Mock; -describe('OutputHealth', () => { +// FLAKY: https://github.com/elastic/kibana/issues/201412 +// FLAKY: https://github.com/elastic/kibana/issues/201068 +describe.skip('OutputHealth', () => { function render(output: Output, showBadge?: boolean) { const renderer = createFleetTestRendererMock(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx index f3fcdfabc772..bfd9028f5d0c 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/settings/components/multi_row_input/index.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { fireEvent, act } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../../../../../mock'; @@ -44,13 +44,9 @@ test('it should allow to add a new host', async () => { test('it should allow to remove an host', async () => { const { utils, mockOnChange } = renderInput(['http://host1.com', 'http://host2.com']); - await act(async () => { - const deleteRowEl = await utils.container.querySelector('[aria-label="Delete row"]'); - if (!deleteRowEl) { - throw new Error('Delete row button not found'); - } - fireEvent.click(deleteRowEl); - }); + const deleteRowEl = await utils.container.querySelector('[aria-label="Delete row"]'); + expect(deleteRowEl).not.toBeNull(); + fireEvent.click(deleteRowEl!); expect(mockOnChange).toHaveBeenCalledWith(['http://host2.com']); }); @@ -95,7 +91,7 @@ test('Should display errors in order', async () => { { message: 'Error 3', index: 2 }, ] ); - await act(async () => { + await waitFor(async () => { const errors = await utils.queryAllByText(/Error [1-3]/); expect(errors[0]).toHaveTextContent('Error 1'); expect(errors[1]).toHaveTextContent('Error 2'); @@ -126,18 +122,14 @@ test('Should remove error when item deleted', async () => { ); }); - await act(async () => { - const deleteRowButtons = await utils.container.querySelectorAll('[aria-label="Delete row"]'); - if (deleteRowButtons.length !== 3) { - throw new Error('Delete row buttons not found'); - } + const deleteRowButtons = await utils.container.querySelectorAll('[aria-label="Delete row"]'); + expect(deleteRowButtons.length).toEqual(3); - fireEvent.click(deleteRowButtons[1]); - expect(mockOnChange).toHaveBeenCalled(); + fireEvent.click(deleteRowButtons[1]); + expect(mockOnChange).toHaveBeenCalled(); - const renderedErrors = await utils.queryAllByText(/Error [1-3]/); - expect(renderedErrors).toHaveLength(2); - expect(renderedErrors[0]).toHaveTextContent('Error 1'); - expect(renderedErrors[1]).toHaveTextContent('Error 3'); - }); + const renderedErrors = await utils.queryAllByText(/Error [1-3]/); + expect(renderedErrors).toHaveLength(2); + expect(renderedErrors[0]).toHaveTextContent('Error 1'); + expect(renderedErrors[1]).toHaveTextContent('Error 3'); }); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx index 6c9be4796f20..400c5f3a5aa6 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.test.tsx @@ -7,7 +7,7 @@ import React, { lazy, memo } from 'react'; import { Route } from '@kbn/shared-ux-router'; -import { act, cleanup } from '@testing-library/react'; +import { act } from '@testing-library/react'; import { INTEGRATIONS_ROUTING_PATHS, pagePathGetters } from '../../../../constants'; import type { @@ -65,10 +65,6 @@ describe('When on integration detail', () => { act(() => testRenderer.mountHistory.push(detailPageUrlPath)); }); - afterEach(() => { - cleanup(); - }); - describe('and the package is installed', () => { beforeEach(async () => { await render(); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx index 9a707500bb03..0e7e6117d2cf 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/index.tsx @@ -846,7 +846,7 @@ export function Detail() { </Route> <Route path={INTEGRATIONS_ROUTING_PATHS.integration_details_policies}> {canReadIntegrationPolicies ? ( - <PackagePoliciesPage name={packageInfo.name} version={packageInfo.version} /> + <PackagePoliciesPage packageInfo={packageInfo} /> ) : ( <PermissionsError error="MISSING_PRIVILEGES" diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agent_based_table.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agent_based_table.test.tsx new file mode 100644 index 000000000000..77ce5720b294 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agent_based_table.test.tsx @@ -0,0 +1,126 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { screen, fireEvent, act } from '@testing-library/react'; + +import { createIntegrationsTestRendererMock } from '../../../../../../../../mock'; + +import { AgentBasedPackagePoliciesTable } from './agent_based_table'; + +const mockPackagePolicies = [ + { + agentPolicies: [ + { + id: '1', + name: 'Agent Policy 1', + status: 'active' as const, + is_managed: false, + is_protected: false, + updated_at: '2023-01-01T00:00:00Z', + updated_by: 'user', + created_at: '2023-01-01T00:00:00Z', + created_by: 'user', + namespace: 'default', + revision: 1, + monitoring_enabled: [], + }, + ], + packagePolicy: { + id: 'pkg1', + name: 'Package Policy 1', + package: { name: 'package-name', title: 'Package Title', version: '1.0.0' }, + hasUpgrade: true, + inputs: [], + revision: 1, + updated_at: '2023-01-01T00:00:00Z', + updated_by: 'user', + created_at: '2023-01-01T00:00:00Z', + created_by: 'user', + namespace: 'default', + policy_id: 'policy1', + policy_ids: ['policy1'], + enabled: true, + }, + rowIndex: 0, + }, +]; + +const mockPagination = { + pagination: { currentPage: 1, pageSize: 10, totalItemCount: 1, pageSizeOptions: [10, 20, 50] }, + setPagination: jest.fn(), + pageSizeOptions: [10, 20, 50], +}; + +describe('AgentBasedPackagePoliciesTable', () => { + it('renders the table with package policies', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render( + <AgentBasedPackagePoliciesTable + isLoading={false} + packagePolicies={mockPackagePolicies} + packagePoliciesTotal={1} + refreshPackagePolicies={jest.fn()} + pagination={mockPagination} + /> + ); + await act(async () => { + expect(result.getByText('Integration policy')).toBeInTheDocument(); + expect(result.getByText('Package Policy 1')).toBeInTheDocument(); + expect(result.getByText('v1.0.0')).toBeInTheDocument(); + }); + }); + + it('shows loading message when isLoading is true', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render( + <AgentBasedPackagePoliciesTable + isLoading={true} + packagePolicies={[]} + packagePoliciesTotal={0} + refreshPackagePolicies={jest.fn()} + pagination={mockPagination} + /> + ); + await act(async () => { + expect(result.getByText('Loading integration policies…')).toBeInTheDocument(); + }); + }); + + it('shows no policies message when there are no package policies', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render( + <AgentBasedPackagePoliciesTable + isLoading={false} + packagePolicies={[]} + packagePoliciesTotal={0} + refreshPackagePolicies={jest.fn()} + pagination={mockPagination} + /> + ); + await act(async () => { + expect(result.getByText('No integration policies')).toBeInTheDocument(); + }); + }); + + it('opens the agent enrollment flyout when add agent button is clicked', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render( + <AgentBasedPackagePoliciesTable + isLoading={false} + packagePolicies={mockPackagePolicies} + packagePoliciesTotal={1} + refreshPackagePolicies={jest.fn()} + pagination={mockPagination} + /> + ); + + await act(async () => { + fireEvent.click(screen.getByText('Add agent')); + }); + expect(result.getByTestId('agentEnrollmentFlyout')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agent_based_table.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agent_based_table.tsx new file mode 100644 index 000000000000..197fa84bf4dd --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agent_based_table.tsx @@ -0,0 +1,346 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { stringify, parse } from 'query-string'; +import React, { useEffect, useState } from 'react'; +import { useLocation, useHistory } from 'react-router-dom'; +import { + EuiBasicTable, + EuiLink, + EuiFlexGroup, + EuiFlexItem, + EuiText, + EuiButton, + EuiIcon, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedRelative, FormattedMessage } from '@kbn/i18n-react'; + +import type { AgentPolicy, InMemoryPackagePolicy, PackagePolicy } from '../../../../../../types'; +import type { usePagination } from '../../../../../../hooks'; +import { useLink, useAuthz, useMultipleAgentPolicies } from '../../../../../../hooks'; +import { + AgentEnrollmentFlyout, + MultipleAgentPoliciesSummaryLine, + AgentPolicySummaryLine, + PackagePolicyActionsMenu, +} from '../../../../../../components'; + +import { Persona } from '../persona'; + +import { PackagePolicyAgentsCell } from './package_policy_agents_cell'; + +export const AgentBasedPackagePoliciesTable = ({ + isLoading, + packagePolicies, + packagePoliciesTotal, + refreshPackagePolicies, + pagination, + addAgentToPolicyIdFromParams, + showAddAgentHelpForPolicyId, +}: { + isLoading: boolean; + packagePolicies: Array<{ + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }>; + packagePoliciesTotal: number; + refreshPackagePolicies: () => void; + pagination: ReturnType<typeof usePagination>; + addAgentToPolicyIdFromParams?: string | null; + showAddAgentHelpForPolicyId?: string | null; +}) => { + const { getHref } = useLink(); + const { search } = useLocation(); + const history = useHistory(); + + const [selectedTableIndex, setSelectedTableIndex] = useState<number | undefined>(); + const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); + const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies; + const canReadIntegrationPolicies = useAuthz().integrations.readIntegrationPolicies; + const canReadAgentPolicies = useAuthz().fleet.readAgentPolicies; + const canShowMultiplePoliciesCell = + canUseMultipleAgentPolicies && canReadIntegrationPolicies && canReadAgentPolicies; + + // Show tour help for adding agents to a policy + const addAgentHelpForPolicyId = packagePolicies.find(({ agentPolicies }) => + agentPolicies.find((agentPolicy) => agentPolicy.id === showAddAgentHelpForPolicyId) + )?.packagePolicy?.id; + + // Handle the "add agent" link displayed in post-installation toast notifications in the case + // where a user is clicking the link while on the package policies listing page + const [flyoutOpenForPolicyId, setFlyoutOpenForPolicyId] = useState<string | null>( + addAgentToPolicyIdFromParams || null + ); + useEffect(() => { + const unlisten = history.listen((location) => { + const params = new URLSearchParams(location.search); + const addAgentToPolicyId = params.get('addAgentToPolicyId'); + + if (addAgentToPolicyId) { + setFlyoutOpenForPolicyId(addAgentToPolicyId); + } + }); + + return () => unlisten(); + }, [history]); + + const selectedPolicies = + selectedTableIndex !== undefined ? packagePolicies[selectedTableIndex] : undefined; + const selectedAgentPolicies = selectedPolicies?.agentPolicies; + const selectedPackagePolicy = selectedPolicies?.packagePolicy; + const flyoutPolicy = selectedAgentPolicies?.length === 1 ? selectedAgentPolicies[0] : undefined; + + return ( + <> + <EuiBasicTable<{ + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }> + items={packagePolicies || []} + columns={[ + { + field: 'packagePolicy.name', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.name', { + defaultMessage: 'Integration policy', + }), + render(_, { agentPolicies, packagePolicy }) { + return ( + <EuiLink + className="eui-textTruncate" + data-test-subj="integrationNameLink" + href={getHref('integration_policy_edit', { + packagePolicyId: packagePolicy.id, + })} + > + {packagePolicy.name} + </EuiLink> + ); + }, + }, + { + field: 'packagePolicy.package.version', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.version', { + defaultMessage: 'Version', + }), + render(_version, { agentPolicies, packagePolicy }) { + return ( + <EuiFlexGroup gutterSize="s" alignItems="center" wrap={true}> + <EuiFlexItem grow={false}> + <EuiText + size="s" + className="eui-textNoWrap" + data-test-subj="packageVersionText" + > + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.packageVersion" + defaultMessage="v{version}" + values={{ version: _version }} + /> + </EuiText> + </EuiFlexItem> + + {agentPolicies.length > 0 && packagePolicy.hasUpgrade && ( + <EuiFlexItem grow={false}> + <EuiButton + size="s" + minWidth="0" + href={`${getHref('upgrade_package_policy', { + policyId: agentPolicies[0].id, + packagePolicyId: packagePolicy.id, + })}?from=integrations-policy-list`} + data-test-subj="integrationPolicyUpgradeBtn" + isDisabled={!canWriteIntegrationPolicies} + > + <FormattedMessage + id="xpack.fleet.policyDetails.packagePoliciesTable.upgradeButton" + defaultMessage="Upgrade" + /> + </EuiButton> + </EuiFlexItem> + )} + </EuiFlexGroup> + ); + }, + }, + { + field: 'packagePolicy.policy_ids', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentPolicy', { + defaultMessage: 'Agent policies', + }), + truncateText: true, + render(ids, { agentPolicies, packagePolicy }) { + return agentPolicies.length > 0 ? ( + canShowMultiplePoliciesCell ? ( + <MultipleAgentPoliciesSummaryLine + policies={agentPolicies} + packagePolicyId={packagePolicy.id} + onAgentPoliciesChange={refreshPackagePolicies} + /> + ) : ( + <AgentPolicySummaryLine policy={agentPolicies[0]} /> + ) + ) : ids.length === 0 ? ( + <EuiText color="subdued" size="xs"> + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.noAgentPolicies" + defaultMessage="No agent policies" + /> + </EuiText> + ) : ( + <EuiText color="subdued" size="xs"> + <EuiIcon size="m" type="warning" color="warning" /> +   + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.agentPolicyDeletedWarning" + defaultMessage="Policy not found" + /> + </EuiText> + ); + }, + }, + { + field: 'packagePolicy.updated_by', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedBy', { + defaultMessage: 'Last updated by', + }), + truncateText: true, + render(updatedBy: PackagePolicy['updated_by']) { + return <Persona size="s" name={updatedBy} title={updatedBy} />; + }, + }, + { + field: 'packagePolicy.updated_at', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedAt', { + defaultMessage: 'Last updated', + }), + truncateText: true, + render(updatedAt: PackagePolicy['updated_at']) { + return ( + <span className="eui-textTruncate" title={updatedAt}> + <FormattedRelative value={updatedAt} /> + </span> + ); + }, + }, + { + field: '', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentCount', { + defaultMessage: 'Agents', + }), + render({ + agentPolicies, + packagePolicy, + rowIndex, + }: { + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }) { + if (agentPolicies.length === 0) { + return ( + <EuiText color="subdued" size="xs"> + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.noAgents" + defaultMessage="No agents" + /> + </EuiText> + ); + } + return ( + <PackagePolicyAgentsCell + agentPolicies={agentPolicies} + onAddAgent={() => { + setSelectedTableIndex(rowIndex); + setFlyoutOpenForPolicyId(agentPolicies[0].id); + }} + hasHelpPopover={addAgentHelpForPolicyId === packagePolicy.id} + /> + ); + }, + }, + { + field: '', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.actions', { + defaultMessage: 'Actions', + }), + width: '8ch', + align: 'right', + render({ + agentPolicies, + packagePolicy, + }: { + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + }) { + const agentPolicy = agentPolicies[0]; // TODO: handle multiple agent policies + return ( + <PackagePolicyActionsMenu + agentPolicies={agentPolicies} + packagePolicy={packagePolicy} + showAddAgent={true} + upgradePackagePolicyHref={ + agentPolicy + ? `${getHref('upgrade_package_policy', { + policyId: agentPolicy.id, + packagePolicyId: packagePolicy.id, + })}?from=integrations-policy-list` + : undefined + } + /> + ); + }, + }, + ]} + loading={isLoading} + data-test-subj="integrationPolicyTable" + pagination={{ + pageIndex: pagination.pagination.currentPage - 1, + pageSize: pagination.pagination.pageSize, + totalItemCount: packagePoliciesTotal, + pageSizeOptions: pagination.pageSizeOptions, + }} + onChange={({ page }: { page: { index: number; size: number } }) => { + pagination.setPagination({ + currentPage: page.index + 1, + pageSize: page.size, + }); + }} + noItemsMessage={ + isLoading ? ( + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.loadingPoliciesMessage" + defaultMessage="Loading integration policies…" + /> + ) : ( + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.noPoliciesMessage" + defaultMessage="No integration policies" + /> + ) + } + /> + {flyoutOpenForPolicyId && selectedAgentPolicies && !isLoading && ( + <AgentEnrollmentFlyout + onClose={() => { + setFlyoutOpenForPolicyId(null); + const { addAgentToPolicyId, ...rest } = parse(search); + history.replace({ search: stringify(rest) }); + }} + agentPolicy={flyoutPolicy} + selectedAgentPolicies={selectedAgentPolicies} + isIntegrationFlow={true} + installedPackagePolicy={{ + name: selectedPackagePolicy?.package?.name || '', + version: selectedPackagePolicy?.package?.version || '', + }} + /> + )} + </> + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agentless_table.test.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agentless_table.test.tsx new file mode 100644 index 000000000000..25a9933fd719 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agentless_table.test.tsx @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { fireEvent, act, waitFor } from '@testing-library/react'; + +import { AGENTS_PREFIX } from '../../../../../../../../../common/constants'; +import { sendGetAgents } from '../../../../../../hooks'; +import { createIntegrationsTestRendererMock } from '../../../../../../../../mock'; + +import { AgentlessPackagePoliciesTable } from './agentless_table'; + +jest.mock('../../../../../../hooks', () => ({ + ...jest.requireActual('../../../../../../hooks'), + useConfirmForceInstall: jest.fn(), + sendGetAgents: jest.fn(), +})); + +describe('AgentlessPackagePoliciesTable', () => { + const mockSendGetAgents = sendGetAgents as jest.MockedFunction<typeof sendGetAgents>; + + beforeEach(() => { + mockSendGetAgents.mockResolvedValue({ + data: { + items: [ + { + policy_id: 'policy1', + id: 'agent1', + packages: ['package'], + type: 'PERMANENT', + active: true, + enrolled_at: '2023-01-01T00:00:00Z', + local_metadata: {}, + status: 'online', + }, + ], + total: 1, + page: 1, + perPage: 10000, + }, + error: null, + }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + const defaultProps = { + isLoading: false, + packagePolicies: [ + { + agentPolicies: [ + { + id: 'policy1', + name: 'Policy 1', + status: 'active' as const, + is_managed: false, + updated_at: '2023-01-01T00:00:00Z', + updated_by: 'user1', + namespace: 'default', + monitoring_enabled: [], + revision: 1, + is_protected: false, + }, + ], + packagePolicy: { + id: 'packagePolicy1', + name: 'Package Policy 1', + updated_by: 'user1', + updated_at: '2023-01-01T00:00:00Z', + inputs: [], + policy_id: 'policy1', + namespace: 'default', + enabled: true, + package: { + name: 'package', + title: 'Package', + version: '1.0.0', + }, + hasUpgrade: false, + revision: 1, + created_at: '2023-01-01T00:00:00Z', + created_by: 'user1', + policy_ids: ['policy1'], + }, + rowIndex: 0, + }, + ], + packagePoliciesTotal: 1, + refreshPackagePolicies: jest.fn(), + pagination: { + pagination: { currentPage: 1, pageSize: 10 }, + setPagination: jest.fn(), + pageSizeOptions: [10, 20, 50], + }, + }; + + it('shows loading message when isLoading is true', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render( + <AgentlessPackagePoliciesTable {...defaultProps} packagePolicies={[]} isLoading={true} /> + ); + await act(async () => { + expect(result.getByText('Loading integration policies…')).toBeInTheDocument(); + }); + }); + + it('shows no items message when there are no package policies', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render( + <AgentlessPackagePoliciesTable {...defaultProps} packagePolicies={[]} /> + ); + await act(async () => { + expect(result.getByText('No agentless integration policies')).toBeInTheDocument(); + }); + }); + + it('renders the table with package policies', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render(<AgentlessPackagePoliciesTable {...defaultProps} />); + + await act(async () => { + expect(result.getByText('Package Policy 1')).toBeInTheDocument(); + expect(result.getByText('user1')).toBeInTheDocument(); + }); + }); + + it('displays agent health status when agents are loaded', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render(<AgentlessPackagePoliciesTable {...defaultProps} />); + await waitFor(() => { + expect(mockSendGetAgents).toHaveBeenCalledWith({ + perPage: 10000, + kuery: `${AGENTS_PREFIX}.policy_id: "policy1"`, + }); + }); + expect(await result.findByText('Healthy')).toBeInTheDocument(); + }); + + it('opens flyout when status badge is clicked', async () => { + const renderer = createIntegrationsTestRendererMock(); + const result = renderer.render(<AgentlessPackagePoliciesTable {...defaultProps} />); + await waitFor(() => { + expect(mockSendGetAgents).toHaveBeenCalledWith({ + perPage: 10000, + kuery: `${AGENTS_PREFIX}.policy_id: "policy1"`, + }); + }); + await act(async () => { + fireEvent.click(await result.findByText('Healthy')); + }); + expect(result.getByText('Confirm agentless enrollment')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agentless_table.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agentless_table.tsx new file mode 100644 index 000000000000..22348f137c51 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/components/agentless_table.tsx @@ -0,0 +1,300 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useEffect, useMemo, useState } from 'react'; +import type { HorizontalAlignment } from '@elastic/eui'; +import { EuiBadge, EuiBasicTable, EuiLink } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedRelative, FormattedMessage } from '@kbn/i18n-react'; + +import type { + Agent, + AgentPolicy, + InMemoryPackagePolicy, + PackagePolicy, +} from '../../../../../../types'; +import { AGENTS_PREFIX, SO_SEARCH_LIMIT } from '../../../../../../../../../common/constants'; +import type { usePagination } from '../../../../../../hooks'; +import { useLink, sendGetAgents, useAuthz, useStartServices } from '../../../../../../hooks'; +import { + Loading, + PackagePolicyActionsMenu, + AgentlessEnrollmentFlyout, +} from '../../../../../../components'; + +import { Persona } from '../persona'; +import { AgentHealth } from '../../../../../../../fleet/sections/agents/components'; + +const REFRESH_INTERVAL_MS = 30000; + +export const AgentlessPackagePoliciesTable = ({ + isLoading, + packagePolicies, + packagePoliciesTotal, + refreshPackagePolicies, + pagination, +}: { + isLoading: boolean; + packagePolicies: Array<{ + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }>; + packagePoliciesTotal: number; + refreshPackagePolicies: () => void; + pagination: ReturnType<typeof usePagination>; +}) => { + const core = useStartServices(); + const { notifications } = core; + const authz = useAuthz(); + const { getHref } = useLink(); + const [isAgentsLoading, setIsAgentsLoading] = useState<boolean>(false); + const [agentsByPolicyId, setAgentsByPolicyId] = useState<Record<string, Agent>>({}); + const canReadAgents = authz.fleet.readAgents; + + // Kuery for all agents enrolled into the agent policies associated with the package policies + // We use the first agent policy as agentless package policies have a 1:1 relationship with agent policies + // Maximum # of agent policies is 50, based on the max page size in UI + const agentsKuery = useMemo(() => { + return packagePolicies + .reduce((policyIds, { agentPolicies }) => { + return [...policyIds, ...(agentPolicies[0] ? [agentPolicies[0]?.id] : [])]; + }, [] as string[]) + .map((policyId) => `${AGENTS_PREFIX}.policy_id: "${policyId}"`) + .join(' or '); + }, [packagePolicies]); + + // Fetch agents using above kuery, if the user has access to read agents + // Polls every 30 seconds + useEffect(() => { + const fetchAgents = async () => { + const { data: agentsData, error } = await sendGetAgents({ + perPage: SO_SEARCH_LIMIT, + kuery: agentsKuery, + }); + + setAgentsByPolicyId( + (agentsData?.items || []).reduce((acc, agent) => { + if (agent.policy_id) { + acc[agent.policy_id] = agent; + } + return acc; + }, {} as Record<string, Agent>) + ); + + if (error) { + notifications.toasts.addError(error, { + title: i18n.translate( + 'xpack.fleet.epm.packageDetails.integrationList.agentlessStatusError', + { + defaultMessage: 'Error fetching agentless status information', + } + ), + }); + } + setIsAgentsLoading(false); + }; + + if (canReadAgents) { + setIsAgentsLoading(true); + fetchAgents(); + const interval = setInterval(() => { + fetchAgents(); + }, REFRESH_INTERVAL_MS); + return () => clearInterval(interval); + } + }, [agentsKuery, canReadAgents, notifications.toasts]); + + // Flyout state + const [flyoutOpenForPolicyId, setFlyoutOpenForPolicyId] = useState<string>(); + const [flyoutPackagePolicy, setFlyoutPackagePolicy] = useState<PackagePolicy>(); + const [flyoutAgentPolicy, setFlyoutAgentPolicy] = useState<AgentPolicy>(); + + return ( + <> + <EuiBasicTable<{ + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }> + items={packagePolicies || []} + columns={[ + { + field: 'packagePolicy.name', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.name', { + defaultMessage: 'Integration policy', + }), + render(_, { agentPolicies, packagePolicy }) { + return ( + <EuiLink + className="eui-textTruncate" + data-test-subj="agentlessIntegrationNameLink" + href={getHref('integration_policy_edit', { + packagePolicyId: packagePolicy.id, + })} + > + {packagePolicy.name} + </EuiLink> + ); + }, + }, + { + field: 'packagePolicy.updated_by', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedBy', { + defaultMessage: 'Last updated by', + }), + truncateText: true, + render(updatedBy: PackagePolicy['updated_by']) { + return <Persona size="s" name={updatedBy} title={updatedBy} />; + }, + }, + { + field: 'packagePolicy.updated_at', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedAt', { + defaultMessage: 'Last updated', + }), + truncateText: true, + render(updatedAt: PackagePolicy['updated_at']) { + return ( + <span className="eui-textTruncate" title={updatedAt}> + <FormattedRelative value={updatedAt} /> + </span> + ); + }, + }, + ...(canReadAgents + ? [ + { + field: '', + name: i18n.translate( + 'xpack.fleet.epm.packageDetails.integrationList.agentlessStatus', + { + defaultMessage: 'Status', + } + ), + align: 'left' as HorizontalAlignment, + render({ + agentPolicies, + packagePolicy, + }: { + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }) { + if (isAgentsLoading) { + return <Loading size="s" />; + } + // Use the first agent policy ID associated with the package policy + // because agentless package policies are only associated with one agent policy + const agentPolicy = agentPolicies[0]; + const agent = + (agentPolicy?.id && agentsByPolicyId[agentPolicy.id]) || undefined; + + // Status badge click handler + const statusBadgeProps = { + onClick: () => { + setFlyoutOpenForPolicyId(packagePolicy.id); + setFlyoutPackagePolicy(packagePolicy); + setFlyoutAgentPolicy(agentPolicy); + }, + 'data-test-subj': 'agentlessStatusBadge', + onClickAriaLabel: i18n.translate( + 'xpack.fleet.epm.packageDetails.integrationList.agentlessStatusAriaLabel', + { + defaultMessage: 'Open status details', + } + ), + }; + + return agent ? ( + <AgentHealth agent={agent} {...statusBadgeProps} /> + ) : ( + <EuiBadge color="default" {...statusBadgeProps}> + <FormattedMessage + id="xpack.fleet.packageDetails.integrationList.pendingAgentlessStatus" + defaultMessage="Pending" + /> + </EuiBadge> + ); + }, + }, + ] + : []), + { + field: '', + name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.actions', { + defaultMessage: 'Actions', + }), + width: '8ch', + align: 'right' as HorizontalAlignment, + render({ + agentPolicies, + packagePolicy, + }: { + agentPolicies: AgentPolicy[]; + packagePolicy: InMemoryPackagePolicy; + }) { + const agentPolicy = agentPolicies[0]; // TODO: handle multiple agent policies + return ( + <PackagePolicyActionsMenu + agentPolicies={agentPolicies} + packagePolicy={packagePolicy} + showAddAgent={true} + upgradePackagePolicyHref={ + agentPolicy + ? `${getHref('upgrade_package_policy', { + policyId: agentPolicy.id, + packagePolicyId: packagePolicy.id, + })}?from=integrations-policy-list` + : undefined + } + /> + ); + }, + }, + ]} + loading={isLoading} + data-test-subj="integrationPolicyTable" + pagination={{ + pageIndex: pagination.pagination.currentPage - 1, + pageSize: pagination.pagination.pageSize, + totalItemCount: packagePoliciesTotal, + pageSizeOptions: pagination.pageSizeOptions, + }} + onChange={({ page }: { page: { index: number; size: number } }) => { + pagination.setPagination({ + currentPage: page.index + 1, + pageSize: page.size, + }); + }} + noItemsMessage={ + isLoading ? ( + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.loadingPoliciesMessage" + defaultMessage="Loading integration policies…" + /> + ) : ( + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.noAgentlessPoliciesMessage" + defaultMessage="No agentless integration policies" + /> + ) + } + /> + {flyoutOpenForPolicyId && flyoutPackagePolicy && ( + <AgentlessEnrollmentFlyout + onClose={() => { + setFlyoutOpenForPolicyId(undefined); + setFlyoutPackagePolicy(undefined); + setFlyoutAgentPolicy(undefined); + }} + packagePolicy={flyoutPackagePolicy} + agentPolicy={flyoutAgentPolicy} + /> + )} + </> + ); +}; diff --git a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx index 300de597f690..06096b1c3de5 100644 --- a/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx +++ b/x-pack/plugins/fleet/public/applications/integrations/sections/epm/screens/detail/policies/package_policies.tsx @@ -4,80 +4,49 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { stringify, parse } from 'query-string'; -import React, { memo, useCallback, useEffect, useMemo, useState } from 'react'; -import { Redirect, useLocation, useHistory } from 'react-router-dom'; -import type { CriteriaWithPagination, EuiTableFieldDataColumnType } from '@elastic/eui'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import { Redirect, useLocation } from 'react-router-dom'; import { - EuiBasicTable, - EuiLink, + EuiAccordion, EuiFlexGroup, EuiFlexItem, + EuiNotificationBadge, + EuiPanel, + EuiSpacer, EuiText, - EuiButton, - EuiIcon, } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import { FormattedRelative, FormattedMessage } from '@kbn/i18n-react'; + +import { FormattedMessage } from '@kbn/i18n-react'; import { InstallStatus } from '../../../../../types'; -import type { GetAgentPoliciesResponseItem, InMemoryPackagePolicy } from '../../../../../types'; +import type { + AgentPolicy, + GetAgentPoliciesResponseItem, + InMemoryPackagePolicy, + PackageInfo, + PackagePolicy, +} from '../../../../../types'; import { useLink, - useUrlPagination, useGetPackageInstallStatus, AgentPolicyRefreshContext, useIsPackagePolicyUpgradable, - useAuthz, - useMultipleAgentPolicies, + usePagination, } from '../../../../../hooks'; import { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../../../constants'; -import { - AgentEnrollmentFlyout, - MultipleAgentPoliciesSummaryLine, - AgentPolicySummaryLine, - PackagePolicyActionsMenu, -} from '../../../../../components'; import { SideBarColumn } from '../../../components/side_bar_column'; -import { PackagePolicyAgentsCell } from './components/package_policy_agents_cell'; -import { usePackagePoliciesWithAgentPolicy } from './use_package_policies_with_agent_policy'; -import { Persona } from './persona'; - -interface PackagePoliciesPanelProps { - name: string; - version: string; -} - -interface InMemoryPackagePolicyAndAgentPolicy { - packagePolicy: InMemoryPackagePolicy; - agentPolicies: GetAgentPoliciesResponseItem[]; - rowIndex: number; -} +import { useAgentless } from '../../../../../../fleet/sections/agent_policy/create_package_policy_page/single_page_layout/hooks/setup_technology'; -const IntegrationDetailsLink = memo<{ - packagePolicy: InMemoryPackagePolicyAndAgentPolicy['packagePolicy']; - agentPolicies: InMemoryPackagePolicyAndAgentPolicy['agentPolicies']; -}>(({ packagePolicy }) => { - const { getHref } = useLink(); - return ( - <EuiLink - className="eui-textTruncate" - data-test-subj="integrationNameLink" - href={getHref('integration_policy_edit', { - packagePolicyId: packagePolicy.id, - })} - > - {packagePolicy.name} - </EuiLink> - ); -}); +import { usePackagePoliciesWithAgentPolicy } from './use_package_policies_with_agent_policy'; +import { AgentBasedPackagePoliciesTable } from './components/agent_based_table'; +import { AgentlessPackagePoliciesTable } from './components/agentless_table'; -export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps) => { +export const PackagePoliciesPage = ({ packageInfo }: { packageInfo: PackageInfo }) => { + const { name, version } = packageInfo; const { search } = useLocation(); - const history = useHistory(); const queryParams = useMemo(() => new URLSearchParams(search), [search]); - const agentPolicyIdFromParams = useMemo( + const addAgentToPolicyIdFromParams = useMemo( () => queryParams.get('addAgentToPolicyId'), [queryParams] ); @@ -85,44 +54,27 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps () => queryParams.get('showAddAgentHelpForPolicyId'), [queryParams] ); - const [flyoutOpenForPolicyId, setFlyoutOpenForPolicyId] = useState<string | null>( - agentPolicyIdFromParams - ); - const [selectedTableIndex, setSelectedTableIndex] = useState<number | undefined>(); - - const { getPath, getHref } = useLink(); + const { getPath } = useLink(); const getPackageInstallStatus = useGetPackageInstallStatus(); const packageInstallStatus = getPackageInstallStatus(name); - const { pagination, pageSizeOptions, setPagination } = useUrlPagination(); - const { canUseMultipleAgentPolicies } = useMultipleAgentPolicies(); - const { - data, - isLoading, - resendRequest: refreshPolicies, - } = usePackagePoliciesWithAgentPolicy({ - page: pagination.currentPage, - perPage: pagination.pageSize, - kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: ${name}`, - }); const { isPackagePolicyUpgradable } = useIsPackagePolicyUpgradable(); + const { isAgentlessIntegration } = useAgentless(); + const canHaveAgentlessPolicies = useMemo( + () => isAgentlessIntegration(packageInfo), + [isAgentlessIntegration, packageInfo] + ); - const canWriteIntegrationPolicies = useAuthz().integrations.writeIntegrationPolicies; - const canReadIntegrationPolicies = useAuthz().integrations.readIntegrationPolicies; - const canReadAgentPolicies = useAuthz().fleet.readAgentPolicies; - - const packageAndAgentPolicies = useMemo((): Array<{ - agentPolicies: GetAgentPoliciesResponseItem[]; - packagePolicy: InMemoryPackagePolicy; - rowIndex: number; - }> => { - if (!data?.items) { - return []; - } - - const newPolicies = data.items.map(({ agentPolicies, packagePolicy }, index) => { + // Helper function to map raw policies data for consumption by the table + const mapPoliciesData = useCallback( + ( + { + agentPolicies, + packagePolicy, + }: { agentPolicies: AgentPolicy[]; packagePolicy: PackagePolicy }, + index: number + ) => { const hasUpgrade = isPackagePolicyUpgradable(packagePolicy); - return { agentPolicies, packagePolicy: { @@ -131,284 +83,204 @@ export const PackagePoliciesPage = ({ name, version }: PackagePoliciesPanelProps }, rowIndex: index, }; - }); - - return newPolicies; - }, [data?.items, isPackagePolicyUpgradable]); - - const showAddAgentHelpForPackagePolicyId = packageAndAgentPolicies.find(({ agentPolicies }) => - agentPolicies.find((agentPolicy) => agentPolicy.id === showAddAgentHelpForPolicyId) - )?.packagePolicy?.id; - // Handle the "add agent" link displayed in post-installation toast notifications in the case - // where a user is clicking the link while on the package policies listing page - useEffect(() => { - const unlisten = history.listen((location) => { - const params = new URLSearchParams(location.search); - const addAgentToPolicyId = params.get('addAgentToPolicyId'); - - if (addAgentToPolicyId) { - setFlyoutOpenForPolicyId(addAgentToPolicyId); - } - }); - - return () => unlisten(); - }, [history]); - - const handleTableOnChange = useCallback( - ({ page }: CriteriaWithPagination<InMemoryPackagePolicyAndAgentPolicy>) => { - setPagination({ - currentPage: page.index + 1, - pageSize: page.size, - }); }, - [setPagination] + [isPackagePolicyUpgradable] ); - const canShowMultiplePoliciesCell = - canUseMultipleAgentPolicies && canReadIntegrationPolicies && canReadAgentPolicies; - const columns: Array<EuiTableFieldDataColumnType<InMemoryPackagePolicyAndAgentPolicy>> = useMemo( - () => [ - { - field: 'packagePolicy.name', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.name', { - defaultMessage: 'Integration policy', - }), - render(_, { agentPolicies, packagePolicy }) { - return ( - <IntegrationDetailsLink packagePolicy={packagePolicy} agentPolicies={agentPolicies} /> - ); - }, - }, - { - field: 'packagePolicy.package.version', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.version', { - defaultMessage: 'Version', - }), - render(_version, { agentPolicies, packagePolicy }) { - return ( - <EuiFlexGroup gutterSize="s" alignItems="center" wrap={true}> - <EuiFlexItem grow={false}> - <EuiText size="s" className="eui-textNoWrap" data-test-subj="packageVersionText"> - <FormattedMessage - id="xpack.fleet.epm.packageDetails.integrationList.packageVersion" - defaultMessage="v{version}" - values={{ version: _version }} - /> - </EuiText> - </EuiFlexItem> - {agentPolicies.length > 0 && packagePolicy.hasUpgrade && ( - <EuiFlexItem grow={false}> - <EuiButton - size="s" - minWidth="0" - href={`${getHref('upgrade_package_policy', { - policyId: agentPolicies[0].id, - packagePolicyId: packagePolicy.id, - })}?from=integrations-policy-list`} - data-test-subj="integrationPolicyUpgradeBtn" - isDisabled={!canWriteIntegrationPolicies} - > - <FormattedMessage - id="xpack.fleet.policyDetails.packagePoliciesTable.upgradeButton" - defaultMessage="Upgrade" - /> - </EuiButton> - </EuiFlexItem> - )} - </EuiFlexGroup> - ); - }, - }, - { - field: 'packagePolicy.policy_ids', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentPolicy', { - defaultMessage: 'Agent policies', - }), - truncateText: true, - render(ids, { agentPolicies, packagePolicy }) { - return agentPolicies.length > 0 ? ( - canShowMultiplePoliciesCell ? ( - <MultipleAgentPoliciesSummaryLine - policies={agentPolicies} - packagePolicyId={packagePolicy.id} - onAgentPoliciesChange={refreshPolicies} - /> - ) : ( - <AgentPolicySummaryLine policy={agentPolicies[0]} /> - ) - ) : ids.length === 0 ? ( - <EuiText color="subdued" size="xs"> - <FormattedMessage - id="xpack.fleet.epm.packageDetails.integrationList.noAgentPolicies" - defaultMessage="No agent policies" - /> - </EuiText> - ) : ( - <EuiText color="subdued" size="xs"> - <EuiIcon size="m" type="warning" color="warning" /> -   - <FormattedMessage - id="xpack.fleet.epm.packageDetails.integrationList.agentPolicyDeletedWarning" - defaultMessage="Policy not found" - /> - </EuiText> - ); - }, - }, - { - field: 'packagePolicy.updated_by', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedBy', { - defaultMessage: 'Last updated by', - }), - truncateText: true, - render(updatedBy) { - return <Persona size="s" name={updatedBy} title={updatedBy} />; - }, - }, - { - field: 'packagePolicy.updated_at', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.updatedAt', { - defaultMessage: 'Last updated', - }), - truncateText: true, - render(updatedAt: InMemoryPackagePolicyAndAgentPolicy['packagePolicy']['updated_at']) { - return ( - <span className="eui-textTruncate" title={updatedAt}> - <FormattedRelative value={updatedAt} /> - </span> - ); - }, - }, - { - field: '', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.agentCount', { - defaultMessage: 'Agents', - }), - render({ agentPolicies, packagePolicy, rowIndex }: InMemoryPackagePolicyAndAgentPolicy) { - if (agentPolicies.length === 0) { - return ( - <EuiText color="subdued" size="xs"> - <FormattedMessage - id="xpack.fleet.epm.packageDetails.integrationList.noAgents" - defaultMessage="No agents" - /> - </EuiText> - ); - } - return ( - <PackagePolicyAgentsCell - agentPolicies={agentPolicies} - onAddAgent={() => { - setSelectedTableIndex(rowIndex); - setFlyoutOpenForPolicyId(agentPolicies[0].id); - }} - hasHelpPopover={showAddAgentHelpForPackagePolicyId === packagePolicy.id} - /> - ); - }, - }, - { - field: '', - name: i18n.translate('xpack.fleet.epm.packageDetails.integrationList.actions', { - defaultMessage: 'Actions', - }), - width: '8ch', - align: 'right', - render({ agentPolicies, packagePolicy }) { - const agentPolicy = agentPolicies[0]; // TODO: handle multiple agent policies - return ( - <PackagePolicyActionsMenu - agentPolicies={agentPolicies} - packagePolicy={packagePolicy} - showAddAgent={true} - upgradePackagePolicyHref={ - agentPolicy - ? `${getHref('upgrade_package_policy', { - policyId: agentPolicy.id, - packagePolicyId: packagePolicy.id, - })}?from=integrations-policy-list` - : undefined - } - /> - ); - }, - }, - ], - [ - getHref, - canWriteIntegrationPolicies, - canShowMultiplePoliciesCell, - showAddAgentHelpForPackagePolicyId, - refreshPolicies, - ] - ); - - const noItemsMessage = useMemo(() => { - return isLoading ? ( - <FormattedMessage - id="xpack.fleet.epm.packageDetails.integrationList.loadingPoliciesMessage" - defaultMessage="Loading integration policies…" - /> - ) : undefined; - }, [isLoading]); + // States and data for agent-based policies table + // If agentless is not supported or not an agentless integration, skip the + // conditional in the kuery + const { + pagination: agentBasedPagination, + pageSizeOptions: agentBasedPageSizeOptions, + setPagination: agentBasedSetPagination, + } = usePagination(); + const [agentBasedPackageAndAgentPolicies, setAgentBasedPackageAndAgentPolicies] = useState< + Array<{ + agentPolicies: GetAgentPoliciesResponseItem[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }> + >([]); + const { + data: agentBasedData, + isLoading: agentBasedIsLoading, + resendRequest: refreshAgentBasedPolicies, + } = usePackagePoliciesWithAgentPolicy({ + page: agentBasedPagination.currentPage, + perPage: agentBasedPagination.pageSize, + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: "${name}" ${ + canHaveAgentlessPolicies + ? `AND NOT ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.supports_agentless: true` + : `` + }`, + }); + useEffect(() => { + setAgentBasedPackageAndAgentPolicies( + !agentBasedData?.items ? [] : agentBasedData.items.map(mapPoliciesData) + ); + }, [agentBasedData, mapPoliciesData]); - const tablePagination = useMemo(() => { - return { - pageIndex: pagination.currentPage - 1, - pageSize: pagination.pageSize, - totalItemCount: data?.total ?? 0, - pageSizeOptions, - }; - }, [data?.total, pageSizeOptions, pagination.currentPage, pagination.pageSize]); + // States and data for agentless policies table + // If agentless is not supported or not an agentless integration, this block and + // initial request is unnessary but reduces code complexity + const { + pagination: agentlessPagination, + pageSizeOptions: agentlessPageSizeOptions, + setPagination: agentlessSetPagination, + } = usePagination(); + const [agentlessPackageAndAgentPolicies, setAgentlessPackageAndAgentPolicies] = useState< + Array<{ + agentPolicies: GetAgentPoliciesResponseItem[]; + packagePolicy: InMemoryPackagePolicy; + rowIndex: number; + }> + >([]); + const { + data: agentlessData, + isLoading: agentlessIsLoading, + resendRequest: refreshAgentlessPolicies, + } = usePackagePoliciesWithAgentPolicy({ + page: agentlessPagination.currentPage, + perPage: agentlessPagination.pageSize, + kuery: `${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.package.name: "${name}" AND ${PACKAGE_POLICY_SAVED_OBJECT_TYPE}.supports_agentless: true`, + }); + useEffect(() => { + setAgentlessPackageAndAgentPolicies( + !agentlessData?.items ? [] : agentlessData.items.map(mapPoliciesData) + ); + }, [agentlessData, mapPoliciesData]); // if they arrive at this page and the package is not installed, send them to overview // this happens if they arrive with a direct url or they uninstall while on this tab - // Check flyoutOpenForPolicyId otherwise right after installing a new integration the flyout won't open - if (packageInstallStatus.status !== InstallStatus.installed && !flyoutOpenForPolicyId) { + // Check `addAgentToPolicyIdFromParams` otherwise right after installing a new integration the flyout won't open + if (packageInstallStatus.status !== InstallStatus.installed && !addAgentToPolicyIdFromParams) { return ( <Redirect to={getPath('integration_details_overview', { pkgkey: `${name}-${version}` })} /> ); } - const selectedPolicies = - selectedTableIndex !== undefined ? packageAndAgentPolicies[selectedTableIndex] : undefined; - - const agentPolicies = selectedPolicies?.agentPolicies; - const packagePolicy = selectedPolicies?.packagePolicy; - const flyoutPolicy = agentPolicies?.length === 1 ? agentPolicies[0] : undefined; - return ( - <AgentPolicyRefreshContext.Provider value={{ refresh: refreshPolicies }}> + <AgentPolicyRefreshContext.Provider + value={{ + refresh: () => { + refreshAgentBasedPolicies(); + refreshAgentlessPolicies(); + }, + }} + > <EuiFlexGroup alignItems="flexStart"> <SideBarColumn grow={1} /> <EuiFlexItem grow={7}> - <EuiBasicTable - items={packageAndAgentPolicies || []} - columns={columns} - loading={isLoading} - data-test-subj="integrationPolicyTable" - pagination={tablePagination} - onChange={handleTableOnChange} - noItemsMessage={noItemsMessage} - /> + {!canHaveAgentlessPolicies ? ( + <AgentBasedPackagePoliciesTable + isLoading={agentBasedIsLoading} + packagePolicies={agentBasedPackageAndAgentPolicies} + packagePoliciesTotal={agentBasedData?.total ?? 0} + refreshPackagePolicies={refreshAgentBasedPolicies} + pagination={{ + pagination: agentBasedPagination, + pageSizeOptions: agentBasedPageSizeOptions, + setPagination: agentBasedSetPagination, + }} + addAgentToPolicyIdFromParams={addAgentToPolicyIdFromParams} + showAddAgentHelpForPolicyId={showAddAgentHelpForPolicyId} + /> + ) : ( + <> + <EuiAccordion + id="agentBasedAccordion" + initialIsOpen={true} + buttonContent={ + <EuiFlexGroup + justifyContent="center" + alignItems="center" + gutterSize="s" + responsive={false} + > + <EuiFlexItem grow={false}> + <EuiText size="m"> + <h3> + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.agentlessHeader" + defaultMessage="Agentless" + /> + </h3> + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiNotificationBadge color="subdued" size="m"> + <h3>{agentlessData?.total ?? 0}</h3> + </EuiNotificationBadge> + </EuiFlexItem> + </EuiFlexGroup> + } + > + <EuiSpacer size="m" /> + <EuiPanel hasBorder={true} hasShadow={false}> + <AgentlessPackagePoliciesTable + isLoading={agentlessIsLoading} + packagePolicies={agentlessPackageAndAgentPolicies} + packagePoliciesTotal={agentlessData?.total ?? 0} + refreshPackagePolicies={refreshAgentlessPolicies} + pagination={{ + pagination: agentlessPagination, + pageSizeOptions: agentlessPageSizeOptions, + setPagination: agentlessSetPagination, + }} + /> + </EuiPanel> + </EuiAccordion> + <EuiSpacer size="l" /> + <EuiAccordion + id="agentBasedAccordion" + initialIsOpen={true} + buttonContent={ + <EuiFlexGroup + justifyContent="center" + alignItems="center" + gutterSize="s" + responsive={false} + > + <EuiFlexItem grow={false}> + <EuiText size="m"> + <h3> + <FormattedMessage + id="xpack.fleet.epm.packageDetails.integrationList.agentBasedHeader" + defaultMessage="Agent-based" + /> + </h3> + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiNotificationBadge color="subdued" size="m"> + <h3>{agentBasedData?.total ?? 0}</h3> + </EuiNotificationBadge> + </EuiFlexItem> + </EuiFlexGroup> + } + > + <EuiSpacer size="m" /> + <EuiPanel hasBorder={true} hasShadow={false}> + <AgentBasedPackagePoliciesTable + isLoading={agentBasedIsLoading} + packagePolicies={agentBasedPackageAndAgentPolicies} + packagePoliciesTotal={agentBasedData?.total ?? 0} + refreshPackagePolicies={refreshAgentBasedPolicies} + pagination={{ + pagination: agentBasedPagination, + pageSizeOptions: agentBasedPageSizeOptions, + setPagination: agentBasedSetPagination, + }} + addAgentToPolicyIdFromParams={addAgentToPolicyIdFromParams} + showAddAgentHelpForPolicyId={showAddAgentHelpForPolicyId} + /> + </EuiPanel> + </EuiAccordion> + </> + )} </EuiFlexItem> </EuiFlexGroup> - {flyoutOpenForPolicyId && agentPolicies && !isLoading && ( - <AgentEnrollmentFlyout - onClose={() => { - setFlyoutOpenForPolicyId(null); - const { addAgentToPolicyId, ...rest } = parse(search); - history.replace({ search: stringify(rest) }); - }} - agentPolicy={flyoutPolicy} - selectedAgentPolicies={agentPolicies} - isIntegrationFlow={true} - installedPackagePolicy={{ - name: packagePolicy?.package?.name || '', - version: packagePolicy?.package?.version || '', - }} - /> - )} </AgentPolicyRefreshContext.Provider> ); }; diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx index 19709c55665f..13ecfc228222 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/agent_enrollment_flyout.test.tsx @@ -8,7 +8,7 @@ import './agent_enrollment_flyout.test.mocks'; import React from 'react'; -import { act, cleanup, fireEvent, waitFor } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import type { RenderResult } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../mock'; @@ -23,11 +23,8 @@ import type { FlyOutProps } from './types'; import { AgentEnrollmentFlyout } from '.'; const render = (props?: Partial<FlyOutProps>) => { - cleanup(); const renderer = createFleetTestRendererMock(); - const results = renderer.render(<AgentEnrollmentFlyout onClose={jest.fn()} {...props} />); - - return results; + return renderer.render(<AgentEnrollmentFlyout onClose={jest.fn()} {...props} />); }; const testAgentPolicy: AgentPolicy = { @@ -46,7 +43,7 @@ const testAgentPolicy: AgentPolicy = { describe('<AgentEnrollmentFlyout />', () => { let results: RenderResult; - beforeEach(async () => { + beforeEach(() => { jest.mocked(useAuthz).mockReturnValue({ fleet: { readAgentPolicies: true, @@ -88,10 +85,6 @@ describe('<AgentEnrollmentFlyout />', () => { agentPolicies: [{ id: 'fleet-server-policy' } as AgentPolicy], refreshAgentPolicies: jest.fn(), }); - - act(() => { - results = render(); - }); }); afterEach(() => { @@ -113,6 +106,8 @@ describe('<AgentEnrollmentFlyout />', () => { describe('managed instructions', () => { it('uses the agent policy selection step', () => { + results = render(); + expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); expect(results.queryByTestId('agent-policy-selection-step')).not.toBeNull(); expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); @@ -154,24 +149,22 @@ describe('<AgentEnrollmentFlyout />', () => { describe('standalone instructions', () => { function goToStandaloneTab() { - act(() => { - fireEvent.click(results.getByTestId('standaloneTab')); - }); + fireEvent.click(results.getByTestId('standaloneTab')); } - beforeEach(() => { + it('uses the agent policy selection step', async () => { results = render({ isIntegrationFlow: true, }); - }); - it('uses the agent policy selection step', async () => { goToStandaloneTab(); - expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); - expect(results.queryByTestId('agent-policy-selection-step')).not.toBeNull(); - expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); - expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + await waitFor(() => { + expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); + expect(results.queryByTestId('agent-policy-selection-step')).not.toBeNull(); + expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); + expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + }); }); describe('with a specific policy', () => { @@ -185,13 +178,15 @@ describe('<AgentEnrollmentFlyout />', () => { }); }); - it('does not use either of the agent policy selection or enrollment key steps', () => { + it('does not use either of the agent policy selection or enrollment key steps', async () => { goToStandaloneTab(); - expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); - expect(results.queryByTestId('agent-policy-selection-step')).toBeNull(); - expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); - expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + await waitFor(() => { + expect(results.queryByTestId('agentEnrollmentFlyout')).not.toBeNull(); + expect(results.queryByTestId('agent-policy-selection-step')).toBeNull(); + expect(results.queryByTestId('agent-enrollment-key-selection-step')).toBeNull(); + expect(results.queryByTestId('configure-standalone-step')).not.toBeNull(); + }); }); }); }); diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_incoming_data.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_incoming_data.tsx index 2a111e5d638a..412b221e88d4 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_incoming_data.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/confirm_incoming_data.tsx @@ -30,7 +30,7 @@ export const ConfirmIncomingData: React.FunctionComponent<Props> = ({ setAgentDataConfirmed, troubleshootLink, }) => { - const { incomingData, isLoading } = usePollingIncomingData(agentIds); + const { incomingData, isLoading } = usePollingIncomingData({ agentIds }); const isGuidedOnboardingActive = useIsGuidedOnboardingActive(installedPolicy?.name); const { guidedOnboarding } = useStartServices(); diff --git a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/use_get_agent_incoming_data.tsx b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/use_get_agent_incoming_data.tsx index 19034151d80a..be08dbd186e5 100644 --- a/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/use_get_agent_incoming_data.tsx +++ b/x-pack/plugins/fleet/public/components/agent_enrollment_flyout/use_get_agent_incoming_data.tsx @@ -75,18 +75,26 @@ export const useGetAgentIncomingData = ( }; const POLLING_INTERVAL_MS = 5 * 1000; // 5 sec -const POLLING_TIMEOUT_MS = 5 * 60 * 1000; // 5 min +export const POLLING_TIMEOUT_MS = 5 * 60 * 1000; // 5 min /** - * Hook for polling incoming data for the selected agent policy. + * Hook for polling incoming data for the selected agent(s). * @param agentIds * @returns incomingData, isLoading */ -export const usePollingIncomingData = ( - agentIds: string[], - previewData?: boolean, - stopPollingAfterPreviewLength: number = 0 -) => { +export const usePollingIncomingData = ({ + agentIds, + pkgName, + pkgVersion, + previewData, + stopPollingAfterPreviewLength = 0, +}: { + agentIds: string[]; + pkgName?: string; + pkgVersion?: string; + previewData?: boolean; + stopPollingAfterPreviewLength?: number; +}) => { const timeout = useRef<number | undefined>(undefined); const [result, setResult] = useState<{ incomingData: IncomingDataList[]; @@ -117,7 +125,12 @@ export const usePollingIncomingData = ( setHasReachedTimeout(true); } - const { data } = await sendGetAgentIncomingData({ agentsIds: agentIds, previewData }); + const { data } = await sendGetAgentIncomingData({ + agentsIds: agentIds, + previewData, + pkgName, + pkgVersion, + }); if (data?.items) { // filter out agents that have `data = false` and keep polling const filtered = data?.items.filter((item) => { @@ -153,7 +166,15 @@ export const usePollingIncomingData = ( return () => { isAborted = true; }; - }, [agentIds, result, previewData, stopPollingAfterPreviewLength, startedPollingAt]); + }, [ + agentIds, + result, + previewData, + stopPollingAfterPreviewLength, + startedPollingAt, + pkgName, + pkgVersion, + ]); return { ...result, diff --git a/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/index.test.tsx b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/index.test.tsx new file mode 100644 index 000000000000..fc63c8c88e9c --- /dev/null +++ b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/index.test.tsx @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { waitFor } from '@testing-library/react'; + +import { sendGetAgents, useGetPackageInfoByKeyQuery } from '../../hooks'; +import { usePollingIncomingData } from '../agent_enrollment_flyout/use_get_agent_incoming_data'; +import { createIntegrationsTestRendererMock } from '../../mock'; + +import { AGENTS_PREFIX } from '../../constants'; + +import type { PackagePolicy } from '../../types'; + +import { AgentlessEnrollmentFlyout } from '.'; + +jest.mock('../../hooks', () => ({ + ...jest.requireActual('../../hooks'), + useGetPackageInfoByKeyQuery: jest.fn(), + sendGetAgents: jest.fn(), +})); + +jest.mock('../agent_enrollment_flyout/use_get_agent_incoming_data', () => ({ + usePollingIncomingData: jest.fn(), +})); + +const mockSendGetAgents = sendGetAgents as jest.Mock; +const mockUseGetPackageInfoByKeyQuery = useGetPackageInfoByKeyQuery as jest.Mock; +const mockUsePollingIncomingData = usePollingIncomingData as jest.Mock; + +// FLAKY: https://github.com/elastic/kibana/issues/201738 +describe.skip('AgentlessEnrollmentFlyout', () => { + const onClose = jest.fn(); + const packagePolicy: PackagePolicy = { + id: 'test-package-policy-id', + name: 'test-package-policy', + namespace: 'default', + policy_ids: ['test-policy-id'], + policy_id: 'test-policy-id', + enabled: true, + output_id: '', + package: { name: 'test-package', title: 'Test Package', version: '1.0.0' }, + inputs: [{ enabled: true, policy_template: 'test-template', type: 'test-type', streams: [] }], + revision: 1, + created_at: '', + created_by: '', + updated_at: '', + updated_by: '', + }; + + beforeEach(() => { + mockSendGetAgents.mockResolvedValue({ data: { items: [] } }); + mockUseGetPackageInfoByKeyQuery.mockReturnValue({ data: { item: { title: 'Test Package' } } }); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('renders the flyout with initial loading state', async () => { + const renderer = createIntegrationsTestRendererMock(); + const { getByText } = renderer.render( + <AgentlessEnrollmentFlyout onClose={onClose} packagePolicy={packagePolicy} /> + ); + await waitFor(async () => { + expect(getByText('Confirm agentless enrollment')).toBeInTheDocument(); + expect(getByText('Step 1 is loading')).toBeInTheDocument(); + expect( + getByText('Listening for agentless connection... this could take several minutes') + ).toBeInTheDocument(); + expect(getByText('Confirm incoming data')).toBeInTheDocument(); + expect(getByText('Step 2 is disabled')).toBeInTheDocument(); + }); + }); + + it('updates step statuses when agent deployment fails', async () => { + const renderer = createIntegrationsTestRendererMock(); + const agentData = { status: 'error' }; + mockSendGetAgents.mockResolvedValueOnce({ data: { items: [agentData] } }); + + const { getByText } = renderer.render( + <AgentlessEnrollmentFlyout onClose={onClose} packagePolicy={packagePolicy} /> + ); + + await waitFor(() => { + expect(getByText('Confirm agentless enrollment')).toBeInTheDocument(); + expect(getByText('Step 1 has errors')).toBeInTheDocument(); + expect(getByText('Agentless deployment failed')).toBeInTheDocument(); + expect(getByText('Confirm incoming data')).toBeInTheDocument(); + expect(getByText('Step 2 is disabled')).toBeInTheDocument(); + }); + }); + + it('fetches agents data on mount and sets step statuses when agent deployment succeeds', async () => { + const renderer = createIntegrationsTestRendererMock(); + const agentData = { status: 'online' }; + mockSendGetAgents.mockResolvedValueOnce({ data: { items: [agentData] } }); + mockUsePollingIncomingData.mockReturnValue({ incomingData: [], hasReachedTimeout: false }); + + const { getByText } = renderer.render( + <AgentlessEnrollmentFlyout onClose={onClose} packagePolicy={packagePolicy} /> + ); + + await waitFor(() => { + expect(mockSendGetAgents).toHaveBeenCalledWith({ + kuery: `${AGENTS_PREFIX}.policy_id: "test-policy-id"`, + }); + expect(getByText('Confirm agentless enrollment')).toBeInTheDocument(); + expect(getByText('Step 1 is complete')).toBeInTheDocument(); + expect(getByText('Agentless deployment was successful')).toBeInTheDocument(); + expect(getByText('Confirm incoming data')).toBeInTheDocument(); + expect(getByText('Step 2 is loading')).toBeInTheDocument(); + }); + }); + + it('shows confirm data step as failed when timeout has been reached', async () => { + const renderer = createIntegrationsTestRendererMock(); + mockSendGetAgents.mockResolvedValueOnce({ data: { items: [{ status: 'online' }] } }); + mockUsePollingIncomingData.mockReturnValue({ incomingData: [], hasReachedTimeout: true }); + + const { getByText } = renderer.render( + <AgentlessEnrollmentFlyout onClose={onClose} packagePolicy={packagePolicy} /> + ); + + await waitFor(() => { + expect(getByText('Step 1 is complete')).toBeInTheDocument(); + expect(getByText('Confirm incoming data')).toBeInTheDocument(); + expect(getByText('Step 2 has errors')).toBeInTheDocument(); + expect(getByText('No incoming data received from agentless integration')).toBeInTheDocument(); + }); + }); + + it('shows confirm data step as successful when incoming data is received', async () => { + const renderer = createIntegrationsTestRendererMock(); + mockSendGetAgents.mockResolvedValueOnce({ data: { items: [{ status: 'online' }] } }); + mockUsePollingIncomingData.mockReturnValue({ incomingData: [{ data: 'test-data' }] }); + + const { getByText } = renderer.render( + <AgentlessEnrollmentFlyout onClose={onClose} packagePolicy={packagePolicy} /> + ); + + await waitFor(() => { + expect(getByText('Step 1 is complete')).toBeInTheDocument(); + expect(getByText('Confirm incoming data')).toBeInTheDocument(); + expect(getByText('Step 2 is complete')).toBeInTheDocument(); + expect(getByText('Incoming data received from agentless integration')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/index.tsx b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/index.tsx new file mode 100644 index 000000000000..0fbf8d278fab --- /dev/null +++ b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/index.tsx @@ -0,0 +1,212 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import type { EuiStepStatus } from '@elastic/eui'; +import { + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiFlyoutFooter, + EuiSteps, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; + +import { AGENTS_PREFIX, MAX_FLYOUT_WIDTH } from '../../constants'; +import type { Agent, AgentPolicy, PackagePolicy } from '../../types'; +import { sendGetAgents, useStartServices, useGetPackageInfoByKeyQuery } from '../../hooks'; + +import { AgentlessStepConfirmEnrollment } from './step_confirm_enrollment'; +import { AgentlessStepConfirmData } from './step_confirm_data'; + +const REFRESH_INTERVAL_MS = 30000; + +/** + * This component displays additional status details of an agentless agent enrolled + * the chosen package policy (and its agent policy). + * It also displays confirmation that the agentless agent is ingesting data from + * the chosen package policy. + */ +export const AgentlessEnrollmentFlyout = ({ + onClose, + packagePolicy, + agentPolicy, +}: { + onClose: () => void; + packagePolicy: PackagePolicy; + agentPolicy?: AgentPolicy; +}) => { + const core = useStartServices(); + const { notifications } = core; + const [confirmEnrollmentStatus, setConfirmEnrollmentStatus] = useState<EuiStepStatus>('loading'); + const [confirmDataStatus, setConfirmDataStatus] = useState<EuiStepStatus>('disabled'); + const [agentData, setAgentData] = useState<Agent>(); + + // Clear agent data polling + // Called when component is unmounted or when agent is healthy + const agentDataInterval = useRef<NodeJS.Timeout>(); + const clearAgentDataPolling = useMemo(() => { + return () => { + if (agentDataInterval.current) { + clearInterval(agentDataInterval.current); + } + }; + }, [agentDataInterval]); + + // Fetch agent(s) data for the first associated agent policy + // Polls every 30 seconds until agent is found and healthy + useEffect(() => { + const fetchAgents = async () => { + const { data: agentsData, error } = await sendGetAgents({ + kuery: `${AGENTS_PREFIX}.policy_id: "${packagePolicy.policy_ids[0]}"`, + }); + + if (error) { + notifications.toasts.addError(error, { + title: i18n.translate( + 'xpack.fleet.epm.packageDetails.integrationList.agentlessStatusError', + { + defaultMessage: 'Error fetching agentless status information', + } + ), + }); + } + + if (agentsData?.items?.[0]) { + setAgentData(agentsData.items?.[0]); + } + }; + + fetchAgents(); + agentDataInterval.current = setInterval(() => { + fetchAgents(); + }, REFRESH_INTERVAL_MS); + + return () => clearAgentDataPolling(); + }, [clearAgentDataPolling, notifications.toasts, packagePolicy.policy_ids]); + + // Watches agent data and updates step statuses and clears polling when agent is healthy + useEffect(() => { + if (agentData) { + if (agentData.status === 'online') { + setConfirmEnrollmentStatus('complete'); + setConfirmDataStatus('loading'); + clearAgentDataPolling(); + } else if (agentData.status === 'error' || agentData.status === 'degraded') { + setConfirmEnrollmentStatus('danger'); + setConfirmDataStatus('disabled'); + } else { + setConfirmEnrollmentStatus('loading'); + setConfirmDataStatus('disabled'); + } + } else { + setConfirmEnrollmentStatus('loading'); + setConfirmDataStatus('disabled'); + } + }, [agentData, clearAgentDataPolling]); + + // Calculate integration title from the base package info and what + // is configured on the package policy. + const { data: packageInfoData } = useGetPackageInfoByKeyQuery( + packagePolicy.package!.name, + packagePolicy.package!.version, + { + prerelease: true, + } + ); + + const integrationTitle = useMemo(() => { + if (packageInfoData?.item) { + const enabledInputs = packagePolicy.inputs?.filter((input) => input.enabled); + + // If only one input is enabled, find the input name from the package info and + // and use that for integration title. Otherwise, use the package name. + if (enabledInputs.length === 1 && enabledInputs[0].policy_template) { + const policyTemplate = packageInfoData.item.policy_templates?.find( + (template) => template.name === enabledInputs[0].policy_template + ); + const input = + policyTemplate && 'inputs' in policyTemplate + ? policyTemplate.inputs?.find((i) => i.type === enabledInputs[0].type) + : null; + return input?.title || packageInfoData.item.title; + } else { + return packageInfoData.item.title; + } + } + return packagePolicy.name; + }, [packageInfoData, packagePolicy]); + + return ( + <EuiFlyout + data-test-subj="agentlessEnrollmentFlyout" + onClose={onClose} + maxWidth={MAX_FLYOUT_WIDTH} + > + <EuiFlyoutHeader hasBorder aria-labelledby="FleetAgentlessEnrollmentFlyoutTitle"> + <EuiTitle size="m"> + <h2 id="FleetAgentlessEnrollmentFlyoutTitle">{packagePolicy.name}</h2> + </EuiTitle> + </EuiFlyoutHeader> + <EuiFlyoutBody> + <EuiSteps + steps={[ + { + title: i18n.translate( + 'xpack.fleet.agentlessEnrollmentFlyout.stepConfirmEnrollmentTitle', + { + defaultMessage: 'Confirm agentless enrollment', + } + ), + children: ( + <AgentlessStepConfirmEnrollment + agent={agentData} + agentPolicy={agentPolicy} + integrationTitle={integrationTitle} + /> + ), + status: confirmEnrollmentStatus, + }, + { + title: i18n.translate('xpack.fleet.agentlessEnrollmentFlyout.stepConfirmDataTitle', { + defaultMessage: 'Confirm incoming data', + }), + children: + agentData && confirmEnrollmentStatus === 'complete' ? ( + <AgentlessStepConfirmData + agent={agentData} + packagePolicy={packagePolicy} + setConfirmDataStatus={setConfirmDataStatus} + /> + ) : ( + <></> // Avoids React error about null children prop + ), + status: confirmDataStatus, + }, + ]} + /> + </EuiFlyoutBody> + <EuiFlyoutFooter> + <EuiFlexGroup justifyContent="flexStart"> + <EuiFlexItem grow={false}> + <EuiButtonEmpty onClick={onClose}> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.closeFlyoutButtonLabel" + defaultMessage="Close" + /> + </EuiButtonEmpty> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlyoutFooter> + </EuiFlyout> + ); +}; diff --git a/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/step_confirm_data.tsx b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/step_confirm_data.tsx new file mode 100644 index 000000000000..34e69d8ef839 --- /dev/null +++ b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/step_confirm_data.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { EuiStepStatus } from '@elastic/eui'; +import { EuiText, EuiLink, EuiSpacer, EuiCallOut } from '@elastic/eui'; + +import { useStartServices } from '../../hooks'; +import type { Agent, PackagePolicy } from '../../types'; +import { + usePollingIncomingData, + POLLING_TIMEOUT_MS, +} from '../agent_enrollment_flyout/use_get_agent_incoming_data'; + +export const AgentlessStepConfirmData = ({ + agent, + packagePolicy, + setConfirmDataStatus, +}: { + agent: Agent; + packagePolicy: PackagePolicy; + setConfirmDataStatus: (status: EuiStepStatus) => void; +}) => { + const { docLinks } = useStartServices(); + const [overallState, setOverallState] = useState<'pending' | 'success' | 'failure'>('pending'); + + // Fetch integration data for the given agent and package policy + const { incomingData, hasReachedTimeout } = usePollingIncomingData({ + agentIds: [agent.id], + pkgName: packagePolicy.package!.name, + pkgVersion: packagePolicy.package!.version, + }); + + // Calculate overall UI state from polling data + useEffect(() => { + if (incomingData.length > 0) { + setConfirmDataStatus('complete'); + setOverallState('success'); + } else if (hasReachedTimeout) { + setConfirmDataStatus('danger'); + setOverallState('failure'); + } else { + setConfirmDataStatus('loading'); + setOverallState('pending'); + } + }, [incomingData, hasReachedTimeout, setConfirmDataStatus]); + + if (overallState === 'success') { + return ( + <EuiCallOut + color="success" + title={i18n.translate('xpack.fleet.agentlessEnrollmentFlyout.confirmData.successText', { + defaultMessage: 'Incoming data received from agentless integration', + })} + iconType="check" + /> + ); + } else if (overallState === 'failure') { + return ( + <> + <EuiCallOut + color="danger" + title={i18n.translate('xpack.fleet.agentlessEnrollmentFlyout.confirmData.failureText', { + defaultMessage: 'No incoming data received from agentless integration', + })} + iconType="warning" + /> + <EuiSpacer size="m" /> + <EuiText> + <p> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmData.failureHelperText" + defaultMessage="No integration data receieved in the past {num} minutes. Check out the {troubleshootingGuideLink} for help." + values={{ + num: POLLING_TIMEOUT_MS / 1000 / 60, + troubleshootingGuideLink: ( + <EuiLink href={docLinks.links.fleet.troubleshooting} target="_blank"> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmData.pendingHelperText.troubleshootingLinkLabel" + defaultMessage="troubleshooting guide" + /> + </EuiLink> + ), + }} + /> + </p> + </EuiText> + </> + ); + } + + return null; +}; diff --git a/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/step_confirm_enrollment.tsx b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/step_confirm_enrollment.tsx new file mode 100644 index 000000000000..f8a5832e0487 --- /dev/null +++ b/x-pack/plugins/fleet/public/components/agentless_enrollment_flyout/step_confirm_enrollment.tsx @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiButton, EuiPanel, EuiText, EuiLink, EuiSpacer, EuiCallOut } from '@elastic/eui'; + +import type { Agent, AgentPolicy } from '../../types'; +import { useStartServices } from '../../hooks'; +import { AgentDetailsIntegrations } from '../../applications/fleet/sections/agents/agent_details_page/components/agent_details/agent_details_integrations'; + +export const AgentlessStepConfirmEnrollment = ({ + agent, + agentPolicy, + integrationTitle, +}: { + agent?: Agent; + agentPolicy?: AgentPolicy; + integrationTitle: string; +}) => { + const { docLinks } = useStartServices(); + const [overallState, setOverallState] = useState<'pending' | 'success' | 'failure'>('pending'); + + // Calculate overall UI state from agent status + useEffect(() => { + if (agent && agent.status === 'online') { + setOverallState('success'); + } else if (agent && (agent.status === 'error' || agent.status === 'degraded')) { + setOverallState('failure'); + } else { + setOverallState('pending'); + } + }, [agent]); + + if (overallState === 'success') { + return ( + <> + <EuiCallOut + color="success" + title={i18n.translate( + 'xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.successText', + { + defaultMessage: 'Agentless deployment was successful', + } + )} + iconType="check" + /> + <EuiSpacer size="m" /> + <EuiText> + <p> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.successHelperText" + defaultMessage="{integrationTitle} agentless integration has been successfully established. You can now seamlessly monitor and manage your {integrationTitle} resources without the need for any additional agents." + values={{ + integrationTitle, + }} + /> + </p> + </EuiText> + </> + ); + } else if (overallState === 'failure') { + return ( + <> + <EuiCallOut + color="danger" + title={i18n.translate( + 'xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.failureText', + { + defaultMessage: 'Agentless deployment failed', + } + )} + iconType="warning" + > + {agent?.last_checkin_message && <p>{agent.last_checkin_message}</p>} + </EuiCallOut> + <EuiSpacer size="m" /> + <EuiText> + <p> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.failureHelperText" + defaultMessage="{integrationTitle} agentless integration failed to establish. Check out the {troubleshootingGuideLink} for help." + values={{ + integrationTitle, + troubleshootingGuideLink: ( + <EuiLink href={docLinks.links.fleet.troubleshooting} target="_blank"> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.pendingHelperText.troubleshootingLinkLabel" + defaultMessage="troubleshooting guide" + /> + </EuiLink> + ), + }} + /> + </p> + </EuiText> + {agent && agentPolicy && ( + <> + <EuiSpacer size="m" /> + <AgentDetailsIntegrations agent={agent} agentPolicy={agentPolicy} linkToLogs={false} /> + </> + )} + </> + ); + } + + return ( + <> + <EuiPanel color="subdued" paddingSize="xl" className="eui-textCenter"> + <EuiButton disabled={true} size="s" isLoading={true}> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.pendingText" + defaultMessage="Listening for agentless connection... this could take several minutes" + /> + </EuiButton> + </EuiPanel> + <EuiSpacer size="m" /> + <EuiText> + <p> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.pendingHelperText" + defaultMessage="Getting ready to connect with your cloud account and confirm incoming data. If you're having trouble connecting, check out the {troubleshootingGuideLink}. You can track the latest status from {policyPagePath} Status column." + values={{ + troubleshootingGuideLink: ( + <EuiLink href={docLinks.links.fleet.troubleshooting} target="_blank"> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.pendingHelperText.troubleshootingLinkLabel" + defaultMessage="troubleshooting guide" + /> + </EuiLink> + ), + policyPagePath: ( + <strong> + <FormattedMessage + id="xpack.fleet.agentlessEnrollmentFlyout.confirmEnrollment.pendingHelperText.policyPagePath" + defaultMessage="Integration policies → Agentless Integrations" + /> + </strong> + ), + }} + /> + </p> + </EuiText> + </> + ); +}; diff --git a/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx b/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx index ae7e62773cb6..6cf1f68673ac 100644 --- a/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx +++ b/x-pack/plugins/fleet/public/components/enrollment_instructions/root_privileges_callout.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { cleanup, waitFor } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import { createFleetTestRendererMock } from '../../mock'; @@ -15,7 +15,6 @@ import { RootPrivilegesCallout } from './root_privileges_callout'; describe('RootPrivilegesCallout', () => { function render(rootIntegrations?: Array<{ name: string; title: string }>) { - cleanup(); const renderer = createFleetTestRendererMock(); const results = renderer.render(<RootPrivilegesCallout rootIntegrations={rootIntegrations} />); diff --git a/x-pack/plugins/fleet/public/components/index.ts b/x-pack/plugins/fleet/public/components/index.ts index 5a995ab1ecbc..39dcfa3e3cd6 100644 --- a/x-pack/plugins/fleet/public/components/index.ts +++ b/x-pack/plugins/fleet/public/components/index.ts @@ -29,3 +29,4 @@ export { HeaderReleaseBadge, InlineReleaseBadge } from './release_badge'; export { WithGuidedOnboardingTour } from './with_guided_onboarding_tour'; export { UninstallCommandFlyout } from './uninstall_command_flyout'; export { MultipleAgentPoliciesSummaryLine } from './multiple_agent_policy_summary_line'; +export { AgentlessEnrollmentFlyout } from './agentless_enrollment_flyout'; diff --git a/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx b/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx index 100a6f67ad83..22efe3f84d43 100644 --- a/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx +++ b/x-pack/plugins/fleet/public/components/multiple_agent_policy_summary_line.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, fireEvent } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import React from 'react'; import type { TestRenderer } from '../mock'; @@ -31,7 +31,7 @@ describe('MultipleAgentPolicySummaryLine', () => { testRenderer = createFleetTestRendererMock(); }); - test('it should only render the policy name when there is only one policy', async () => { + test('it should only render the policy name when there is only one policy', () => { const results = render([{ name: 'Test policy', revision: 2 }] as AgentPolicy[]); expect(results.container.textContent).toBe('Test policyrev. 2'); expect(results.queryByTestId('agentPolicyNameLink')).toBeInTheDocument(); @@ -48,19 +48,18 @@ describe('MultipleAgentPolicySummaryLine', () => { expect(results.queryByTestId('agentPoliciesNumberBadge')).toBeInTheDocument(); expect(results.container.textContent).toBe('Test policy 1+2'); - await act(async () => { - fireEvent.click(results.getByTestId('agentPoliciesNumberBadge')); - }); - expect(results.queryByTestId('agentPoliciesPopover')).toBeInTheDocument(); - expect(results.queryByTestId('agentPoliciesPopoverButton')).toBeInTheDocument(); - expect(results.queryByTestId('policy-0001')).toBeInTheDocument(); - expect(results.queryByTestId('policy-0002')).toBeInTheDocument(); - expect(results.queryByTestId('policy-0003')).toBeInTheDocument(); + fireEvent.click(results.getByTestId('agentPoliciesNumberBadge')); - await act(async () => { - fireEvent.click(results.getByTestId('agentPoliciesPopoverButton')); + await waitFor(() => { + expect(results.queryByTestId('agentPoliciesPopover')).toBeInTheDocument(); + expect(results.queryByTestId('agentPoliciesPopoverButton')).toBeInTheDocument(); + expect(results.queryByTestId('policy-0001')).toBeInTheDocument(); + expect(results.queryByTestId('policy-0002')).toBeInTheDocument(); + expect(results.queryByTestId('policy-0003')).toBeInTheDocument(); }); + fireEvent.click(results.getByTestId('agentPoliciesPopoverButton')); + expect(results.queryByTestId('manageAgentPoliciesModal')).toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx index f016acf8783a..3c4b2c7f1bf3 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { act } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; import type { AgentPolicy, InMemoryPackagePolicy } from '../types'; import { createIntegrationsTestRendererMock } from '../mock'; @@ -109,19 +109,19 @@ function createMockPackagePolicy( ...props, }; } -// FLAKY: https://github.com/elastic/kibana/issues/191804 -describe.skip('PackagePolicyActionsMenu', () => { + +describe('PackagePolicyActionsMenu', () => { beforeAll(() => { useMultipleAgentPoliciesMock.mockReturnValue({ canUseMultipleAgentPolicies: false }); }); - it('Should disable upgrade button if package does not have upgrade', async () => { + it('Should not have upgrade button if package does not have upgrade', async () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy({ hasUpgrade: false }); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { - const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); - expect(upgradeButton).toBeDisabled(); + + await waitFor(() => { + expect(utils.queryByTestId('PackagePolicyActionsUpgradeItem')).toBeNull(); }); }); @@ -130,7 +130,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); expect(upgradeButton).not.toBeDisabled(); }); @@ -141,7 +141,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { const upgradeButton = utils.getByTestId('PackagePolicyActionsUpgradeItem'); expect(upgradeButton).toBeDisabled(); }); @@ -151,7 +151,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: true }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Delete integration')).toBeNull(); }); }); @@ -160,7 +160,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: false }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Delete integration')).not.toBeNull(); }); }); @@ -169,7 +169,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: false, supports_agentless: true }); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Delete integration')).not.toBeNull(); }); }); @@ -178,7 +178,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Add agent')).not.toBeNull(); }); }); @@ -187,7 +187,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ is_managed: true }); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Add agent')).toBeNull(); }); }); @@ -196,7 +196,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies({ supports_agentless: true }); const packagePolicy = createMockPackagePolicy({ hasUpgrade: true }); const { utils } = renderMenu({ agentPolicies, packagePolicy, showAddAgent: true }); - await act(async () => { + await waitFor(() => { expect(utils.queryByText('Add agent')).toBeNull(); }); }); @@ -205,7 +205,7 @@ describe.skip('PackagePolicyActionsMenu', () => { const agentPolicies = createMockAgentPolicies(); const packagePolicy = createMockPackagePolicy(); const { utils } = renderMenu({ agentPolicies, packagePolicy }); - await act(async () => { + await waitFor(() => { const editButton = utils.getByTestId('PackagePolicyActionsEditItem'); expect(editButton).not.toHaveAttribute('disabled'); expect(editButton).toHaveAttribute('href'); @@ -228,7 +228,7 @@ describe.skip('PackagePolicyActionsMenu', () => { agentPolicies: [], packagePolicy, }); - await act(async () => { + await waitFor(() => { const editButton = utils.getByTestId('PackagePolicyActionsEditItem'); expect(editButton).not.toHaveAttribute('disabled'); expect(editButton).toHaveAttribute('href'); diff --git a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx index e51d61ea8ab2..25ed040f05e7 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_actions_menu.tsx @@ -108,24 +108,27 @@ export const PackagePolicyActionsMenu: React.FunctionComponent<{ defaultMessage="Edit integration" /> </EuiContextMenuItem>, - <EuiContextMenuItem - data-test-subj="PackagePolicyActionsUpgradeItem" - disabled={ - !packagePolicy.hasUpgrade || - !canWriteIntegrationPolicies || - !upgradePackagePolicyHref || - agentPolicy?.supports_agentless === true - } - icon="refresh" - href={upgradePackagePolicyHref} - key="packagePolicyUpgrade" - > - <FormattedMessage - id="xpack.fleet.policyDetails.packagePoliciesTable.upgradeActionTitle" - data-test-subj="UpgradeIntegrationPolicy" - defaultMessage="Upgrade integration policy" - /> - </EuiContextMenuItem>, + ...(packagePolicy.hasUpgrade + ? [ + <EuiContextMenuItem + data-test-subj="PackagePolicyActionsUpgradeItem" + disabled={ + !canWriteIntegrationPolicies || + !upgradePackagePolicyHref || + agentPolicy?.supports_agentless === true + } + icon="refresh" + href={upgradePackagePolicyHref} + key="packagePolicyUpgrade" + > + <FormattedMessage + id="xpack.fleet.policyDetails.packagePoliciesTable.upgradeActionTitle" + data-test-subj="UpgradeIntegrationPolicy" + defaultMessage="Upgrade integration policy" + /> + </EuiContextMenuItem>, + ] + : []), // FIXME: implement Copy package policy action // <EuiContextMenuItem disabled icon="copy" onClick={() => {}} key="packagePolicyCopy"> // <FormattedMessage diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx index 720218731136..75fce0507f5a 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { act, fireEvent } from '@testing-library/react'; +import { fireEvent, waitFor } from '@testing-library/react'; import { EuiContextMenuItem } from '@elastic/eui'; @@ -24,13 +24,15 @@ jest.mock('../hooks', () => { useMultipleAgentPolicies: jest.fn(), useStartServices: jest.fn().mockReturnValue({ notifications: { - toasts: { addSuccess: jest.fn() }, + toasts: { addSuccess: jest.fn(), addDanger: jest.fn() }, }, }), sendGetAgents: jest.fn(), useConfig: jest.fn().mockReturnValue({ agents: { enabled: true }, }), + sendDeletePackagePolicy: jest.fn().mockResolvedValue({ data: [] }), + sendDeleteAgentPolicy: jest.fn().mockResolvedValue({ data: [] }), }; }); @@ -56,6 +58,7 @@ function renderMenu({ onClick={() => { deletePackagePoliciesPrompt(packagePolicyIds, () => {}); }} + data-test-subj="deleteIntegrationBtn" > Delete integration </EuiContextMenuItem> @@ -154,15 +157,16 @@ describe('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + await waitFor(() => { + const calloutText = utils.getByTestId('affectedAgentsCallOut').textContent; + expect(calloutText).toContain('This action will affect 5 agents.'); + expect(calloutText).toContain('is already in use by some of your agents'); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); }); - expect(utils.getByText('This action will affect 5 agents.')).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); - expect(utils.getAllByText(/is already in use by some of your agents./).length).toBe(1); }); it('When multiple agent policies are present and agents are enrolled show additional warnings', async () => { @@ -184,18 +188,19 @@ describe('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + + await waitFor(() => { + const calloutText = utils.getByTestId('affectedAgentsCallOut').textContent; + expect(calloutText).toContain('This action will affect 5 agents.'); + expect(utils.getByTestId('sharedAgentPolicyCallOut').textContent).toContain( + 'This integration is shared by multiple agent policies.' + ); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); }); - expect(utils.getByText('This action will affect 5 agents.')).toBeInTheDocument(); - expect( - utils.getByText('This integration is shared by multiple agent policies.') - ).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); - expect(utils.queryAllByText(/is already in use by some of your agents./).length).toBe(0); }); it('When multiple agent policies are present and no agents are enrolled show additional warnings', async () => { @@ -212,18 +217,18 @@ describe('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + + await waitFor(() => { + expect(utils.queryByTestId('affectedAgentsCallOut')).not.toBeInTheDocument(); + expect(utils.getByTestId('sharedAgentPolicyCallOut').textContent).toContain( + 'This integration is shared by multiple agent policies.' + ); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); }); - expect(utils.queryByText('This action will affect 5 agents.')).not.toBeInTheDocument(); - expect(utils.queryAllByText(/is already in use by some of your agents./).length).toBe(0); - expect( - utils.getByText('This integration is shared by multiple agent policies.') - ).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); }); it('When agentless should show a different set of warnings', async () => { @@ -245,16 +250,19 @@ describe('PackagePolicyDeleteProvider', () => { agentPolicies, packagePolicyIds: ['integration-0001'], }); - await act(async () => { - const button = utils.getByRole('button'); - fireEvent.click(button); + const button = utils.getByTestId('deleteIntegrationBtn'); + fireEvent.click(button); + + await waitFor(() => { + expect(utils.getByTestId('affectedAgentsCallOut').textContent).not.toContain( + 'This action will affect 5 agents.' + ); + expect(utils.getByTestId('confirmModalBodyText').textContent).toContain( + 'This action can not be undone. Are you sure you wish to continue?' + ); + expect(utils.getByTestId('confirmModalTitleText').textContent).toContain( + 'about to delete an integration' + ); }); - // utils.debug(); - expect(utils.queryByText('This action will affect 5 agents.')).not.toBeInTheDocument(); - expect(utils.getByText(/about to delete an integration/)).toBeInTheDocument(); - expect( - utils.getByText('This action can not be undone. Are you sure you wish to continue?') - ).toBeInTheDocument(); - expect(utils.getAllByText(/integration will stop data ingestion./).length).toBe(1); }); }); diff --git a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx index f12c4cf371ed..70e7d77636fc 100644 --- a/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx +++ b/x-pack/plugins/fleet/public/components/package_policy_delete_provider.tsx @@ -247,6 +247,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({ defaultMessage="This integration is shared by multiple agent policies." /> } + data-test-subj="sharedAgentPolicyCallOut" /> <EuiSpacer size="m" /> </> @@ -261,6 +262,7 @@ export const PackagePolicyDeleteProvider: React.FunctionComponent<Props> = ({ <> <EuiCallOut color="danger" + data-test-subj="affectedAgentsCallOut" title={ !isAgentlessPolicy && ( <FormattedMessage diff --git a/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts b/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts index 36024a38fb51..2f48cf1f3c50 100644 --- a/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts +++ b/x-pack/plugins/fleet/public/hooks/use_agent_version.test.ts @@ -14,7 +14,9 @@ import { sendGetAgentsAvailableVersions } from './use_request'; jest.mock('./use_kibana_version'); jest.mock('./use_request'); -describe('useAgentVersion', () => { +// FLAKY: https://github.com/elastic/kibana/issues/201392 +// FLAKY: https://github.com/elastic/kibana/issues/201759 +describe.skip('useAgentVersion', () => { afterEach(() => { jest.clearAllMocks(); }); diff --git a/x-pack/plugins/fleet/scripts/create_agent_policies/create_agent_policies.ts b/x-pack/plugins/fleet/scripts/create_agent_policies/create_agent_policies.ts index db47c056ce12..e000640a477e 100644 --- a/x-pack/plugins/fleet/scripts/create_agent_policies/create_agent_policies.ts +++ b/x-pack/plugins/fleet/scripts/create_agent_policies/create_agent_policies.ts @@ -9,8 +9,7 @@ import { ToolingLog } from '@kbn/tooling-log'; import yargs from 'yargs'; import { chunk } from 'lodash'; -import { LEGACY_PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../common/constants'; -import { LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../common'; +import { AGENT_POLICY_SAVED_OBJECT_TYPE } from '../../common/constants'; import { packagePolicyFixture } from './fixtures'; @@ -30,20 +29,18 @@ const printUsage = () => const INDEX_BULK_OP = '{ "index":{ "_id": "{{id}}" } }\n'; +const space = 'default'; function getPolicyId(idx: number | string) { - return `test-policy-${idx}`; + return `test-policy-${space}-${idx}`; } async function createAgentPoliciesDocsBulk(range: number[]) { const auth = 'Basic ' + Buffer.from(ES_SUPERUSER + ':' + ES_PASSWORD).toString('base64'); const body = range .flatMap((idx) => [ - INDEX_BULK_OP.replace( - /{{id}}/, - `${LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE}:${getPolicyId(idx)}` - ), + INDEX_BULK_OP.replace(/{{id}}/, `${AGENT_POLICY_SAVED_OBJECT_TYPE}:${getPolicyId(idx)}`), JSON.stringify({ - [LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE]: { + [AGENT_POLICY_SAVED_OBJECT_TYPE]: { namespace: 'default', monitoring_enabled: ['logs', 'metrics', 'traces'], name: `Test Policy ${idx}`, @@ -60,11 +57,11 @@ async function createAgentPoliciesDocsBulk(range: number[]) { schema_version: '1.1.1', is_protected: false, }, - type: LEGACY_AGENT_POLICY_SAVED_OBJECT_TYPE, + namespaces: [space], + type: AGENT_POLICY_SAVED_OBJECT_TYPE, references: [], managed: false, coreMigrationVersion: '8.8.0', - typeMigrationVersion: '10.3.0', created_at: new Date().toISOString(), updated_at: new Date().toISOString(), }) + '\n', @@ -81,7 +78,7 @@ async function createAgentPoliciesDocsBulk(range: number[]) { const data = await res.json(); if (!data.items) { - logger.error('Error creating agent policies docs: ' + JSON.stringify(data)); + logger.error('Error creating agent policy docs: ' + JSON.stringify(data)); process.exit(1); } return data; @@ -91,14 +88,14 @@ async function createEnrollmentToken(range: number[]) { const auth = 'Basic ' + Buffer.from(ES_SUPERUSER + ':' + ES_PASSWORD).toString('base64'); const body = range .flatMap((idx) => [ - INDEX_BULK_OP.replace(/{{id}}/, `test-enrollment-token-${idx}`), + INDEX_BULK_OP.replace(/{{id}}/, `test-enrollment-token-${space}-${idx}`), JSON.stringify({ active: true, api_key_id: 'faketest123', api_key: 'test==', name: `Test Policy ${idx}`, policy_id: `${getPolicyId(idx)}`, - namespaces: [], + namespaces: [space], created_at: new Date().toISOString(), }) + '\n', ]) @@ -115,7 +112,7 @@ async function createEnrollmentToken(range: number[]) { const data = await res.json(); if (!data.items) { - logger.error('Error creating agent policies docs: ' + JSON.stringify(data)); + logger.error('Error creating enrollment key docs: ' + JSON.stringify(data)); process.exit(1); } return data; @@ -125,14 +122,12 @@ async function createPackagePolicies(range: number[]) { const auth = 'Basic ' + Buffer.from(ES_SUPERUSER + ':' + ES_PASSWORD).toString('base64'); const body = range .flatMap((idx) => [ - INDEX_BULK_OP.replace( - /{{id}}/, - `${LEGACY_PACKAGE_POLICY_SAVED_OBJECT_TYPE}:test-policy-${idx}` - ), + INDEX_BULK_OP.replace(/{{id}}/, `fleet-package-policies:test-policy-${space}-${idx}`), JSON.stringify( packagePolicyFixture({ idx, agentPolicyId: getPolicyId(idx), + space, }) ) + '\n', ]) @@ -150,7 +145,7 @@ async function createPackagePolicies(range: number[]) { const data = await res.json(); if (!data.items) { - logger.error('Error creating agent policies docs: ' + JSON.stringify(data)); + logger.error('Error creating package policy docs: ' + JSON.stringify(data)); process.exit(1); } return data; diff --git a/x-pack/plugins/fleet/scripts/create_agent_policies/fixtures.ts b/x-pack/plugins/fleet/scripts/create_agent_policies/fixtures.ts index b10f412ac43f..ddaa226c0729 100644 --- a/x-pack/plugins/fleet/scripts/create_agent_policies/fixtures.ts +++ b/x-pack/plugins/fleet/scripts/create_agent_policies/fixtures.ts @@ -8,11 +8,13 @@ export const packagePolicyFixture = ({ agentPolicyId, idx, + space, }: { idx: number; agentPolicyId: string; + space: string; }) => ({ - 'ingest-package-policies': { + 'fleet-package-policies': { name: `system-test-${idx}`, namespace: '', description: '', @@ -790,11 +792,12 @@ export const packagePolicyFixture = ({ updated_at: '2024-08-30T13:45:51.197Z', updated_by: 'system', }, - type: 'ingest-package-policies', + namespaces: [space], + type: 'fleet-package-policies', references: [], managed: false, coreMigrationVersion: '8.8.0', - typeMigrationVersion: '10.14.0', + typeMigrationVersion: '10.1.0', updated_at: '2024-08-30T13:45:51.197Z', created_at: '2024-08-30T13:45:51.197Z', }); diff --git a/x-pack/plugins/fleet/scripts/create_agent_policies/index.js b/x-pack/plugins/fleet/scripts/create_agent_policies/index.js index a51859ee684c..a61ed0e7e54d 100644 --- a/x-pack/plugins/fleet/scripts/create_agent_policies/index.js +++ b/x-pack/plugins/fleet/scripts/create_agent_policies/index.js @@ -12,6 +12,6 @@ require('./create_agent_policies').run(); Usage: cd x-pack/plugins/fleet -node scripts/create_agents/index.js +node scripts/create_agent_policies/index.js */ diff --git a/x-pack/plugins/fleet/server/constants/index.ts b/x-pack/plugins/fleet/server/constants/index.ts index 48de05c0b635..ecb889a1fcae 100644 --- a/x-pack/plugins/fleet/server/constants/index.ts +++ b/x-pack/plugins/fleet/server/constants/index.ts @@ -124,3 +124,4 @@ export { export { FILE_STORAGE_DATA_AGENT_INDEX } from './fleet_es_assets'; export { FILE_STORAGE_METADATA_AGENT_INDEX } from './fleet_es_assets'; export * from '../../common/constants/mappings'; +export * from './max_concurrency_constants'; diff --git a/x-pack/plugins/fleet/server/constants/max_concurrency_constants.ts b/x-pack/plugins/fleet/server/constants/max_concurrency_constants.ts new file mode 100644 index 000000000000..1253d8b06e42 --- /dev/null +++ b/x-pack/plugins/fleet/server/constants/max_concurrency_constants.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// Constants used across the code to limit concurrency of pMap operations +export const MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS = 50; +export const MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 = 20; +export const MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_10 = 10; +export const MAX_CONCURRENT_DATASTREAM_OPERATIONS = 50; +export const MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS = 20; +export const MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS = 10; +export const MAX_CONCURRENT_PACKAGE_ASSETS = 5; +export const MAX_CONCURRENT_CREATE_ACTIONS = 50; +export const MAX_CONCURRENT_DATASTREAMS_ILM_OPERATIONS = 50; +export const MAX_CONCURRENT_ILM_POLICIES_OPERATIONS = 50; +export const MAX_CONCURRENT_PIPELINES_DELETIONS = 50; +export const MAX_CONCURRENT_ML_MODELS_OPERATIONS = 50; +export const MAX_CONCURRENT_COMPONENT_TEMPLATES = 50; +export const MAX_CONCURRENT_TRANSFORMS_OPERATIONS = 20; +export const MAX_CONCURRENT_INDEX_PATTERN_OPERATIONS = 50; +export const MAX_CONCURRENT_ES_ASSETS_OPERATIONS = 50; +export const MAX_CONCURRENT_AGENT_FILES_UPLOADS = 50; +export const MAX_CONCURRENT_BACKFILL_OUTPUTS_PRESETS = 20; +export const MAX_CONCURRENT_CLEAN_OLD_FILE_INDICES = 2; diff --git a/x-pack/plugins/fleet/server/mocks/index.ts b/x-pack/plugins/fleet/server/mocks/index.ts index 8d452b394dd1..db100c5fcf7e 100644 --- a/x-pack/plugins/fleet/server/mocks/index.ts +++ b/x-pack/plugins/fleet/server/mocks/index.ts @@ -29,6 +29,7 @@ import { createFleetActionsClientMock } from '../services/actions/mocks'; import { createFleetFilesClientFactoryMock } from '../services/files/mocks'; import { createArtifactsClientMock } from '../services/artifacts/mocks'; +import { createOutputClientMock } from '../services/output_client.mock'; import type { PackagePolicyClient } from '../services/package_policy_service'; import type { AgentPolicyServiceInterface } from '../services'; @@ -303,6 +304,7 @@ export const createFleetStartContractMock = (): DeeplyMockedKeys<FleetStartContr uninstallTokenService: createUninstallTokenServiceMock(), createFleetActionsClient: jest.fn((_) => fleetActionsClient), getPackageSpecTagId: jest.fn(getPackageSpecTagId), + createOutputClient: jest.fn(async (_) => createOutputClientMock()), }; return startContract; diff --git a/x-pack/plugins/fleet/server/plugin.ts b/x-pack/plugins/fleet/server/plugin.ts index 4c5cdf707053..1620df27b82c 100644 --- a/x-pack/plugins/fleet/server/plugin.ts +++ b/x-pack/plugins/fleet/server/plugin.ts @@ -84,6 +84,8 @@ import { MessageSigningService, } from './services/security'; +import { OutputClient, type OutputClientInterface } from './services/output_client'; + import { ASSETS_SAVED_OBJECT_TYPE, DOWNLOAD_SOURCE_SAVED_OBJECT_TYPE, @@ -143,6 +145,7 @@ import { registerFieldsMetadataExtractors } from './services/register_fields_met import { registerUpgradeManagedPackagePoliciesTask } from './services/setup/managed_package_policies'; import { registerDeployAgentPoliciesTask } from './services/agent_policies/deploy_agent_policies_task'; import { DeleteUnenrolledAgentsTask } from './tasks/delete_unenrolled_agents_task'; +import { registerBumpAgentPoliciesTask } from './services/agent_policies/bump_agent_policies_task'; export interface FleetSetupDeps { security: SecurityPluginSetup; @@ -261,6 +264,12 @@ export interface FleetStartContract { Function exported to allow creating unique ids for saved object tags */ getPackageSpecTagId: (spaceId: string, pkgName: string, tagName: string) => string; + + /** + * Create a Fleet Output Client instance + * @param packageName + */ + createOutputClient: (request: KibanaRequest) => Promise<OutputClientInterface>; } export class FleetPlugin @@ -619,6 +628,7 @@ export class FleetPlugin // Register task registerUpgradeManagedPackagePoliciesTask(deps.taskManager); registerDeployAgentPoliciesTask(deps.taskManager); + registerBumpAgentPoliciesTask(deps.taskManager); this.bulkActionsResolver = new BulkActionsResolver(deps.taskManager, core); this.checkDeletedFilesTask = new CheckDeletedFilesTask({ @@ -835,6 +845,11 @@ export class FleetPlugin return new FleetActionsClient(core.elasticsearch.client.asInternalUser, packageName); }, getPackageSpecTagId, + async createOutputClient(request: KibanaRequest) { + const soClient = appContextService.getSavedObjects().getScopedClient(request); + const authz = await getAuthzFromRequest(request); + return new OutputClient(soClient, authz); + }, }; } diff --git a/x-pack/plugins/fleet/server/routes/agent/handlers.ts b/x-pack/plugins/fleet/server/routes/agent/handlers.ts index bcefa56b806e..c51fb9de674c 100644 --- a/x-pack/plugins/fleet/server/routes/agent/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent/handlers.ts @@ -46,6 +46,8 @@ import { fetchAndAssignAgentMetrics } from '../../services/agents/agent_metrics' import { getAgentStatusForAgentPolicy } from '../../services/agents'; import { isAgentInNamespace } from '../../services/spaces/agent_namespaces'; import { getCurrentNamespace } from '../../services/spaces/get_current_namespace'; +import { getPackageInfo } from '../../services/epm/packages'; +import { generateTemplateIndexPattern } from '../../services/epm/elasticsearch/template/template'; import { buildAgentStatusRuntimeField } from '../../services/agents/build_status_runtime_field'; async function verifyNamespace(agent: Agent, namespace?: string) { @@ -308,17 +310,32 @@ export const getAgentDataHandler: RequestHandler< > = async (context, request, response) => { const coreContext = await context.core; const esClient = coreContext.elasticsearch.client.asCurrentUser; - - const returnDataPreview = request.query.previewData; - const agentIds = isStringArray(request.query.agentsIds) + const agentsIds = isStringArray(request.query.agentsIds) ? request.query.agentsIds : [request.query.agentsIds]; + const { pkgName, pkgVersion, previewData: returnDataPreview } = request.query; + + // If a package is specified, get data stream patterns for that package + // and scope incoming data query to that pattern + let dataStreamPattern: string | undefined; + if (pkgName && pkgVersion) { + const packageInfo = await getPackageInfo({ + savedObjectsClient: coreContext.savedObjects.client, + prerelease: true, + pkgName, + pkgVersion, + }); + dataStreamPattern = (packageInfo.data_streams || []) + .map((ds) => generateTemplateIndexPattern(ds)) + .join(','); + } - const { items, dataPreview } = await AgentService.getIncomingDataByAgentsId( + const { items, dataPreview } = await AgentService.getIncomingDataByAgentsId({ esClient, - agentIds, - returnDataPreview - ); + agentsIds, + dataStreamPattern, + returnDataPreview, + }); const body = { items, dataPreview }; diff --git a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts index faa18c0cfa47..6d5587e28387 100644 --- a/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/agent_policy/handlers.ts @@ -19,7 +19,11 @@ import { HTTPAuthorizationHeader } from '../../../common/http_authorization_head import { fullAgentPolicyToYaml } from '../../../common/services'; import { appContextService, agentPolicyService } from '../../services'; import { type AgentClient, getLatestAvailableAgentVersion } from '../../services/agents'; -import { AGENTS_PREFIX, UNPRIVILEGED_AGENT_KUERY } from '../../constants'; +import { + AGENTS_PREFIX, + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_10, + UNPRIVILEGED_AGENT_KUERY, +} from '../../constants'; import type { GetAgentPoliciesRequestSchema, GetOneAgentPolicyRequestSchema, @@ -82,7 +86,7 @@ export async function populateAssignedAgentsCount( .then(({ total }) => (agentPolicy.unprivileged_agents = total)); return Promise.all([totalAgents, unprivilegedAgents]); }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_10 } ); } diff --git a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts index 7ed4b5bacf33..2a4ab12ad005 100644 --- a/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts +++ b/x-pack/plugins/fleet/server/routes/data_streams/handlers.ts @@ -17,6 +17,7 @@ import type { GetDataStreamsResponse } from '../../../common/types'; import { getPackageSavedObjects } from '../../services/epm/packages/get'; import type { MeteringStats } from '../../services/data_streams'; import { dataStreamService } from '../../services/data_streams'; +import { MAX_CONCURRENT_DATASTREAM_OPERATIONS } from '../../constants'; import { appContextService } from '../../services'; import { getDataStreamsQueryMetadata } from './get_data_streams_query_metadata'; @@ -233,7 +234,7 @@ export const getListHandler: RequestHandler = async (context, request, response) // After filtering out data streams that are missing dataset/namespace/type/package fields body.data_streams = ( await pMap(dataStreamNames, (dataStreamName) => queryDataStreamInfo(dataStreamName), { - concurrency: 50, + concurrency: MAX_CONCURRENT_DATASTREAM_OPERATIONS, }) ) .filter(({ dataset, namespace, type }) => dataset && namespace && type) diff --git a/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts b/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts index 2d63b357347d..880b042de435 100644 --- a/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts +++ b/x-pack/plugins/fleet/server/routes/fleet_proxies/handler.ts @@ -31,6 +31,7 @@ import type { DownloadSource, } from '../../types'; import { agentPolicyService } from '../../services'; +import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; async function bumpRelatedPolicies( soClient: SavedObjectsClientContract, @@ -49,7 +50,7 @@ async function bumpRelatedPolicies( outputs, (output) => agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, output.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); await pMap( @@ -57,7 +58,7 @@ async function bumpRelatedPolicies( (fleetServerHost) => agentPolicyService.bumpAllAgentPoliciesForFleetServerHosts(esClient, fleetServerHost.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); @@ -66,7 +67,7 @@ async function bumpRelatedPolicies( (downloadSource) => agentPolicyService.bumpAllAgentPoliciesForDownloadSource(esClient, downloadSource.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } diff --git a/x-pack/plugins/fleet/server/routes/package_policy/utils/index.ts b/x-pack/plugins/fleet/server/routes/package_policy/utils/index.ts index 518d8fc3f74c..a174cb65fe3c 100644 --- a/x-pack/plugins/fleet/server/routes/package_policy/utils/index.ts +++ b/x-pack/plugins/fleet/server/routes/package_policy/utils/index.ts @@ -11,7 +11,7 @@ import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-ser import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; -import { isAgentlessApiEnabled } from '../../../services/utils/agentless'; +import { isAgentlessEnabled } from '../../../services/utils/agentless'; import { getAgentlessAgentPolicyNameFromPackagePolicyName } from '../../../../common/services/agentless_policy_helper'; @@ -65,7 +65,7 @@ export async function renameAgentlessAgentPolicy( packagePolicy: PackagePolicy, name: string ) { - if (!isAgentlessApiEnabled()) { + if (!isAgentlessEnabled()) { return; } // If agentless is enabled for cloud, we need to rename the agent policy diff --git a/x-pack/plugins/fleet/server/saved_objects/bump_agent_policies.md b/x-pack/plugins/fleet/server/saved_objects/bump_agent_policies.md new file mode 100644 index 000000000000..403ad148df23 --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/bump_agent_policies.md @@ -0,0 +1,33 @@ +## Agent policy SO changes + +When making changes to agent policy SO, the changes are not automatically deployed to agents. To trigger an agent policy bump, add a new model version to the agent policy SO type with a revision increase. + +``` + '2': { + changes: [ + { + type: 'data_backfill', + backfillFn: (doc) => { + return { attributes: { ...doc.attributes, revision: doc.attributes.revision + 1 } }; + }, + }, + ], + }, +``` + +## Package policy SO changes + +Similarly, package policy SO changes do not automatically trigger a redeploy of agent policies using them. To trigger an agent policy bump using package policies, add a new model version to the package policy SO type with `bump_agent_policy_revision: true`. + +``` + '2': { + changes: [ + { + type: 'data_backfill', + backfillFn: (doc) => { + return { attributes: { ...doc.attributes, bump_agent_policy_revision: true } }; + }, + }, + ], + }, +``` \ No newline at end of file diff --git a/x-pack/plugins/fleet/server/saved_objects/index.test.ts b/x-pack/plugins/fleet/server/saved_objects/index.test.ts new file mode 100644 index 000000000000..636992dd70fe --- /dev/null +++ b/x-pack/plugins/fleet/server/saved_objects/index.test.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import _ from 'lodash'; + +import { getSavedObjectTypes } from '.'; + +describe('space aware models', () => { + it('should have the same mappings for space and non-space aware agent policies', () => { + const soTypes = getSavedObjectTypes(); + + const legacyMappings = _.omit( + soTypes['ingest-agent-policies'].mappings, + 'properties.monitoring_diagnostics', + 'properties.monitoring_http', + 'properties.monitoring_pprof_enabled' + ); + + expect(legacyMappings).toEqual(soTypes['fleet-agent-policies'].mappings); + }); + it('should have the same mappings for space and non-space aware package policies', () => { + const soTypes = getSavedObjectTypes(); + + expect(soTypes['ingest-package-policies'].mappings).toEqual( + soTypes['fleet-package-policies'].mappings + ); + }); +}); diff --git a/x-pack/plugins/fleet/server/saved_objects/index.ts b/x-pack/plugins/fleet/server/saved_objects/index.ts index 706d0686b984..2dfdf333fd72 100644 --- a/x-pack/plugins/fleet/server/saved_objects/index.ts +++ b/x-pack/plugins/fleet/server/saved_objects/index.ts @@ -214,6 +214,7 @@ export const getSavedObjectTypes = ( importableAndExportable: false, }, mappings: { + dynamic: false, properties: { name: { type: 'keyword' }, schema_version: { type: 'version' }, @@ -305,6 +306,14 @@ export const getSavedObjectTypes = ( }, ], }, + '5': { + changes: [ + { + type: 'mappings_addition', + addedMappings: {}, + }, + ], + }, }, }, [AGENT_POLICY_SAVED_OBJECT_TYPE]: { @@ -316,6 +325,7 @@ export const getSavedObjectTypes = ( importableAndExportable: false, }, mappings: { + dynamic: false, properties: { name: { type: 'keyword' }, schema_version: { type: 'version' }, @@ -350,6 +360,16 @@ export const getSavedObjectTypes = ( global_data_tags: { type: 'flattened', index: false }, }, }, + modelVersions: { + '1': { + changes: [ + { + type: 'mappings_addition', + addedMappings: {}, + }, + ], + }, + }, }, [OUTPUT_SAVED_OBJECT_TYPE]: { name: OUTPUT_SAVED_OBJECT_TYPE, @@ -614,11 +634,13 @@ export const getSavedObjectTypes = ( }, secret_references: { properties: { id: { type: 'keyword' } } }, overrides: { type: 'flattened', index: false }, + supports_agentless: { type: 'boolean' }, revision: { type: 'integer' }, updated_at: { type: 'date' }, updated_by: { type: 'keyword' }, created_at: { type: 'date' }, created_by: { type: 'keyword' }, + bump_agent_policy_revision: { type: 'boolean' }, }, }, modelVersions: { @@ -763,6 +785,26 @@ export const getSavedObjectTypes = ( }, ], }, + '15': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + bump_agent_policy_revision: { type: 'boolean' }, + }, + }, + ], + }, + '16': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + supports_agentless: { type: 'boolean' }, + }, + }, + ], + }, }, migrations: { '7.10.0': migratePackagePolicyToV7100, @@ -818,11 +860,35 @@ export const getSavedObjectTypes = ( }, secret_references: { properties: { id: { type: 'keyword' } } }, overrides: { type: 'flattened', index: false }, + supports_agentless: { type: 'boolean' }, revision: { type: 'integer' }, updated_at: { type: 'date' }, updated_by: { type: 'keyword' }, created_at: { type: 'date' }, created_by: { type: 'keyword' }, + bump_agent_policy_revision: { type: 'boolean' }, + }, + }, + modelVersions: { + '1': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + bump_agent_policy_revision: { type: 'boolean' }, + }, + }, + ], + }, + '2': { + changes: [ + { + type: 'mappings_addition', + addedMappings: { + supports_agentless: { type: 'boolean' }, + }, + }, + ], }, }, }, diff --git a/x-pack/plugins/fleet/server/services/agent_policies/bump_agent_policies_task.test.ts b/x-pack/plugins/fleet/server/services/agent_policies/bump_agent_policies_task.test.ts new file mode 100644 index 000000000000..2e7305c5c571 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agent_policies/bump_agent_policies_task.test.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loggingSystemMock } from '@kbn/core/server/mocks'; + +import { agentPolicyService } from '../agent_policy'; + +import { appContextService } from '..'; +import { getPackagePolicySavedObjectType } from '../package_policy'; + +import { _updatePackagePoliciesThatNeedBump } from './bump_agent_policies_task'; + +jest.mock('../app_context'); +jest.mock('../agent_policy'); +jest.mock('../package_policy'); + +const mockedAgentPolicyService = jest.mocked(agentPolicyService); +const mockedAppContextService = jest.mocked(appContextService); +const mockSoClient = { + find: jest.fn(), + bulkUpdate: jest.fn(), +} as any; +const mockGetPackagePolicySavedObjectType = jest.mocked(getPackagePolicySavedObjectType); + +describe('_updatePackagePoliciesThatNeedBump', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockSoClient.find.mockResolvedValue({ + total: 3, + saved_objects: [ + { + id: 'packagePolicy1', + namespaces: ['default'], + attributes: { + policy_ids: ['policy1'], + }, + }, + { + id: 'packagePolicy12', + namespaces: ['default'], + attributes: { + policy_ids: ['policy1'], + }, + }, + { + id: 'packagePolicy2', + namespaces: ['space'], + attributes: { + policy_ids: ['policy2'], + }, + }, + { + id: 'packagePolicy3', + namespaces: ['space'], + attributes: { + policy_ids: ['policy3'], + }, + }, + ], + page: 1, + perPage: 100, + }); + mockedAppContextService.getInternalUserSOClientWithoutSpaceExtension.mockReturnValue( + mockSoClient + ); + mockedAppContextService.getInternalUserSOClientForSpaceId.mockReturnValue(mockSoClient); + mockGetPackagePolicySavedObjectType.mockResolvedValue('fleet-package-policies'); + }); + + it('should update package policy if bump agent policy revision needed', async () => { + const logger = loggingSystemMock.createLogger(); + + await _updatePackagePoliciesThatNeedBump(logger, () => false); + + expect(mockSoClient.bulkUpdate).toHaveBeenCalledWith([ + { + attributes: { bump_agent_policy_revision: false }, + id: 'packagePolicy1', + type: 'fleet-package-policies', + }, + { + attributes: { bump_agent_policy_revision: false }, + id: 'packagePolicy12', + type: 'fleet-package-policies', + }, + ]); + expect(mockSoClient.bulkUpdate).toHaveBeenCalledWith([ + { + attributes: { bump_agent_policy_revision: false }, + id: 'packagePolicy2', + type: 'fleet-package-policies', + }, + { + attributes: { bump_agent_policy_revision: false }, + id: 'packagePolicy3', + type: 'fleet-package-policies', + }, + ]); + + expect(mockedAgentPolicyService.bumpAgentPoliciesByIds).toHaveBeenCalledWith( + expect.anything(), + undefined, + ['policy1'] + ); + expect(mockedAgentPolicyService.bumpAgentPoliciesByIds).toHaveBeenCalledWith( + expect.anything(), + undefined, + ['policy2', 'policy3'] + ); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/agent_policies/bump_agent_policies_task.ts b/x-pack/plugins/fleet/server/services/agent_policies/bump_agent_policies_task.ts new file mode 100644 index 000000000000..d134fdbfae04 --- /dev/null +++ b/x-pack/plugins/fleet/server/services/agent_policies/bump_agent_policies_task.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { Logger } from '@kbn/core/server'; +import type { + ConcreteTaskInstance, + TaskManagerSetupContract, + TaskManagerStartContract, +} from '@kbn/task-manager-plugin/server'; +import { v4 as uuidv4 } from 'uuid'; +import { uniq } from 'lodash'; + +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; + +import { agentPolicyService, appContextService } from '..'; +import { runWithCache } from '../epm/packages/cache'; +import { getPackagePolicySavedObjectType } from '../package_policy'; +import { mapPackagePolicySavedObjectToPackagePolicy } from '../package_policies'; +import type { PackagePolicy, PackagePolicySOAttributes } from '../../types'; +import { normalizeKuery } from '../saved_object'; +import { SO_SEARCH_LIMIT } from '../../constants'; + +const TASK_TYPE = 'fleet:bump_agent_policies'; + +export function registerBumpAgentPoliciesTask(taskManagerSetup: TaskManagerSetupContract) { + taskManagerSetup.registerTaskDefinitions({ + [TASK_TYPE]: { + title: 'Fleet Bump policies', + timeout: '5m', + maxAttempts: 3, + createTaskRunner: ({ taskInstance }: { taskInstance: ConcreteTaskInstance }) => { + let cancelled = false; + const isCancelled = () => cancelled; + return { + async run() { + if (isCancelled()) { + throw new Error('Task has been cancelled'); + } + + await runWithCache(async () => { + await _updatePackagePoliciesThatNeedBump(appContextService.getLogger(), isCancelled); + }); + }, + async cancel() { + cancelled = true; + }, + }; + }, + }, + }); +} + +async function getPackagePoliciesToBump(savedObjectType: string) { + const result = await appContextService + .getInternalUserSOClientWithoutSpaceExtension() + .find<PackagePolicySOAttributes>({ + type: savedObjectType, + filter: normalizeKuery(savedObjectType, `${savedObjectType}.bump_agent_policy_revision:true`), + perPage: SO_SEARCH_LIMIT, + namespaces: ['*'], + fields: ['id', 'namespaces', 'policy_ids'], + }); + return { + total: result.total, + items: result.saved_objects.map((so) => + mapPackagePolicySavedObjectToPackagePolicy(so, so.namespaces) + ), + }; +} + +export async function _updatePackagePoliciesThatNeedBump( + logger: Logger, + isCancelled: () => boolean +) { + const savedObjectType = await getPackagePolicySavedObjectType(); + const packagePoliciesToBump = await getPackagePoliciesToBump(savedObjectType); + + logger.info( + `Found ${packagePoliciesToBump.total} package policies that need agent policy revision bump` + ); + + const packagePoliciesIndexedBySpace = packagePoliciesToBump.items.reduce((acc, policy) => { + const spaceId = policy.spaceIds?.[0] ?? DEFAULT_SPACE_ID; + if (!acc[spaceId]) { + acc[spaceId] = []; + } + + acc[spaceId].push(policy); + + return acc; + }, {} as { [k: string]: PackagePolicy[] }); + + const start = Date.now(); + + for (const [spaceId, packagePolicies] of Object.entries(packagePoliciesIndexedBySpace)) { + if (isCancelled()) { + throw new Error('Task has been cancelled'); + } + + const soClient = appContextService.getInternalUserSOClientForSpaceId(spaceId); + const esClient = appContextService.getInternalUserESClient(); + + await soClient.bulkUpdate<PackagePolicySOAttributes>( + packagePolicies.map((item) => ({ + type: savedObjectType, + id: item.id, + attributes: { + bump_agent_policy_revision: false, + }, + })) + ); + + const updatedCount = packagePolicies.length; + + const agentPoliciesToBump = uniq(packagePolicies.map((item) => item.policy_ids).flat()); + + await agentPolicyService.bumpAgentPoliciesByIds(soClient, esClient, agentPoliciesToBump); + + logger.debug( + `Updated ${updatedCount} package policies in space ${spaceId} in ${ + Date.now() - start + }ms, bump ${agentPoliciesToBump.length} agent policies` + ); + } +} + +export async function scheduleBumpAgentPoliciesTask(taskManagerStart: TaskManagerStartContract) { + await taskManagerStart.ensureScheduled({ + id: `${TASK_TYPE}:${uuidv4()}`, + scope: ['fleet'], + params: {}, + taskType: TASK_TYPE, + runAt: new Date(Date.now() + 3 * 1000), + state: {}, + }); +} diff --git a/x-pack/plugins/fleet/server/services/agent_policy.test.ts b/x-pack/plugins/fleet/server/services/agent_policy.test.ts index fb3274b6eef7..76d2727b65e8 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.test.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.test.ts @@ -157,7 +157,7 @@ describe('Agent policy', () => { beforeEach(() => { mockedLogger = loggerMock.create(); mockedAppContextService.getLogger.mockReturnValue(mockedLogger); - mockedAppContextService.getExperimentalFeatures.mockReturnValue({ agentless: false } as any); + mockedAppContextService.getExperimentalFeatures.mockReturnValue({} as any); jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(false); jest .mocked(getPackagePolicySavedObjectType) @@ -315,10 +315,7 @@ describe('Agent policy', () => { ); }); - it('should throw AgentPolicyInvalidError if support_agentless is defined in stateful without agentless feature', async () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); + it('should throw AgentPolicyInvalidError if support_agentless is defined in stateful without agentless enabled', async () => { jest .spyOn(appContextService, 'getCloud') .mockReturnValue({ isServerlessEnabled: false } as any); @@ -339,10 +336,7 @@ describe('Agent policy', () => { ); }); - it('should throw AgentPolicyInvalidError if agentless feature flag is disabled in serverless', async () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); + it('should throw AgentPolicyInvalidError if agentless is disabled in serverless', async () => { jest .spyOn(appContextService, 'getCloud') .mockReturnValue({ isServerlessEnabled: true } as any); @@ -363,10 +357,10 @@ describe('Agent policy', () => { ); }); - it('should create a policy agentless feature flag is set and in serverless env', async () => { + it('should create an agentless policy when agentless config is set and in serverless env', async () => { jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: true } as any); + .spyOn(appContextService, 'getConfig') + .mockReturnValue({ agentless: { enabled: true } } as any); jest .spyOn(appContextService, 'getCloud') .mockReturnValue({ isServerlessEnabled: true } as any); @@ -1229,13 +1223,13 @@ describe('Agent policy', () => { ).resolves.not.toThrow(); }); - it('should throw AgentPolicyInvalidError if agentless flag is disabled in serverless', async () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); + it('should not throw AgentPolicyInvalidError if support_agentless is defined in serverless', async () => { + jest.spyOn(appContextService, 'getConfig').mockReturnValue({ + agentless: { enabled: true }, + } as any); jest .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: true } as any); + .mockReturnValue({ isServerlessEnabled: true, isCloudEnabled: false } as any); const soClient = getAgentPolicyCreateMock(); const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser; @@ -1252,17 +1246,13 @@ describe('Agent policy', () => { namespace: 'default', supports_agentless: true, }) - ).rejects.toThrowError( - new AgentPolicyInvalidError( - 'supports_agentless is only allowed in serverless and cloud environments that support the agentless feature' - ) - ); + ).resolves.not.toThrow(); }); - it('should not throw in serverless if support_agentless is set and agentless feature flag is set', async () => { + it('should not throw in serverless if support_agentless and agentless config is set', async () => { jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: true } as any); + .spyOn(appContextService, 'getConfig') + .mockReturnValue({ agentless: { enabled: true } } as any); jest .spyOn(appContextService, 'getCloud') .mockReturnValue({ isServerlessEnabled: true } as any); diff --git a/x-pack/plugins/fleet/server/services/agent_policy.ts b/x-pack/plugins/fleet/server/services/agent_policy.ts index cada1c8e6445..eed9b058ad03 100644 --- a/x-pack/plugins/fleet/server/services/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/agent_policy.ts @@ -97,6 +97,11 @@ import type { FullAgentConfigMap } from '../../common/types/models/agent_cm'; import { fullAgentConfigMapToYaml } from '../../common/services/agent_cm_to_yaml'; +import { + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, +} from '../constants'; + import { appContextService } from '.'; import { mapAgentPolicySavedObjectToAgentPolicy } from './agent_policies/utils'; @@ -550,7 +555,7 @@ class AgentPolicyService { } return agentPolicy; }, - { concurrency: 50 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS } ); const result = agentPolicies.filter( @@ -657,7 +662,7 @@ class AgentPolicyService { return agentPolicy; }, - { concurrency: 50 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS } ); } @@ -955,7 +960,7 @@ class AgentPolicyService { ); }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); await pMap( @@ -970,7 +975,7 @@ class AgentPolicyService { }); }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -1014,7 +1019,7 @@ class AgentPolicyService { } ), { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -1083,7 +1088,7 @@ class AgentPolicyService { this.triggerAgentPolicyUpdatedEvent(esClient, 'updated', policy.id, { spaceId: policy.namespaces?.[0], }), - { concurrency: 50 } + { concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS } ); } @@ -1352,7 +1357,7 @@ class AgentPolicyService { agentPolicy: agentPolicies?.find((policy) => policy.id === agentPolicyId), }), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); @@ -1423,27 +1428,29 @@ class AgentPolicyService { ); } - await Promise.all( - fleetServerPolicies - .filter((fleetServerPolicy) => { - const policy = policiesMap[fleetServerPolicy.policy_id]; - return ( - !policy.schema_version || lt(policy.schema_version, FLEET_AGENT_POLICIES_SCHEMA_VERSION) - ); - }) - .map((fleetServerPolicy) => - // There are some potential performance concerns around using `agentPolicyService.update` in this context. - // This could potentially be a bottleneck in environments with several thousand agent policies being deployed here. - agentPolicyService.update( - soClient, - esClient, - fleetServerPolicy.policy_id, - { - schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, - }, - { force: true } - ) - ) + const filteredFleetServerPolicies = fleetServerPolicies.filter((fleetServerPolicy) => { + const policy = policiesMap[fleetServerPolicy.policy_id]; + return ( + !policy.schema_version || lt(policy.schema_version, FLEET_AGENT_POLICIES_SCHEMA_VERSION) + ); + }); + await pMap( + filteredFleetServerPolicies, + (fleetServerPolicy) => + // There are some potential performance concerns around using `agentPolicyService.update` in this context. + // This could potentially be a bottleneck in environments with several thousand agent policies being deployed here. + agentPolicyService.update( + soClient, + esClient, + fleetServerPolicy.policy_id, + { + schema_version: FLEET_AGENT_POLICIES_SCHEMA_VERSION, + }, + { force: true } + ), + { + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, + } ); } @@ -1589,7 +1596,7 @@ class AgentPolicyService { } ), { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -1646,6 +1653,27 @@ class AgentPolicyService { ); } + public async bumpAgentPoliciesByIds( + soClient: SavedObjectsClientContract, + esClient: ElasticsearchClient, + agentPolicyIds: string[], + options?: { user?: AuthenticatedUser } + ): Promise<SavedObjectsBulkUpdateResponse<AgentPolicy>> { + const internalSoClientWithoutSpaceExtension = + appContextService.getInternalUserSOClientWithoutSpaceExtension(); + const savedObjectType = await getAgentPolicySavedObjectType(); + + const objects = agentPolicyIds.map((id: string) => ({ id, type: savedObjectType })); + const bulkGetResponse = await soClient.bulkGet<AgentPolicySOAttributes>(objects); + + return this._bumpPolicies( + internalSoClientWithoutSpaceExtension, + esClient, + bulkGetResponse.saved_objects, + options + ); + } + public async getInactivityTimeouts(): Promise< Array<{ policyIds: string[]; inactivityTimeout: number }> > { @@ -1869,7 +1897,7 @@ class AgentPolicyService { return { integrationPolicyName: pkgPolicy?.name, id: pkgPolicy?.output_id ?? '' }; }, { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -1902,7 +1930,7 @@ class AgentPolicyService { return { agentPolicyId: agentPolicy.id, ...output }; }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); return allOutputs; diff --git a/x-pack/plugins/fleet/server/services/agents/actions.ts b/x-pack/plugins/fleet/server/services/agents/actions.ts index f0dcd9a1ac62..f2faf26fd96a 100644 --- a/x-pack/plugins/fleet/server/services/agents/actions.ts +++ b/x-pack/plugins/fleet/server/services/agents/actions.ts @@ -8,6 +8,7 @@ import { v4 as uuidv4 } from 'uuid'; import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import apm from 'elastic-apm-node'; +import pMap from 'p-map'; import { partition } from 'lodash'; @@ -33,6 +34,8 @@ import { getAgentIdsForAgentPolicies } from '../agent_policies/agent_policies_to import { getCurrentNamespace } from '../spaces/get_current_namespace'; import { addNamespaceFilteringToQuery } from '../spaces/query_namespaces_filtering'; +import { MAX_CONCURRENT_CREATE_ACTIONS } from '../../constants'; + import { bulkUpdateAgents } from './crud'; const ONE_MONTH_IN_MS = 2592000000; @@ -110,40 +113,47 @@ export async function bulkCreateAgentActions( } const messageSigningService = appContextService.getMessageSigningService(); - await esClient.bulk({ - index: AGENT_ACTIONS_INDEX, - body: await Promise.all( - actions.flatMap(async (action) => { - const body: FleetServerAgentAction = { - '@timestamp': new Date().toISOString(), - expiration: action.expiration ?? new Date(Date.now() + ONE_MONTH_IN_MS).toISOString(), - start_time: action.start_time, - rollout_duration_seconds: action.rollout_duration_seconds, - agents: action.agents, - action_id: action.id, - data: action.data, - type: action.type, - traceparent: apm.currentTraceparent, - }; - if (SIGNED_ACTIONS.has(action.type) && messageSigningService) { - const signedBody = await messageSigningService.sign(body); - body.signed = { - data: signedBody.data.toString('base64'), - signature: signedBody.signature, - }; - } + const fleetServerAgentActions = await pMap( + actions, + async (action) => { + const body: FleetServerAgentAction = { + '@timestamp': new Date().toISOString(), + expiration: action.expiration ?? new Date(Date.now() + ONE_MONTH_IN_MS).toISOString(), + start_time: action.start_time, + rollout_duration_seconds: action.rollout_duration_seconds, + agents: action.agents, + action_id: action.id, + data: action.data, + type: action.type, + traceparent: apm.currentTraceparent, + }; + + if (SIGNED_ACTIONS.has(action.type) && messageSigningService) { + const signedBody = await messageSigningService.sign(body); + body.signed = { + data: signedBody.data.toString('base64'), + signature: signedBody.signature, + }; + } - return [ - { - create: { - _id: action.id, - }, + return [ + { + create: { + _id: action.id, }, - body, - ]; - }) - ), + }, + body, + ].flat(); + }, + { + concurrency: MAX_CONCURRENT_CREATE_ACTIONS, + } + ); + + await esClient.bulk({ + index: AGENT_ACTIONS_INDEX, + body: fleetServerAgentActions, }); for (const action of actions) { diff --git a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts index 314af0ada7bf..6d1945fced80 100644 --- a/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts +++ b/x-pack/plugins/fleet/server/services/agents/agentless_agent.ts @@ -35,7 +35,7 @@ import { appContextService } from '../app_context'; import { listEnrollmentApiKeys } from '../api_keys'; import { listFleetServerHosts } from '../fleet_server_host'; import type { AgentlessConfig } from '../utils/agentless'; -import { prependAgentlessApiBasePathToEndpoint, isAgentlessApiEnabled } from '../utils/agentless'; +import { prependAgentlessApiBasePathToEndpoint, isAgentlessEnabled } from '../utils/agentless'; class AgentlessAgentService { public async createAgentlessAgent( @@ -59,7 +59,7 @@ class AgentlessAgentService { throw new AgentlessAgentConfigError('missing Agentless API configuration in Kibana'); } - if (!isAgentlessApiEnabled()) { + if (!isAgentlessEnabled()) { logger.error( '[Agentless API] Agentless agents are only supported in cloud deployment and serverless projects' ); @@ -179,7 +179,7 @@ class AgentlessAgentService { `[Agentless API] Start deleting agentless agent for agent policy ${requestConfigDebugStatus}` ); - if (!isAgentlessApiEnabled) { + if (!isAgentlessEnabled) { logger.error( '[Agentless API] Agentless API is not supported. Deleting agentless agent is not supported in non-cloud or non-serverless environments' ); @@ -431,45 +431,38 @@ class AgentlessAgentService { 400: { create: { log: '[Agentless API] Creating the agentless agent failed with a status 400, bad request for agentless policy.', - message: - 'the Agentless API could not create the agentless agent. Please delete the agentless policy and try again or contact your administrator.', + message: `the Agentless API could not create the agentless agent. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting the agentless deployment failed with a status 400, bad request for agentless policy', - message: - 'the Agentless API could not create the agentless agent. Please delete the agentless policy try again or contact your administrator.', + message: `the Agentless API could not create the agentless agent. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, 401: { create: { log: '[Agentless API] Creating the agentless agent failed with a status 401 unauthorized for agentless policy.', - message: - 'the Agentless API could not create the agentless agent because an unauthorized request was sent. Please delete the agentless policy and try again or contact your administrator.', + message: `the Agentless API could not create the agentless agent because an unauthorized request was sent. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting the agentless deployment failed with a status 401 unauthorized for agentless policy. Check the Kibana Agentless API tls configuration', - message: - 'the Agentless API could not delete the agentless deployment because an unauthorized request was sent. Please try again or contact your administrator.', + message: `the Agentless API could not delete the agentless deployment because an unauthorized request was sent. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, 403: { create: { log: '[Agentless API] Creating the agentless agent failed with a status 403 forbidden for agentless policy. Check the Kibana Agentless API configuration and endpoints.', - message: - 'the Agentless API could not create the agentless agent because a forbidden request was sent. Please delete the agentless policy and try again or contact your administrator.', + message: `the Agentless API could not create the agentless agent because a forbidden request was sent. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting the agentless deployment failed with a status 403 forbidden for agentless policy. Check the Kibana Agentless API configuration and endpoints.', - message: - 'the Agentless API could not delete the agentless deployment because a forbidden request was sent. Please try again or contact your administrator.', + message: `the Agentless API could not delete the agentless deployment because a forbidden request was sent. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, 404: { // this is likely to happen when creating agentless agents, but covering it in case create: { log: '[Agentless API] Creating the agentless agent failed with a status 404 not found.', - message: - 'the Agentless API could not create the agentless agent because it returned a 404 error not found.', + message: `the Agentless API could not create the agentless agent because it returned a 404 error not found. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting the agentless deployment failed with a status 404 not found', @@ -479,12 +472,11 @@ class AgentlessAgentService { 408: { create: { log: '[Agentless API] Creating the agentless agent failed with a status 408, the request timed out', - message: - 'the Agentless API request timed out waiting for the agentless agent status to respond, please wait a few minutes for the agent to enroll with fleet. If agent fails to enroll with Fleet please delete the agentless policy try again or contact your administrator.', + message: `the Agentless API request timed out waiting for the agentless agent status to respond, please wait a few minutes for the agent to enroll with fleet. If agent fails to enroll with Fleet please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting the agentless deployment failed with a status 408, the request timed out', - message: `the Agentless API could not delete the agentless deployment ${agentlessPolicyId} because the request timed out, please wait a few minutes for the agentless agent deployment to be removed. If it continues to persist please try again or contact your administrator.`, + message: `the Agentless API could not delete the agentless deployment because the request timed out, please wait a few minutes for the agentless agent deployment to be removed. If it continues to persist please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, 429: { @@ -503,36 +495,31 @@ class AgentlessAgentService { 500: { create: { log: '[Agentless API] Creating the agentless agent failed with a status 500 internal service error.', - message: - 'the Agentless API could not create the agentless agent because it returned a 500 internal error. Please delete the agentless policy and try again later or contact your administrator.', + message: `the Agentless API could not create the agentless agent because it returned a 500 internal error. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting the agentless deployment failed with a status 500 internal service error.', - message: - 'the Agentless API could not delete the agentless deployment because it returned a 500 internal error. Please try again later or contact your administrator.', + message: `the Agentless API could not delete the agentless deployment because it returned a 500 internal error. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, unhandled_response: { create: { log: '[Agentless API] Creating agentless agent failed because the Agentless API responded with an unhandled status code that falls out of the range of 2xx:', - message: - 'the Agentless API could not create the agentless agent due to an unexpected error. Please delete the agentless policy and try again later or contact your administrator.', + message: `the Agentless API could not create the agentless agent due to an unexpected error. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting agentless deployment failed because the Agentless API responded with an unhandled status code that falls out of the range of 2xx:', - message: `the Agentless API could not delete the agentless deployment ${agentlessPolicyId}. Please try again later or contact your administrator.`, + message: `the Agentless API could not delete the agentless deployment. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, request_error: { create: { log: '[Agentless API] Creating agentless agent failed with a request error:', - message: - 'the Agentless API could not create the agentless agent due to a request error. Please delete the agentless policy and try again later or contact your administrator.', + message: `the Agentless API could not create the agentless agent due to a request error. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, delete: { log: '[Agentless API] Deleting agentless deployment failed with a request error:', - message: - 'the Agentless API could not delete the agentless deployment due to a request error. Please try again later or contact your administrator.', + message: `the Agentless API could not delete the agentless deployment due to a request error. Please delete the agentless policy ${agentlessPolicyId} and try again or contact your administrator.`, }, }, }; diff --git a/x-pack/plugins/fleet/server/services/agents/status.ts b/x-pack/plugins/fleet/server/services/agents/status.ts index c413ee7e268c..e960a7b955fe 100644 --- a/x-pack/plugins/fleet/server/services/agents/status.ts +++ b/x-pack/plugins/fleet/server/services/agents/status.ts @@ -177,11 +177,17 @@ export async function getAgentStatusForAgentPolicy( }; } -export async function getIncomingDataByAgentsId( - esClient: ElasticsearchClient, - agentsIds: string[], - returnDataPreview: boolean = false -) { +export async function getIncomingDataByAgentsId({ + esClient, + agentsIds, + dataStreamPattern = DATA_STREAM_INDEX_PATTERN, + returnDataPreview = false, +}: { + esClient: ElasticsearchClient; + agentsIds: string[]; + dataStreamPattern?: string; + returnDataPreview?: boolean; +}) { const logger = appContextService.getLogger(); try { @@ -189,7 +195,7 @@ export async function getIncomingDataByAgentsId( body: { index: [ { - names: [DATA_STREAM_INDEX_PATTERN], + names: [dataStreamPattern], privileges: ['read'], }, ], @@ -203,7 +209,7 @@ export async function getIncomingDataByAgentsId( const searchResult = await retryTransientEsErrors( () => esClient.search({ - index: DATA_STREAM_INDEX_PATTERN, + index: dataStreamPattern, allow_partial_search_results: true, _source: returnDataPreview, timeout: '5s', @@ -244,9 +250,9 @@ export async function getIncomingDataByAgentsId( if (!searchResult.aggregations?.agent_ids) { return { items: agentsIds.map((id) => { - return { items: { [id]: { data: false } } }; + return { [id]: { data: false } }; }), - data: [], + dataPreview: [], }; } diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts index 6a14c1c301aa..eafda9a99e4f 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/install.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import { ElasticsearchAssetType, @@ -18,6 +19,8 @@ import { getAssetFromAssetsMap } from '../../archive'; import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; +import { MAX_CONCURRENT_DATASTREAMS_ILM_OPERATIONS } from '../../../../constants'; + import { deleteIlms } from './remove'; interface IlmInstallation { @@ -111,11 +114,15 @@ export const installIlmForDataStream = async ( } ); - const installationPromises = ilmInstallations.map(async (ilmInstallation) => { - return handleIlmInstall({ esClient, ilmInstallation, logger }); - }); - - installedIlms = await Promise.all(installationPromises).then((results) => results.flat()); + installedIlms = await pMap( + ilmInstallations, + async (ilmInstallation) => { + return handleIlmInstall({ esClient, ilmInstallation, logger }); + }, + { + concurrency: MAX_CONCURRENT_DATASTREAMS_ILM_OPERATIONS, + } + ).then((results) => results.flat()); } return { installedIlms, esReferences }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts index 331088d195d0..b8f484993475 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/datastream_ilm/remove.ts @@ -7,9 +7,17 @@ import type { ElasticsearchClient } from '@kbn/core/server'; +import pMap from 'p-map'; + +import { appContextService } from '../../../app_context'; +import { MAX_CONCURRENT_ILM_POLICIES_OPERATIONS } from '../../../../constants'; + export const deleteIlms = async (esClient: ElasticsearchClient, ilmPolicyIds: string[]) => { - await Promise.all( - ilmPolicyIds.map(async (ilmPolicyId) => { + const logger = appContextService.getLogger(); + + await pMap( + ilmPolicyIds, + async (ilmPolicyId) => { await esClient.transport.request( { method: 'DELETE', @@ -19,6 +27,10 @@ export const deleteIlms = async (esClient: ElasticsearchClient, ilmPolicyIds: st ignore: [404, 400], } ); - }) + logger.debug(`Deleted ilm policy with id: ${ilmPolicyId}`); + }, + { + concurrency: MAX_CONCURRENT_ILM_POLICIES_OPERATIONS, + } ); }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts index 6596650a94c5..1203ec02ba9a 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ilm/install.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import type { EsAssetReference } from '../../../../types'; @@ -16,6 +17,7 @@ import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; import { PackageInvalidArchiveError } from '../../../../errors'; import type { PackageInstallContext } from '../../../../../common/types'; +import { MAX_CONCURRENT_ILM_POLICIES_OPERATIONS } from '../../../../constants'; export async function installILMPolicy( packageInstallContext: PackageInstallContext, @@ -48,8 +50,9 @@ export async function installILMPolicy( })), }); - await Promise.all( - ilmPolicies.map(async (policy) => { + await pMap( + ilmPolicies, + async (policy) => { try { await retryTransientEsErrors( () => @@ -63,7 +66,10 @@ export async function installILMPolicy( } catch (err) { throw new PackageInvalidArchiveError(`Couldn't install ilm policies: ${err.message}`); } - }) + }, + { + concurrency: MAX_CONCURRENT_ILM_POLICIES_OPERATIONS, + } ); return esReferences; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts index aab876652756..242365d5cc21 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ingest_pipeline/remove.ts @@ -7,11 +7,14 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; + import { appContextService } from '../../..'; import { ElasticsearchAssetType } from '../../../../types'; import { FleetError } from '../../../../errors'; import type { EsAssetReference } from '../../../../../common/types'; import { updateEsAssetReferences } from '../../packages/es_assets_reference'; +import { MAX_CONCURRENT_PIPELINES_DELETIONS } from '../../../../constants'; export const deletePreviousPipelines = async ( esClient: ElasticsearchClient, @@ -26,10 +29,15 @@ export const deletePreviousPipelines = async ( type === ElasticsearchAssetType.ingestPipeline && id.includes(previousPkgVersion) ); try { - await Promise.all( - installedPipelines.map(({ type, id }) => { + await pMap( + installedPipelines, + ({ type, id }) => { + logger.debug(`Deleting pipeline with id: ${id}`); return deletePipeline(esClient, id); - }) + }, + { + concurrency: MAX_CONCURRENT_PIPELINES_DELETIONS, + } ); } catch (e) { logger.error(e); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts index 3abd19bd8035..7852787da0d7 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/ml_model/remove.ts @@ -7,17 +7,24 @@ import type { ElasticsearchClient } from '@kbn/core/server'; +import pMap from 'p-map'; + import { appContextService } from '../../../app_context'; +import { MAX_CONCURRENT_ML_MODELS_OPERATIONS } from '../../../../constants'; export const deleteMlModel = async (esClient: ElasticsearchClient, mlModelIds: string[]) => { const logger = appContextService.getLogger(); if (mlModelIds.length) { logger.info(`Deleting currently installed ml model ids ${mlModelIds}`); } - await Promise.all( - mlModelIds.map(async (modelId) => { + await pMap( + mlModelIds, + async (modelId) => { await esClient.ml.deleteTrainedModel({ model_id: modelId }, { ignore: [404] }); logger.info(`Deleted: ${modelId}`); - }) + }, + { + concurrency: MAX_CONCURRENT_ML_MODELS_OPERATIONS, + } ); }; diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts index 2a17768ac1f9..a15e8cb71923 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/install.ts @@ -8,6 +8,7 @@ import { merge, concat, uniqBy, omit } from 'lodash'; import Boom from '@hapi/boom'; import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import pMap from 'p-map'; import type { IndicesCreateRequest, @@ -38,6 +39,7 @@ import { PACKAGE_TEMPLATE_SUFFIX, USER_SETTINGS_TEMPLATE_SUFFIX, STACK_COMPONENT_TEMPLATES, + MAX_CONCURRENT_COMPONENT_TEMPLATES, } from '../../../../constants'; import { getESAssetMetadata } from '../meta'; import { retryTransientEsErrors } from '../retry'; @@ -103,15 +105,18 @@ export const prepareToInstallTemplates = ( await installPreBuiltComponentTemplates(packageInstallContext, esClient, logger); await installPreBuiltTemplates(packageInstallContext, esClient, logger); - await Promise.all( - templates.map((template) => + await pMap( + templates, + (template) => installComponentAndIndexTemplateForDataStream({ esClient, logger, componentTemplates: template.componentTemplates, indexTemplate: template.indexTemplate, - }) - ) + }), + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } ); return templates.map((template) => template.indexTemplate); @@ -125,32 +130,37 @@ const installPreBuiltTemplates = async ( logger: Logger ) => { const templatePaths = packageInstallContext.paths.filter((path) => isTemplate(path)); - const templateInstallPromises = templatePaths.map(async (path) => { - const { file } = getPathParts(path); - const templateName = file.substr(0, file.lastIndexOf('.')); - const content = JSON.parse( - getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') - ); - - const esClientParams = { name: templateName, body: content }; - const esClientRequestOptions = { ignore: [404] }; - - if (Object.hasOwn(content, 'template') || Object.hasOwn(content, 'composed_of')) { - // Template is v2 - return retryTransientEsErrors( - () => esClient.indices.putIndexTemplate(esClientParams, esClientRequestOptions), - { logger } - ); - } else { - // template is V1 - return retryTransientEsErrors( - () => esClient.indices.putTemplate(esClientParams, esClientRequestOptions), - { logger } - ); - } - }); try { - return await Promise.all(templateInstallPromises); + await pMap( + templatePaths, + async (path) => { + const { file } = getPathParts(path); + const templateName = file.substr(0, file.lastIndexOf('.')); + const content = JSON.parse( + getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') + ); + + const esClientParams = { name: templateName, body: content }; + const esClientRequestOptions = { ignore: [404] }; + + if (Object.hasOwn(content, 'template') || Object.hasOwn(content, 'composed_of')) { + // Template is v2 + return retryTransientEsErrors( + () => esClient.indices.putIndexTemplate(esClientParams, esClientRequestOptions), + { logger } + ); + } else { + // template is V1 + return retryTransientEsErrors( + () => esClient.indices.putTemplate(esClientParams, esClientRequestOptions), + { logger } + ); + } + }, + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } + ); } catch (e) { throw new Boom.Boom(`Error installing prebuilt index templates ${e.message}`, { statusCode: 400, @@ -164,26 +174,30 @@ const installPreBuiltComponentTemplates = async ( logger: Logger ) => { const templatePaths = packageInstallContext.paths.filter((path) => isComponentTemplate(path)); - const templateInstallPromises = templatePaths.map(async (path) => { - const { file } = getPathParts(path); - const templateName = file.substr(0, file.lastIndexOf('.')); - const content = JSON.parse( - getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') - ); - - const esClientParams = { - name: templateName, - body: content, - }; - - return retryTransientEsErrors( - () => esClient.cluster.putComponentTemplate(esClientParams, { ignore: [404] }), - { logger } - ); - }); - try { - return await Promise.all(templateInstallPromises); + await pMap( + templatePaths, + async (path) => { + const { file } = getPathParts(path); + const templateName = file.substr(0, file.lastIndexOf('.')); + const content = JSON.parse( + getAssetFromAssetsMap(packageInstallContext.assetsMap, path).toString('utf8') + ); + + const esClientParams = { + name: templateName, + body: content, + }; + + return retryTransientEsErrors( + () => esClient.cluster.putComponentTemplate(esClientParams, { ignore: [404] }), + { logger } + ); + }, + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } + ); } catch (e) { throw new Boom.Boom(`Error installing prebuilt component templates ${e.message}`, { statusCode: 400, @@ -450,8 +464,9 @@ async function installDataStreamComponentTemplates({ logger: Logger; componentTemplates: TemplateMap; }) { - await Promise.all( - Object.entries(componentTemplates).map(async ([name, body]) => { + await pMap( + Object.entries(componentTemplates), + async ([name, body]) => { // @custom component template should be lazily created by user if (isUserSettingsTemplate(name)) { return; @@ -459,7 +474,10 @@ async function installDataStreamComponentTemplates({ const { clusterPromise } = putComponentTemplate(esClient, logger, { body, name }); return clusterPromise; - }) + }, + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } ); } @@ -467,10 +485,12 @@ export async function ensureDefaultComponentTemplates( esClient: ElasticsearchClient, logger: Logger ) { - return Promise.all( - FLEET_COMPONENT_TEMPLATES.map(({ name, body }) => - ensureComponentTemplate(esClient, logger, name, body) - ) + return await pMap( + FLEET_COMPONENT_TEMPLATES, + ({ name, body }) => ensureComponentTemplate(esClient, logger, name, body), + { + concurrency: MAX_CONCURRENT_COMPONENT_TEMPLATES, + } ); } diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts index c06d0cdbb642..dbc93e35c821 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.test.ts @@ -1900,9 +1900,19 @@ describe('EPM template', () => { it('should fill constant keywords from previous mappings', async () => { const esClient = elasticsearchServiceMock.createElasticsearchClient(); + esClient.indices.getDataStream.mockResponse({ - data_streams: [{ name: 'test-constant.keyword-default' }], + data_streams: [ + { + name: 'test-constant.keyword-default', + indices: [ + { index_name: '.ds-test-constant.keyword-default-0001' }, + { index_name: '.ds-test-constant.keyword-default-0002' }, + ], + }, + ], } as any); + esClient.indices.get.mockResponse({ 'test-constant.keyword-default': { mappings: { @@ -1942,6 +1952,9 @@ describe('EPM template', () => { } as any, }, ]); + expect(esClient.indices.get).toBeCalledWith({ + index: '.ds-test-constant.keyword-default-0002', + }); const putMappingsCalls = esClient.indices.putMapping.mock.calls; expect(putMappingsCalls).toHaveLength(1); expect(putMappingsCalls[0][0]).toEqual({ diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts index b9c0846f3e4f..b6d357193b14 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/template/template.ts @@ -19,6 +19,7 @@ import { FLEET_EVENT_INGESTED_COMPONENT_TEMPLATE_NAME, STACK_COMPONENT_TEMPLATE_LOGS_MAPPINGS, } from '../../../../constants/fleet_es_assets'; +import { MAX_CONCURRENT_DATASTREAM_OPERATIONS } from '../../../../constants'; import type { Field, Fields } from '../../fields/field'; import type { @@ -65,6 +66,7 @@ export interface CurrentDataStream { dataStreamName: string; replicated: boolean; indexTemplate: IndexTemplate; + currentWriteIndex: string; } const DEFAULT_IGNORE_ABOVE = 1024; @@ -930,10 +932,15 @@ const queryDataStreamsFromTemplates = async ( esClient: ElasticsearchClient, templates: IndexTemplateEntry[] ): Promise<CurrentDataStream[]> => { - const dataStreamPromises = templates.map((template) => { - return getDataStreams(esClient, template); - }); - const dataStreamObjects = await Promise.all(dataStreamPromises); + const dataStreamObjects = await pMap( + templates, + (template) => { + return getDataStreams(esClient, template); + }, + { + concurrency: MAX_CONCURRENT_DATASTREAM_OPERATIONS, + } + ); return dataStreamObjects.filter(isCurrentDataStream).flat(); }; @@ -954,6 +961,7 @@ const getDataStreams = async ( dataStreamName: dataStream.name, replicated: dataStream.replicated, indexTemplate, + currentWriteIndex: dataStream.indices?.at(-1)?.index_name, })); }; @@ -989,24 +997,26 @@ const updateAllDataStreams = async ( return updateExistingDataStream({ esClient, logger, + currentWriteIndex: templateEntry.currentWriteIndex, dataStreamName: templateEntry.dataStreamName, options, }); }, { - // Limit concurrent putMapping/rollover requests to avoid overwhelming ES cluster - concurrency: 20, + concurrency: MAX_CONCURRENT_DATASTREAM_OPERATIONS, } ); }; const updateExistingDataStream = async ({ dataStreamName, + currentWriteIndex, esClient, logger, options, }: { dataStreamName: string; + currentWriteIndex: string; esClient: ElasticsearchClient; logger: Logger; options?: { @@ -1015,7 +1025,7 @@ const updateExistingDataStream = async ({ }; }) => { const existingDs = await esClient.indices.get({ - index: dataStreamName, + index: currentWriteIndex, }); const existingDsConfig = Object.values(existingDs); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts index cbdde6feee64..85ae293455c9 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/install.ts @@ -10,6 +10,7 @@ import { errors } from '@elastic/elasticsearch'; import { load } from 'js-yaml'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import { uniqBy } from 'lodash'; +import pMap from 'p-map'; import type { HTTPAuthorizationHeader } from '../../../../../common/http_authorization_header'; @@ -44,6 +45,8 @@ import { getInstallation } from '../../packages'; import { retryTransientEsErrors } from '../retry'; import { isUserSettingsTemplate } from '../template/utils'; +import { MAX_CONCURRENT_TRANSFORMS_OPERATIONS } from '../../../../constants'; + import { deleteTransforms } from './remove'; import { getDestinationIndexAliases } from './transform_utils'; import { loadMappingForTransform } from './mappings'; @@ -573,17 +576,21 @@ const installTransformsAssets = async ( } } else { // Else, create & start all the transforms at once for speed - const transformsPromises = transforms.map(async (transform) => { - return handleTransformInstall({ - esClient, - logger, - transform, - startTransform: transformsSpecifications.get(transform.transformModuleId)?.get('start'), - secondaryAuth: transform.runAsKibanaSystem !== false ? undefined : secondaryAuth, - }); - }); - - installedTransforms = await Promise.all(transformsPromises).then((results) => results.flat()); + installedTransforms = await pMap( + transforms, + async (transform) => { + return handleTransformInstall({ + esClient, + logger, + transform, + startTransform: transformsSpecifications.get(transform.transformModuleId)?.get('start'), + secondaryAuth: transform.runAsKibanaSystem !== false ? undefined : secondaryAuth, + }); + }, + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } + ).then((results) => results.flat()); } // If user does not have sufficient permissions to start the transforms, diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts index d1a492cb213a..8d53a952608f 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/reauthorize.ts @@ -10,6 +10,7 @@ import type { Logger } from '@kbn/logging'; import type { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { sortBy, uniqBy } from 'lodash'; +import pMap from 'p-map'; import { isPopulatedObject } from '@kbn/ml-is-populated-object'; import type { ErrorResponseBase } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; @@ -19,6 +20,7 @@ import type { Installation } from '../../../../../common'; import { ElasticsearchAssetType, PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common'; import { retryTransientEsErrors } from '../retry'; +import { MAX_CONCURRENT_TRANSFORMS_OPERATIONS } from '../../../../constants'; interface FleetTransformMetadata { fleet_transform_version?: string; @@ -119,8 +121,9 @@ export async function handleTransformReauthorizeAndStart({ ); } - const transformInfos = await Promise.all( - transforms.map(({ transformId }) => + const transformInfos = await pMap( + transforms, + ({ transformId }) => retryTransientEsErrors( () => esClient.transform.getTransform( @@ -130,8 +133,10 @@ export async function handleTransformReauthorizeAndStart({ { ...(secondaryAuth ? secondaryAuth : {}), ignore: [404] } ), { logger, additionalResponseStatuses: [400] } - ) - ) + ), + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } ); const transformsMetadata: FleetTransformMetadata[] = transformInfos @@ -168,17 +173,20 @@ export async function handleTransformReauthorizeAndStart({ } } else { // Else, create & start all the transforms at once for speed - const transformsPromises = transformsMetadata.map(async ({ transformId, ...meta }) => { - return await reauthorizeAndStartTransform({ - esClient, - logger, - transformId, - secondaryAuth, - meta: { ...meta, last_authorized_by: username }, - }); - }); - - authorizedTransforms = await Promise.all(transformsPromises).then((results) => results.flat()); + authorizedTransforms = await pMap( + transformsMetadata, + async ({ transformId, ...meta }) => + reauthorizeAndStartTransform({ + esClient, + logger, + transformId, + secondaryAuth, + meta: { ...meta, last_authorized_by: username }, + }), + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } + ).then((results) => results.flat()); } const so = await savedObjectsClient.get<Installation>(PACKAGES_SAVED_OBJECT_TYPE, pkgName); diff --git a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts index 4149d1589916..8a2d5cd13c59 100644 --- a/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/elasticsearch/transform/remove.ts @@ -6,6 +6,7 @@ */ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import type { SecondaryAuthorizationHeader } from '../../../../../common/types/models/transform_api_key'; import { ElasticsearchAssetType } from '../../../../types'; @@ -14,6 +15,7 @@ import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../../../common/constants'; import { appContextService } from '../../../app_context'; import { retryTransientEsErrors } from '../retry'; +import { MAX_CONCURRENT_TRANSFORMS_OPERATIONS } from '../../../../constants'; export const stopTransforms = async (transformIds: string[], esClient: ElasticsearchClient) => { for (const transformId of transformIds) { @@ -34,8 +36,10 @@ export const deleteTransforms = async ( if (transformIds.length) { logger.info(`Deleting currently installed transform ids ${transformIds}`); } - await Promise.all( - transformIds.map(async (transformId) => { + + await pMap( + transformIds, + async (transformId) => { await stopTransforms([transformId], esClient); await retryTransientEsErrors(() => esClient.transform.deleteTransform( @@ -48,7 +52,10 @@ export const deleteTransforms = async ( ) ); logger.info(`Deleted: ${transformId}`); - }) + }, + { + concurrency: MAX_CONCURRENT_TRANSFORMS_OPERATIONS, + } ); }; diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts index 3ae1c4a6cffb..3ecdfe02319a 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/index_pattern/install.ts @@ -6,10 +6,12 @@ */ import type { SavedObjectsClientContract } from '@kbn/core/server'; +import pMap from 'p-map'; import { dataTypes, installationStatuses } from '../../../../../common/constants'; import { appContextService } from '../../..'; import { getPackageSavedObjects } from '../../packages/get'; +import { MAX_CONCURRENT_INDEX_PATTERN_OPERATIONS } from '../../../../constants'; const INDEX_PATTERN_SAVED_OBJECT_TYPE = 'index-pattern'; export const indexPatternTypes = [dataTypes.Logs, dataTypes.Metrics]; @@ -72,9 +74,9 @@ export async function removeUnusedIndexPatterns(savedObjectsClient: SavedObjects // eslint-disable-next-line @typescript-eslint/naming-convention const idsToDelete = resolvedObjects.map(({ saved_object }) => saved_object.id); - - return Promise.all( - idsToDelete.map(async (id) => { + await pMap( + idsToDelete, + async (id) => { try { logger.debug(`deleting index pattern ${id}`); await savedObjectsClient.delete(INDEX_PATTERN_SAVED_OBJECT_TYPE, id); @@ -83,6 +85,9 @@ export async function removeUnusedIndexPatterns(savedObjectsClient: SavedObjects logger.debug(`Non fatal error encountered deleting index pattern ${id} : ${err}`); } return; - }) + }, + { + concurrency: MAX_CONCURRENT_INDEX_PATTERN_OPERATIONS, + } ); } diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts b/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts index eeaa80b0c944..e72b218ab1fc 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.mock.ts @@ -17,6 +17,7 @@ const createClientMock = (): jest.Mocked<PackageClient> => ({ fetchFindLatestPackage: jest.fn(), readBundledPackage: jest.fn(), getAgentPolicyConfigYAML: jest.fn(), + getLatestPackageInfo: jest.fn(), getPackage: jest.fn(), getPackageFieldsMetadata: jest.fn(), getPackages: jest.fn(), diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.test.ts b/x-pack/plugins/fleet/server/services/epm/package_service.test.ts index 479d355c00e6..ea7586b9ebd7 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.test.ts @@ -43,6 +43,7 @@ const testKeys = [ 'getInstallation', 'ensureInstalledPackage', 'fetchFindLatestPackage', + 'getLatestPackageInfo', 'getPackage', 'getPackageFieldsMetadata', 'reinstallEsAssets', @@ -112,6 +113,23 @@ function getTest( }; break; case testKeys[3]: + test = { + method: mocks.packageClient.getLatestPackageInfo.bind(mocks.packageClient), + args: ['package name'], + spy: jest.spyOn(epmPackagesGet, 'getPackageInfo'), + spyArgs: [ + { + pkgName: 'package name', + pkgVersion: '', + savedObjectsClient: mocks.soClient, + prerelease: undefined, + }, + ], + spyResponse: { name: 'getLatestPackageInfo test' }, + expectedReturnValue: { name: 'getLatestPackageInfo test' }, + }; + break; + case testKeys[4]: test = { method: mocks.packageClient.getPackage.bind(mocks.packageClient), args: ['package name', '8.0.0'], @@ -127,7 +145,7 @@ function getTest( }, }; break; - case testKeys[4]: + case testKeys[5]: test = { method: mocks.packageClient.getPackageFieldsMetadata.bind(mocks.packageClient), args: [{ packageName: 'package_name', datasetName: 'dataset_name' }], @@ -141,7 +159,7 @@ function getTest( }, }; break; - case testKeys[5]: + case testKeys[6]: const pkg: InstallablePackage = { format_version: '1.0.0', name: 'package name', @@ -187,7 +205,7 @@ function getTest( ], }; break; - case testKeys[6]: + case testKeys[7]: const bundledPackage = { name: 'package name', version: '8.0.0', diff --git a/x-pack/plugins/fleet/server/services/epm/package_service.ts b/x-pack/plugins/fleet/server/services/epm/package_service.ts index a097db584b46..782aeffb6a85 100644 --- a/x-pack/plugins/fleet/server/services/epm/package_service.ts +++ b/x-pack/plugins/fleet/server/services/epm/package_service.ts @@ -56,6 +56,7 @@ import { getPackages, installPackage, getTemplateInputs, + getPackageInfo, } from './packages'; import { generatePackageInfoFromArchiveBuffer } from './archive'; import { getEsPackage } from './archive/storage'; @@ -113,6 +114,11 @@ export interface PackageClient { options?: Parameters<typeof getPackageFieldsMetadata>['1'] ): ReturnType<typeof getPackageFieldsMetadata>; + getLatestPackageInfo( + packageName: string, + prerelease?: boolean + ): ReturnType<typeof getPackageInfo>; + getPackages(params?: { excludeInstallStatus?: false; category?: CategoryId; @@ -328,6 +334,16 @@ class PackageClientImpl implements PackageClient { return getPackageFieldsMetadata(params, options); } + public async getLatestPackageInfo(packageName: string, prerelease?: boolean) { + await this.#runPreflight(READ_PACKAGE_INFO_AUTHZ); + return getPackageInfo({ + savedObjectsClient: this.internalSoClient, + pkgName: packageName, + pkgVersion: '', + prerelease, + }); + } + public async getPackages(params?: { excludeInstallStatus?: false; category?: CategoryId; diff --git a/x-pack/plugins/fleet/server/services/epm/packages/get.ts b/x-pack/plugins/fleet/server/services/epm/packages/get.ts index 2ab085606336..5b0e3df279cd 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/get.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/get.ts @@ -39,7 +39,10 @@ import type { PackageSpecManifest, AssetsMap, } from '../../../../common/types'; -import { PACKAGES_SAVED_OBJECT_TYPE } from '../../../constants'; +import { + PACKAGES_SAVED_OBJECT_TYPE, + MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS, +} from '../../../constants'; import type { ArchivePackage, RegistryPackage, @@ -142,7 +145,7 @@ export async function getPackages( ); } }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ) ).filter((p): p is Installable<any> => p !== null); diff --git a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts index 84c8a8eb9e10..0557027a3c0a 100644 --- a/x-pack/plugins/fleet/server/services/epm/packages/remove.ts +++ b/x-pack/plugins/fleet/server/services/epm/packages/remove.ts @@ -17,10 +17,12 @@ import { SavedObjectsUtils, SavedObjectsErrorHelpers } from '@kbn/core/server'; import minVersion from 'semver/ranges/min-version'; import { chunk } from 'lodash'; +import pMap from 'p-map'; import { updateIndexSettings } from '../elasticsearch/index/update_settings'; import { + MAX_CONCURRENT_ES_ASSETS_OPERATIONS, PACKAGE_POLICY_SAVED_OBJECT_TYPE, PACKAGES_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT, @@ -209,29 +211,36 @@ async function bulkDeleteSavedObjects( } } -export function deleteESAssets( +export const deleteESAsset = async ( + installedObject: EsAssetReference, + esClient: ElasticsearchClient +): Promise<void> => { + const { id, type } = installedObject; + const assetType = type as AssetType; + if (assetType === ElasticsearchAssetType.ingestPipeline) { + return deletePipeline(esClient, id); + } else if (assetType === ElasticsearchAssetType.indexTemplate) { + return deleteIndexTemplate(esClient, id); + } else if (assetType === ElasticsearchAssetType.componentTemplate) { + return deleteComponentTemplate(esClient, id); + } else if (assetType === ElasticsearchAssetType.transform) { + return deleteTransforms(esClient, [id], true); + } else if (assetType === ElasticsearchAssetType.dataStreamIlmPolicy) { + return deleteIlms(esClient, [id]); + } else if (assetType === ElasticsearchAssetType.ilmPolicy) { + return deleteIlms(esClient, [id]); + } else if (assetType === ElasticsearchAssetType.mlModel) { + return deleteMlModel(esClient, [id]); + } +}; + +export const deleteESAssets = ( installedObjects: EsAssetReference[], esClient: ElasticsearchClient -): Array<Promise<unknown>> { - return installedObjects.map(async ({ id, type }) => { - const assetType = type as AssetType; - if (assetType === ElasticsearchAssetType.ingestPipeline) { - return deletePipeline(esClient, id); - } else if (assetType === ElasticsearchAssetType.indexTemplate) { - return deleteIndexTemplate(esClient, id); - } else if (assetType === ElasticsearchAssetType.componentTemplate) { - return deleteComponentTemplate(esClient, id); - } else if (assetType === ElasticsearchAssetType.transform) { - return deleteTransforms(esClient, [id], true); - } else if (assetType === ElasticsearchAssetType.dataStreamIlmPolicy) { - return deleteIlms(esClient, [id]); - } else if (assetType === ElasticsearchAssetType.ilmPolicy) { - return deleteIlms(esClient, [id]); - } else if (assetType === ElasticsearchAssetType.mlModel) { - return deleteMlModel(esClient, [id]); - } - }); -} +): Array<Promise<void>> => { + return installedObjects.map((installedObject) => deleteESAsset(installedObject, esClient)); +}; + type Tuple = [EsAssetReference[], EsAssetReference[], EsAssetReference[], EsAssetReference[]]; export const splitESAssets = (installedEs: EsAssetReference[]) => { @@ -291,16 +300,24 @@ export async function deletePrerequisiteAssets( try { // must first unset any default pipeline associated with any existing indices // by setting empty string - await Promise.all( - indexAssets.map((asset) => updateIndexSettings(esClient, asset.id, { default_pipeline: '' })) + await pMap( + indexAssets, + (asset) => updateIndexSettings(esClient, asset.id, { default_pipeline: '' }), + { + concurrency: MAX_CONCURRENT_ES_ASSETS_OPERATIONS, + } ); // in case transform's destination index contains any pipeline, // we should delete the transforms first - await Promise.all(deleteESAssets(transformAssets, esClient)); + await pMap(transformAssets, (transformAsset) => deleteESAsset(transformAsset, esClient), { + concurrency: MAX_CONCURRENT_ES_ASSETS_OPERATIONS, + }); // then delete index templates and pipelines - await Promise.all(deleteESAssets(indexTemplatesAndPipelines, esClient)); + await pMap(indexTemplatesAndPipelines, (asset) => deleteESAsset(asset, esClient), { + concurrency: MAX_CONCURRENT_ES_ASSETS_OPERATIONS, + }); } catch (err) { // in the rollback case, partial installs are likely, so missing assets are not an error if (!SavedObjectsErrorHelpers.isNotFoundError(err)) { diff --git a/x-pack/plugins/fleet/server/services/files/index.ts b/x-pack/plugins/fleet/server/services/files/index.ts index c7a00ee597f6..0598155153ce 100644 --- a/x-pack/plugins/fleet/server/services/files/index.ts +++ b/x-pack/plugins/fleet/server/services/files/index.ts @@ -8,6 +8,7 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import type { SearchHit, UpdateByQueryResponse } from '@elastic/elasticsearch/lib/api/types'; import type { FileStatus } from '@kbn/files-plugin/common/types'; +import pMap from 'p-map'; import { FILE_STORAGE_DATA_INDEX_PATTERN, @@ -20,6 +21,8 @@ import { getFileMetadataIndexName } from '../../../common/services'; import { ES_SEARCH_LIMIT } from '../../../common/constants'; +import { MAX_CONCURRENT_AGENT_FILES_UPLOADS } from '../../constants'; + import { parseFileStorageIndex } from './utils'; /** @@ -145,14 +148,15 @@ export async function fileIdsWithoutChunksByIndex( * @param fileIdsByIndex * @param status */ -export function updateFilesStatus( +export async function updateFilesStatus( esClient: ElasticsearchClient, abortController: AbortController | undefined, fileIdsByIndex: FileIdsByIndex, status: FileStatus ): Promise<UpdateByQueryResponse[]> { - return Promise.all( - Object.entries(fileIdsByIndex).map(([index, fileIds]) => { + return await pMap( + Object.entries(fileIdsByIndex), + ([index, fileIds]) => { return esClient .updateByQuery( { @@ -174,6 +178,9 @@ export function updateFilesStatus( Error.captureStackTrace(err); throw err; }); - }) + }, + { + concurrency: MAX_CONCURRENT_AGENT_FILES_UPLOADS, + } ); } diff --git a/x-pack/plugins/fleet/server/services/fleet_proxies.ts b/x-pack/plugins/fleet/server/services/fleet_proxies.ts index 4cfc81db5074..e60c15577bdc 100644 --- a/x-pack/plugins/fleet/server/services/fleet_proxies.ts +++ b/x-pack/plugins/fleet/server/services/fleet_proxies.ts @@ -13,7 +13,11 @@ import type { import { omit } from 'lodash'; import pMap from 'p-map'; -import { FLEET_PROXY_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT } from '../constants'; +import { + FLEET_PROXY_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, + MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS, +} from '../constants'; import { FleetProxyUnauthorizedError } from '../errors'; import type { DownloadSource, @@ -206,7 +210,7 @@ async function updateRelatedSavedObject( ...omit(fleetServerHost, 'id'), proxy_id: null, }), - { concurrency: 20 } + { concurrency: MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS } ); await pMap( @@ -216,7 +220,7 @@ async function updateRelatedSavedObject( ...omit(output, 'id'), proxy_id: null, } as Partial<Output>), - { concurrency: 20 } + { concurrency: MAX_CONCURRENT_FLEET_PROXIES_OPERATIONS } ); await pMap(downloadSources, (downloadSource) => diff --git a/x-pack/plugins/fleet/server/services/output.ts b/x-pack/plugins/fleet/server/services/output.ts index ceecd29562fc..0b30890ee566 100644 --- a/x-pack/plugins/fleet/server/services/output.ts +++ b/x-pack/plugins/fleet/server/services/output.ts @@ -44,6 +44,7 @@ import { DEFAULT_OUTPUT_ID, OUTPUT_SAVED_OBJECT_TYPE, OUTPUT_HEALTH_DATA_STREAM, + MAX_CONCURRENT_BACKFILL_OUTPUTS_PRESETS, } from '../constants'; import { SO_SEARCH_LIMIT, @@ -1165,7 +1166,7 @@ class OutputService { await agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, output.id); }, { - concurrency: 5, + concurrency: MAX_CONCURRENT_BACKFILL_OUTPUTS_PRESETS, } ); } diff --git a/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context_mocks.ts b/x-pack/plugins/fleet/server/services/output_client.mock.ts similarity index 69% rename from x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context_mocks.ts rename to x-pack/plugins/fleet/server/services/output_client.mock.ts index dcd5d681b34b..ba684a2aff61 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context_mocks.ts +++ b/x-pack/plugins/fleet/server/services/output_client.mock.ts @@ -11,6 +11,11 @@ * 2.0. */ -export const mockReportCardOpen = jest.fn(); -export const mockReportCardComplete = jest.fn(); -export const mockReportCardLinkClicked = jest.fn(); +import type { OutputClientInterface } from './output_client'; + +export const createOutputClientMock = (): jest.Mocked<OutputClientInterface> => { + return { + getDefaultDataOutputId: jest.fn(), + get: jest.fn(), + }; +}; diff --git a/x-pack/plugins/fleet/server/services/output_client.test.ts b/x-pack/plugins/fleet/server/services/output_client.test.ts new file mode 100644 index 000000000000..f3d4b83bea4b --- /dev/null +++ b/x-pack/plugins/fleet/server/services/output_client.test.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { savedObjectsClientMock } from '@kbn/core/server/mocks'; + +import { createFleetAuthzMock } from '../../common/mocks'; + +import { OutputClient } from './output_client'; +import { outputService } from './output'; + +jest.mock('./output'); + +const mockedOutputService = outputService as jest.Mocked<typeof outputService>; + +describe('OutputClient', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('getDefaultDataOutputId()', () => { + it('should call output service `getDefaultDataOutputId()` method', async () => { + const soClient = savedObjectsClientMock.create(); + const authz = createFleetAuthzMock(); + const outputClient = new OutputClient(soClient, authz); + await outputClient.getDefaultDataOutputId(); + + expect(mockedOutputService.getDefaultDataOutputId).toHaveBeenCalledWith(soClient); + }); + + it('should throw error when no `fleet.readSettings` and no `fleet.readAgentPolicies` privileges', async () => { + const soClient = savedObjectsClientMock.create(); + const authz = createFleetAuthzMock(); + authz.fleet.readSettings = false; + authz.fleet.readAgentPolicies = false; + const outputClient = new OutputClient(soClient, authz); + + await expect(outputClient.getDefaultDataOutputId()).rejects.toMatchInlineSnapshot( + `[OutputUnauthorizedError]` + ); + expect(mockedOutputService.getDefaultDataOutputId).not.toHaveBeenCalled(); + }); + }); + + describe('get()', () => { + it('should call output service `get()` method', async () => { + const soClient = savedObjectsClientMock.create(); + const authz = createFleetAuthzMock(); + const outputClient = new OutputClient(soClient, authz); + await outputClient.get('default'); + + expect(mockedOutputService.get).toHaveBeenCalledWith(soClient, 'default'); + }); + + it('should throw error when no `fleet.readSettings` and no `fleet.readAgentPolicies` privileges', async () => { + const soClient = savedObjectsClientMock.create(); + const authz = createFleetAuthzMock(); + authz.fleet.readSettings = false; + authz.fleet.readAgentPolicies = false; + const outputClient = new OutputClient(soClient, authz); + + await expect(outputClient.get('default')).rejects.toMatchInlineSnapshot( + `[OutputUnauthorizedError]` + ); + expect(mockedOutputService.get).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/x-pack/plugins/fleet/server/services/output_client.ts b/x-pack/plugins/fleet/server/services/output_client.ts new file mode 100644 index 000000000000..574446e1f32a --- /dev/null +++ b/x-pack/plugins/fleet/server/services/output_client.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectsClientContract } from '@kbn/core/server'; + +import type { FleetAuthz } from '../../common'; + +import { OutputUnauthorizedError } from '../errors'; +import type { Output } from '../types'; + +import { outputService } from './output'; + +export { transformOutputToFullPolicyOutput } from './agent_policies/full_agent_policy'; + +export interface OutputClientInterface { + getDefaultDataOutputId(): Promise<string | null>; + get(outputId: string): Promise<Output>; +} + +export class OutputClient implements OutputClientInterface { + constructor(private soClient: SavedObjectsClientContract, private authz: FleetAuthz) {} + + async getDefaultDataOutputId() { + if (!this.authz.fleet.readSettings && !this.authz.fleet.readAgentPolicies) { + throw new OutputUnauthorizedError(); + } + return outputService.getDefaultDataOutputId(this.soClient); + } + + async get(outputId: string) { + if (!this.authz.fleet.readSettings && !this.authz.fleet.readAgentPolicies) { + throw new OutputUnauthorizedError(); + } + return outputService.get(this.soClient, outputId); + } +} diff --git a/x-pack/plugins/fleet/server/services/package_policies/utils.ts b/x-pack/plugins/fleet/server/services/package_policies/utils.ts index ef59c643a8b3..a27ac5943f80 100644 --- a/x-pack/plugins/fleet/server/services/package_policies/utils.ts +++ b/x-pack/plugins/fleet/server/services/package_policies/utils.ts @@ -28,17 +28,16 @@ import { licenseService } from '../license'; import { outputService } from '../output'; import { appContextService } from '../app_context'; -export const mapPackagePolicySavedObjectToPackagePolicy = ({ - id, - version, - attributes, - namespaces, -}: SavedObject<PackagePolicySOAttributes>): PackagePolicy => { +export const mapPackagePolicySavedObjectToPackagePolicy = ( + { id, version, attributes }: SavedObject<PackagePolicySOAttributes>, + namespaces?: string[] +): PackagePolicy => { + const { bump_agent_policy_revision: bumpAgentPolicyRevision, ...restAttributes } = attributes; return { id, version, - spaceIds: namespaces, - ...attributes, + ...(namespaces ? { spaceIds: namespaces } : {}), + ...restAttributes, }; }; diff --git a/x-pack/plugins/fleet/server/services/package_policy.ts b/x-pack/plugins/fleet/server/services/package_policy.ts index 48dc3956d698..32ec4c90b431 100644 --- a/x-pack/plugins/fleet/server/services/package_policy.ts +++ b/x-pack/plugins/fleet/server/services/package_policy.ts @@ -20,6 +20,7 @@ import type { RequestHandlerContext, SavedObjectsBulkCreateObject, SavedObjectsBulkUpdateObject, + SavedObject, } from '@kbn/core/server'; import { SavedObjectsUtils } from '@kbn/core/server'; import { v4 as uuidv4 } from 'uuid'; @@ -99,6 +100,11 @@ import type { } from '../types'; import type { ExternalCallback } from '..'; +import { + MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, + MAX_CONCURRENT_PACKAGE_ASSETS, +} from '../constants'; + import { createSoFindIterable } from './utils/create_so_find_iterable'; import type { FleetAuthzRouteConfig } from './security'; @@ -177,7 +183,7 @@ async function getPkgInfoAssetsMap({ pkgInfo, }); }, - { concurrency: 5 } + { concurrency: MAX_CONCURRENT_PACKAGE_ASSETS } ); return packageInfosandAssetsMap; @@ -446,7 +452,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } - const createdPackagePolicy = { id: newSo.id, version: newSo.version, ...newSo.attributes }; + const createdPackagePolicy = mapPackagePolicySavedObjectToPackagePolicy(newSo); logger.debug(`Created new package policy with id ${newSo.id} and version ${newSo.version}`); return packagePolicyService.runExternalCallbacks( @@ -668,11 +674,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } logger.debug(`Created new package policies`); return { - created: newSos.map((newSo) => ({ - id: newSo.id, - version: newSo.version, - ...newSo.attributes, - })), + created: newSos.map((newSo) => mapPackagePolicySavedObjectToPackagePolicy(newSo)), failed: failedPolicies, }; } @@ -754,11 +756,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } - const response = { - id: packagePolicySO.id, - version: packagePolicySO.version, - ...packagePolicySO.attributes, - }; + const response = mapPackagePolicySavedObjectToPackagePolicy(packagePolicySO); // If possible, return the experimental features map for the package policy's `package` field if (experimentalFeatures && response.package) { @@ -788,11 +786,9 @@ class PackagePolicyClientImpl implements PackagePolicyClient { return []; } - const packagePolicies = packagePolicySO.saved_objects.map((so) => ({ - id: so.id, - version: so.version, - ...so.attributes, - })); + const packagePolicies = packagePolicySO.saved_objects.map((so) => + mapPackagePolicySavedObjectToPackagePolicy(so) + ); for (const packagePolicy of packagePolicies) { auditLoggingService.writeCustomSoAuditLog({ @@ -835,11 +831,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } } - return { - id: so.id, - version: so.version, - ...so.attributes, - }; + return mapPackagePolicySavedObjectToPackagePolicy(so); }) .filter((packagePolicy): packagePolicy is PackagePolicy => packagePolicy !== null); @@ -889,12 +881,9 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } return { - items: packagePolicies?.saved_objects.map((packagePolicySO) => ({ - id: packagePolicySO.id, - version: packagePolicySO.version, - ...packagePolicySO.attributes, - spaceIds: packagePolicySO.namespaces, - })), + items: packagePolicies?.saved_objects.map((so) => + mapPackagePolicySavedObjectToPackagePolicy(so, so.namespaces) + ), total: packagePolicies?.total, page, perPage, @@ -1392,13 +1381,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient { const updatedPoliciesSuccess = updatedPolicies .filter((policy) => !policy.error && policy.attributes) - .map( - (soPolicy) => - ({ - id: soPolicy.id, - version: soPolicy.version, - ...soPolicy.attributes, - } as PackagePolicy) + .map((soPolicy) => + mapPackagePolicySavedObjectToPackagePolicy( + soPolicy as SavedObject<PackagePolicySOAttributes> + ) ); return { updatedPolicies: updatedPoliciesSuccess, failedPolicies }; @@ -1948,6 +1934,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { output_id: newPolicy.output_id, inputs: newPolicy.inputs[0]?.streams ? newPolicy.inputs : inputs, vars: newPolicy.vars || newPP.vars, + supports_agentless: newPolicy.supports_agentless, }; } } @@ -2189,7 +2176,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { perPage: SO_SEARCH_LIMIT, namespaces: ['*'], }) - ).saved_objects.map(mapPackagePolicySavedObjectToPackagePolicy); + ).saved_objects.map((so) => mapPackagePolicySavedObjectToPackagePolicy(so, so.namespaces)); if (packagePolicies.length > 0) { const getPackagePolicyUpdate = (packagePolicy: PackagePolicy) => ({ @@ -2229,7 +2216,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { } }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); await pMap( @@ -2249,7 +2236,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient { ); }, { - concurrency: 50, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS, } ); } @@ -2306,7 +2293,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient { savedObjectType, }); - return mapPackagePolicySavedObjectToPackagePolicy(packagePolicySO); + return mapPackagePolicySavedObjectToPackagePolicy( + packagePolicySO, + packagePolicySO.namespaces + ); }); }, }); diff --git a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts index fb2153ff903f..57621238d914 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration.test.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration.test.ts @@ -306,10 +306,8 @@ jest.mock('./app_context', () => ({ }), getExternalCallbacks: jest.fn(), getCloud: jest.fn(), - getExperimentalFeatures: jest.fn().mockReturnValue({ - agentless: false, - }), getConfig: jest.fn(), + getExperimentalFeatures: jest.fn().mockReturnValue({}), getInternalUserSOClientForSpaceId: jest.fn(), }, })); @@ -1075,10 +1073,6 @@ describe('policy preconfiguration', () => { DEFAULT_SPACE_ID ); - jest.mocked(appContextService.getExperimentalFeatures).mockReturnValue({ - agentless: true, - } as any); - expect(appContextService.getInternalUserSOClientForSpaceId).toBeCalledTimes(1); expect(appContextService.getInternalUserSOClientForSpaceId).toBeCalledWith(TEST_NAMESPACE); diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts b/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts index 03787b8e6be6..d09494e52d30 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/fleet_proxies.ts @@ -22,6 +22,8 @@ import { listFleetServerHostsForProxyId } from '../fleet_server_host'; import { agentPolicyService } from '../agent_policy'; import { outputService } from '../output'; +import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; + export function getPreconfiguredFleetProxiesFromConfig(config?: FleetConfigType) { const { proxies: fleetProxiesFromConfig } = config; @@ -107,7 +109,7 @@ async function createOrUpdatePreconfiguredFleetProxies( outputs, (output) => agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, output.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); await pMap( @@ -118,7 +120,7 @@ async function createOrUpdatePreconfiguredFleetProxies( fleetServerHost.id ), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts index 714b16af5bcd..f605df4680b3 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/outputs.ts @@ -11,6 +11,7 @@ import utils from 'node:util'; import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import { isEqual } from 'lodash'; import { dump } from 'js-yaml'; +import pMap from 'p-map'; const pbkdf2Async = utils.promisify(crypto.pbkdf2); @@ -32,6 +33,8 @@ import { appContextService } from '../app_context'; import { isDifferent } from './utils'; +export const MAX_CONCURRENT_OUTPUTS_OPERATIONS = 50; + export function getPreconfiguredOutputFromConfig(config?: FleetConfigType) { const { outputs: outputsOrUndefined } = config; @@ -78,67 +81,69 @@ export async function createOrUpdatePreconfiguredOutputs( { ignoreNotFound: true } ); - await Promise.all( - outputs.map(async (output) => { - const existingOutput = existingOutputs.find((o) => o.id === output.id); + const updateOrConfigureOutput = async (output: PreconfiguredOutput) => { + const existingOutput = existingOutputs.find((o) => o.id === output.id); - const { id, config, ...outputData } = output; + const { id, config, ...outputData } = output; - const configYaml = config ? dump(config) : undefined; + const configYaml = config ? dump(config) : undefined; - const data: NewOutput = { - ...outputData, - is_preconfigured: true, - config_yaml: configYaml ?? null, - // Set value to null to update these fields on update - ca_sha256: outputData.ca_sha256 ?? null, - ca_trusted_fingerprint: outputData.ca_trusted_fingerprint ?? null, - ssl: outputData.ssl ?? null, - } as NewOutput; + const data: NewOutput = { + ...outputData, + is_preconfigured: true, + config_yaml: configYaml ?? null, + // Set value to null to update these fields on update + ca_sha256: outputData.ca_sha256 ?? null, + ca_trusted_fingerprint: outputData.ca_trusted_fingerprint ?? null, + ssl: outputData.ssl ?? null, + } as NewOutput; - if (!data.hosts || data.hosts.length === 0) { - data.hosts = outputService.getDefaultESHosts(); - } + if (!data.hosts || data.hosts.length === 0) { + data.hosts = outputService.getDefaultESHosts(); + } - const isCreate = !existingOutput; + const isCreate = !existingOutput; - // field in allow edit are not updated through preconfiguration - if (!isCreate && output.allow_edit) { - for (const key of output.allow_edit) { - // @ts-expect-error - data[key] = existingOutput[key]; - } + // field in allow edit are not updated through preconfiguration + if (!isCreate && output.allow_edit) { + for (const key of output.allow_edit) { + // @ts-expect-error + data[key] = existingOutput[key]; } + } + + const isUpdateWithNewData = + existingOutput && (await isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)); + + if (isCreate || isUpdateWithNewData) { + const secretHashes = await hashSecrets(output); - const isUpdateWithNewData = - existingOutput && (await isPreconfiguredOutputDifferentFromCurrent(existingOutput, data)); - - if (isCreate || isUpdateWithNewData) { - const secretHashes = await hashSecrets(output); - - if (isCreate) { - logger.debug(`Creating preconfigured output ${output.id}`); - await outputService.create(soClient, esClient, data, { - id, - fromPreconfiguration: true, - secretHashes, - }); - } else if (isUpdateWithNewData) { - logger.debug(`Updating preconfigured output ${output.id}`); - await outputService.update(soClient, esClient, id, data, { - fromPreconfiguration: true, - secretHashes, - }); - // Bump revision of all policies using that output - if (outputData.is_default || outputData.is_default_monitoring) { - await agentPolicyService.bumpAllAgentPolicies(esClient); - } else { - await agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, id); - } + if (isCreate) { + logger.debug(`Creating preconfigured output ${output.id}`); + await outputService.create(soClient, esClient, data, { + id, + fromPreconfiguration: true, + secretHashes, + }); + } else if (isUpdateWithNewData) { + logger.debug(`Updating preconfigured output ${output.id}`); + await outputService.update(soClient, esClient, id, data, { + fromPreconfiguration: true, + secretHashes, + }); + // Bump revision of all policies using that output + if (outputData.is_default || outputData.is_default_monitoring) { + await agentPolicyService.bumpAllAgentPolicies(esClient); + } else { + await agentPolicyService.bumpAllAgentPoliciesForOutput(esClient, id); } } - }) - ); + } + }; + + await pMap(outputs, (output) => updateOrConfigureOutput(output), { + concurrency: MAX_CONCURRENT_OUTPUTS_OPERATIONS, + }); } // Values recommended by NodeJS documentation diff --git a/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts b/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts index 7e65dd665d0b..84dbbf817d66 100644 --- a/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts +++ b/x-pack/plugins/fleet/server/services/preconfiguration/reset_agent_policies.ts @@ -24,6 +24,8 @@ import { listEnrollmentApiKeys, deleteEnrollmentApiKey } from '../api_keys'; import type { AgentPolicy } from '../../types'; import { AgentPolicyInvalidError } from '../../errors'; +import { MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; + export async function resetPreconfiguredAgentPolicies( soClient: SavedObjectsClientContract, esClient: ElasticsearchClient, @@ -83,7 +85,7 @@ async function _deleteGhostPackagePolicies( } }, { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -116,7 +118,7 @@ async function _deletePreconfigurationDeleteRecord( }), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -167,7 +169,7 @@ async function _deleteExistingData( if (agents.length > 0) { logger.info(`Force unenrolling ${agents.length} agents`); await pMap(agents, (agent) => forceUnenrollAgent(esClient, soClient, agent.id), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, }); } @@ -183,7 +185,7 @@ async function _deleteExistingData( enrollmentApiKeys, (enrollmentKey) => deleteEnrollmentApiKey(esClient, enrollmentKey.id, true), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } @@ -195,7 +197,7 @@ async function _deleteExistingData( force: true, }), { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); } diff --git a/x-pack/plugins/fleet/server/services/settings.test.ts b/x-pack/plugins/fleet/server/services/settings.test.ts index f88e735dfcb6..9a75dc72abf3 100644 --- a/x-pack/plugins/fleet/server/services/settings.test.ts +++ b/x-pack/plugins/fleet/server/services/settings.test.ts @@ -143,6 +143,42 @@ describe('getSettings', () => { await getSettings(soClient); }); + + it('should handle null values for space awareness migration fields', async () => { + const soClient = savedObjectsClientMock.create(); + + soClient.find.mockResolvedValueOnce({ + saved_objects: [ + { + id: GLOBAL_SETTINGS_ID, + attributes: { + use_space_awareness_migration_status: null, + use_space_awareness_migration_started_at: null, + }, + references: [], + type: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + score: 0, + }, + ], + page: 1, + per_page: 10, + total: 1, + }); + + const settings = await getSettings(soClient); + expect(settings).toEqual({ + delete_unenrolled_agents: undefined, + has_seen_add_data_notice: undefined, + id: 'fleet-default-settings', + output_secret_storage_requirements_met: undefined, + preconfigured_fields: [], + prerelease_integrations_enabled: undefined, + secret_storage_requirements_met: undefined, + use_space_awareness_migration_started_at: undefined, + use_space_awareness_migration_status: undefined, + version: undefined, + }); + }); }); describe('saveSettings', () => { diff --git a/x-pack/plugins/fleet/server/services/settings.ts b/x-pack/plugins/fleet/server/services/settings.ts index 3288ec1090e4..5e1948d5d379 100644 --- a/x-pack/plugins/fleet/server/services/settings.ts +++ b/x-pack/plugins/fleet/server/services/settings.ts @@ -6,7 +6,11 @@ */ import Boom from '@hapi/boom'; -import type { SavedObjectsClientContract, SavedObjectsUpdateOptions } from '@kbn/core/server'; +import type { + SavedObject, + SavedObjectsClientContract, + SavedObjectsUpdateOptions, +} from '@kbn/core/server'; import { omit } from 'lodash'; import { GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, GLOBAL_SETTINGS_ID } from '../../common/constants'; @@ -18,21 +22,7 @@ import { DeleteUnenrolledAgentsPreconfiguredError } from '../errors'; import { appContextService } from './app_context'; import { auditLoggingService } from './audit_logging'; -export async function getSettings(soClient: SavedObjectsClientContract): Promise<Settings> { - const res = await soClient.find<SettingsSOAttributes>({ - type: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, - }); - auditLoggingService.writeCustomSoAuditLog({ - action: 'get', - id: GLOBAL_SETTINGS_ID, - savedObjectType: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, - }); - - if (res.total === 0) { - throw Boom.notFound('Global settings not found'); - } - const settingsSo = res.saved_objects[0]; - +function mapSettingsSO(settingsSo: SavedObject<SettingsSOAttributes>): Settings { return { id: settingsSo.id, version: settingsSo.version, @@ -42,14 +32,30 @@ export async function getSettings(soClient: SavedObjectsClientContract): Promise has_seen_add_data_notice: settingsSo.attributes.has_seen_add_data_notice, prerelease_integrations_enabled: settingsSo.attributes.prerelease_integrations_enabled, use_space_awareness_migration_status: - settingsSo.attributes.use_space_awareness_migration_status, + settingsSo.attributes.use_space_awareness_migration_status ?? undefined, use_space_awareness_migration_started_at: - settingsSo.attributes.use_space_awareness_migration_started_at, + settingsSo.attributes.use_space_awareness_migration_started_at ?? undefined, preconfigured_fields: getConfigFleetServerHosts() ? ['fleet_server_hosts'] : [], delete_unenrolled_agents: settingsSo.attributes.delete_unenrolled_agents, }; } +export async function getSettings(soClient: SavedObjectsClientContract): Promise<Settings> { + const res = await soClient.find<SettingsSOAttributes>({ + type: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + }); + auditLoggingService.writeCustomSoAuditLog({ + action: 'get', + id: GLOBAL_SETTINGS_ID, + savedObjectType: GLOBAL_SETTINGS_SAVED_OBJECT_TYPE, + }); + + if (res.total === 0) { + throw Boom.notFound('Global settings not found'); + } + return mapSettingsSO(res.saved_objects[0]); +} + export async function getSettingsOrUndefined( soClient: SavedObjectsClientContract ): Promise<Settings | undefined> { diff --git a/x-pack/plugins/fleet/server/services/setup.ts b/x-pack/plugins/fleet/server/services/setup.ts index ab882a013ebe..24d655a4cae1 100644 --- a/x-pack/plugins/fleet/server/services/setup.ts +++ b/x-pack/plugins/fleet/server/services/setup.ts @@ -21,6 +21,8 @@ import { AUTO_UPDATE_PACKAGES, FLEET_SETUP_LOCK_TYPE } from '../../common/consta import type { PreconfigurationError } from '../../common/constants'; import type { DefaultPackagesInstallationError, FleetSetupLock } from '../../common/types'; +import { MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } from '../constants'; + import { appContextService } from './app_context'; import { ensurePreconfiguredPackagesAndPolicies } from './preconfiguration'; import { @@ -359,7 +361,7 @@ export async function ensureFleetGlobalEsAssets( ); }); }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ); } } diff --git a/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx b/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx index cd3317c5eb23..ab3045ee57a0 100644 --- a/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx +++ b/x-pack/plugins/fleet/server/services/setup/clean_old_fleet_indices.tsx @@ -8,6 +8,8 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import pMap from 'p-map'; +import { MAX_CONCURRENT_CLEAN_OLD_FILE_INDICES } from '../../constants'; + const INDICES_TO_CLEAN = [ '.fleet-files-*', '.fleet-file-data-*', @@ -49,7 +51,7 @@ export async function cleanUpOldFileIndices(esClient: ElasticsearchClient, logge }); } }, - { concurrency: 2 } + { concurrency: MAX_CONCURRENT_CLEAN_OLD_FILE_INDICES } ); await esClient.indices .deleteIndexTemplate({ diff --git a/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.test.ts b/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.test.ts index 07ec6593ec9e..9fb30ad75ab7 100644 --- a/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.test.ts +++ b/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.test.ts @@ -17,6 +17,7 @@ import { ensureAgentPoliciesFleetServerKeysAndPolicies } from './fleet_server_po jest.mock('../app_context'); jest.mock('../agent_policy'); jest.mock('../api_keys'); +jest.mock('../agent_policies/bump_agent_policies_task'); const mockedEnsureDefaultEnrollmentAPIKeyForAgentPolicy = jest.mocked( ensureDefaultEnrollmentAPIKeyForAgentPolicy diff --git a/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts b/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts index f5ed816d96e6..07efdde6f7b7 100644 --- a/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts +++ b/x-pack/plugins/fleet/server/services/setup/fleet_server_policies_enrollment_keys.ts @@ -10,9 +10,10 @@ import pMap from 'p-map'; import { agentPolicyService } from '../agent_policy'; import { ensureDefaultEnrollmentAPIKeyForAgentPolicy } from '../api_keys'; -import { SO_SEARCH_LIMIT } from '../../constants'; +import { SO_SEARCH_LIMIT, MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20 } from '../../constants'; import { appContextService } from '../app_context'; import { scheduleDeployAgentPoliciesTask } from '../agent_policies/deploy_agent_policies_task'; +import { scheduleBumpAgentPoliciesTask } from '../agent_policies/bump_agent_policies_task'; export async function ensureAgentPoliciesFleetServerKeysAndPolicies({ logger, @@ -37,7 +38,6 @@ export async function ensureAgentPoliciesFleetServerKeysAndPolicies({ }); const outdatedAgentPolicyIds: Array<{ id: string; spaceId?: string }> = []; - await pMap( agentPolicies, async (agentPolicy) => { @@ -51,27 +51,27 @@ export async function ensureAgentPoliciesFleetServerKeysAndPolicies({ } }, { - concurrency: 20, + concurrency: MAX_CONCURRENT_AGENT_POLICIES_OPERATIONS_20, } ); - if (!outdatedAgentPolicyIds.length) { - return; - } + await scheduleBumpAgentPoliciesTask(appContextService.getTaskManagerStart()!); - if (appContextService.getExperimentalFeatures().asyncDeployPolicies) { - return scheduleDeployAgentPoliciesTask( - appContextService.getTaskManagerStart()!, - outdatedAgentPolicyIds - ); - } else { - return agentPolicyService - .deployPolicies( - soClient, - outdatedAgentPolicyIds.map(({ id }) => id) - ) - .catch((error) => { - logger.warn(`Error deploying policies: ${error.message}`, { error }); - }); + if (outdatedAgentPolicyIds.length) { + if (appContextService.getExperimentalFeatures().asyncDeployPolicies) { + return scheduleDeployAgentPoliciesTask( + appContextService.getTaskManagerStart()!, + outdatedAgentPolicyIds + ); + } else { + return agentPolicyService + .deployPolicies( + soClient, + outdatedAgentPolicyIds.map(({ id }) => id) + ) + .catch((error) => { + logger.warn(`Error deploying policies: ${error.message}`, { error }); + }); + } } } diff --git a/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts b/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts index db85e269dc34..bb9def3dc4ae 100644 --- a/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts +++ b/x-pack/plugins/fleet/server/services/setup/upgrade_package_install_version.ts @@ -9,7 +9,11 @@ import type { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/ import pMap from 'p-map'; import type { Logger } from '@kbn/logging'; -import { PACKAGES_SAVED_OBJECT_TYPE, SO_SEARCH_LIMIT } from '../../constants'; +import { + MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS, + PACKAGES_SAVED_OBJECT_TYPE, + SO_SEARCH_LIMIT, +} from '../../constants'; import { FLEET_INSTALL_FORMAT_VERSION } from '../../constants/fleet_es_assets'; import type { Installation } from '../../types'; @@ -59,6 +63,6 @@ export async function upgradePackageInstallVersion({ } }); }, - { concurrency: 10 } + { concurrency: MAX_CONCURRENT_EPM_PACKAGES_INSTALLATIONS } ); } diff --git a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts index e123ca442665..50f20443c326 100644 --- a/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts +++ b/x-pack/plugins/fleet/server/services/spaces/agent_policy.ts @@ -23,9 +23,10 @@ import { ENROLLMENT_API_KEYS_INDEX } from '../../constants'; import { packagePolicyService } from '../package_policy'; import { FleetError, HostedAgentPolicyRestrictionRelatedError } from '../../errors'; -import { isSpaceAwarenessEnabled } from './helpers'; import type { UninstallTokenSOAttributes } from '../security/uninstall_token_service'; +import { isSpaceAwarenessEnabled } from './helpers'; + export async function updateAgentPolicySpaces({ agentPolicyId, currentSpaceId, diff --git a/x-pack/plugins/fleet/server/services/utils/agentless.test.ts b/x-pack/plugins/fleet/server/services/utils/agentless.test.ts index 5bf5116128d9..48f186fed553 100644 --- a/x-pack/plugins/fleet/server/services/utils/agentless.test.ts +++ b/x-pack/plugins/fleet/server/services/utils/agentless.test.ts @@ -9,12 +9,7 @@ import { securityMock } from '@kbn/security-plugin/server/mocks'; import { appContextService } from '../app_context'; -import { - isAgentlessApiEnabled, - isAgentlessEnabled, - isDefaultAgentlessPolicyEnabled, - prependAgentlessApiBasePathToEndpoint, -} from './agentless'; +import { isAgentlessEnabled, prependAgentlessApiBasePathToEndpoint } from './agentless'; jest.mock('../app_context'); @@ -23,7 +18,7 @@ mockedAppContextService.getSecuritySetup.mockImplementation(() => ({ ...securityMock.createSetup(), })); -describe('isAgentlessApiEnabled', () => { +describe('isAgentlessEnabled', () => { afterEach(() => { jest.clearAllMocks(); mockedAppContextService.getConfig.mockReset(); @@ -36,7 +31,7 @@ describe('isAgentlessApiEnabled', () => { } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: false } as any); - expect(isAgentlessApiEnabled()).toBe(false); + expect(isAgentlessEnabled()).toBe(false); }); it('should return false if cloud is enabled but agentless is not', () => { @@ -47,7 +42,7 @@ describe('isAgentlessApiEnabled', () => { } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - expect(isAgentlessApiEnabled()).toBe(false); + expect(isAgentlessEnabled()).toBe(false); }); it('should return true if cloud is enabled and agentless is enabled', () => { @@ -58,109 +53,10 @@ describe('isAgentlessApiEnabled', () => { } as any); jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - expect(isAgentlessApiEnabled()).toBe(true); - }); -}); - -describe('isDefaultAgentlessPolicyEnabled', () => { - afterEach(() => { - jest.clearAllMocks(); - mockedAppContextService.getConfig.mockReset(); - }); - - it('should return false if serverless is not enabled', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: false } as any); - - expect(isDefaultAgentlessPolicyEnabled()).toBe(false); - }); - - it('should return false if serverless is enabled but agentless is not', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); - jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isServerlessEnabled: true } as any); - - expect(isDefaultAgentlessPolicyEnabled()).toBe(false); - }); - - it('should return true if serverless is enabled and agentless is enabled', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: true } as any); - jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isServerlessEnabled: true } as any); - - expect(isDefaultAgentlessPolicyEnabled()).toBe(true); - }); -}); - -describe('isAgentlessEnabled', () => { - afterEach(() => { - jest.clearAllMocks(); - mockedAppContextService.getConfig.mockReset(); - }); - - it('should return false if cloud and serverless are not enabled', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); - jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: false } as any); - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: false } as any); - - expect(isAgentlessEnabled()).toBe(false); - }); - - it('should return false if cloud is enabled but agentless is not', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); - jest.spyOn(appContextService, 'getCloud').mockReturnValue({ isCloudEnabled: true } as any); - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isServerlessEnabled: false } as any); - - expect(isAgentlessEnabled()).toBe(false); - }); - - it('should return false if serverless is enabled but agentless is not', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: false } as any); - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isCloudEnabled: false, isServerlessEnabled: true } as any); - - expect(isAgentlessEnabled()).toBe(false); - }); - - it('should return true if cloud is enabled and agentless is enabled', () => { - jest - .spyOn(appContextService, 'getConfig') - .mockReturnValue({ agentless: { enabled: true } } as any); - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isCloudEnabled: true, isServerlessEnabled: false } as any); - - expect(isAgentlessEnabled()).toBe(true); - }); - - it('should return true if serverless is enabled and agentless is enabled', () => { - jest - .spyOn(appContextService, 'getExperimentalFeatures') - .mockReturnValue({ agentless: true } as any); - jest - .spyOn(appContextService, 'getCloud') - .mockReturnValue({ isCloudEnabled: false, isServerlessEnabled: true } as any); - expect(isAgentlessEnabled()).toBe(true); }); }); + describe('prependAgentlessApiBasePathToEndpoint', () => { afterEach(() => { jest.clearAllMocks(); diff --git a/x-pack/plugins/fleet/server/services/utils/agentless.ts b/x-pack/plugins/fleet/server/services/utils/agentless.ts index 0f5d4e9d1de8..019c035d55e2 100644 --- a/x-pack/plugins/fleet/server/services/utils/agentless.ts +++ b/x-pack/plugins/fleet/server/services/utils/agentless.ts @@ -9,20 +9,11 @@ import { appContextService } from '..'; import type { FleetConfigType } from '../../config'; export { isOnlyAgentlessIntegration } from '../../../common/services/agentless_policy_helper'; -export const isAgentlessApiEnabled = () => { +export const isAgentlessEnabled = () => { const cloudSetup = appContextService.getCloud(); const isHosted = cloudSetup?.isCloudEnabled || cloudSetup?.isServerlessEnabled; return Boolean(isHosted && appContextService.getConfig()?.agentless?.enabled); }; -export const isDefaultAgentlessPolicyEnabled = () => { - const cloudSetup = appContextService.getCloud && appContextService.getCloud(); - return Boolean( - cloudSetup?.isServerlessEnabled && appContextService.getExperimentalFeatures().agentless - ); -}; -export const isAgentlessEnabled = () => { - return isAgentlessApiEnabled() || isDefaultAgentlessPolicyEnabled(); -}; const AGENTLESS_ESS_API_BASE_PATH = '/api/v1/ess'; const AGENTLESS_SERVERLESS_API_BASE_PATH = '/api/v1/serverless'; diff --git a/x-pack/plugins/fleet/server/types/models/package_policy.ts b/x-pack/plugins/fleet/server/types/models/package_policy.ts index c5f3e94868cf..bbbb94b28cd4 100644 --- a/x-pack/plugins/fleet/server/types/models/package_policy.ts +++ b/x-pack/plugins/fleet/server/types/models/package_policy.ts @@ -172,6 +172,16 @@ export const PackagePolicyBaseSchema = { ), ]) ), + supports_agentless: schema.maybe( + schema.nullable( + schema.boolean({ + defaultValue: false, + meta: { + description: 'Indicates whether the package policy belongs to an agentless agent policy.', + }, + }) + ) + ), }; export const NewPackagePolicySchema = schema.object({ @@ -286,6 +296,16 @@ export const SimplifiedPackagePolicyBaseSchema = schema.object({ output_id: schema.maybe(schema.oneOf([schema.literal(null), schema.string()])), vars: schema.maybe(SimplifiedVarsSchema), inputs: SimplifiedPackagePolicyInputsSchema, + supports_agentless: schema.maybe( + schema.nullable( + schema.boolean({ + defaultValue: false, + meta: { + description: 'Indicates whether the package policy belongs to an agentless agent policy.', + }, + }) + ) + ), }); export const SimplifiedPackagePolicyPreconfiguredSchema = SimplifiedPackagePolicyBaseSchema.extends( diff --git a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts index f9db02b92a65..a5fb3e9e034e 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/agent.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/agent.ts @@ -527,6 +527,8 @@ export const GetAgentStatusResponseSchema = schema.object({ export const GetAgentDataRequestSchema = { query: schema.object({ agentsIds: schema.oneOf([schema.arrayOf(schema.string()), schema.string()]), + pkgName: schema.maybe(schema.string()), + pkgVersion: schema.maybe(schema.string()), previewData: schema.boolean({ defaultValue: false }), }), }; diff --git a/x-pack/plugins/fleet/server/types/rest_spec/settings.ts b/x-pack/plugins/fleet/server/types/rest_spec/settings.ts index c40dcc0b6359..64684e51350d 100644 --- a/x-pack/plugins/fleet/server/types/rest_spec/settings.ts +++ b/x-pack/plugins/fleet/server/types/rest_spec/settings.ts @@ -61,7 +61,9 @@ export const SettingsResponseSchema = schema.object({ use_space_awareness_migration_status: schema.maybe( schema.oneOf([schema.literal('pending'), schema.literal('success'), schema.literal('error')]) ), - use_space_awareness_migration_started_at: schema.maybe(schema.string()), + use_space_awareness_migration_started_at: schema.maybe( + schema.oneOf([schema.literal(null), schema.string()]) + ), delete_unenrolled_agents: schema.maybe( schema.object({ enabled: schema.boolean(), diff --git a/x-pack/plugins/fleet/server/types/so_attributes.ts b/x-pack/plugins/fleet/server/types/so_attributes.ts index 31207dda64bc..6f415eea9eb6 100644 --- a/x-pack/plugins/fleet/server/types/so_attributes.ts +++ b/x-pack/plugins/fleet/server/types/so_attributes.ts @@ -137,6 +137,7 @@ export interface PackagePolicySOAttributes { }; agents?: number; overrides?: any | null; + bump_agent_policy_revision?: boolean; } interface OutputSoBaseAttributes { diff --git a/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx b/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx index 22790bc7f639..28ee3bd0fd17 100644 --- a/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx +++ b/x-pack/plugins/graph/public/helpers/use_workspace_loader.test.tsx @@ -10,7 +10,7 @@ import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { createMockGraphStore } from '../state_management/mocks'; import { Workspace } from '../types'; -import { renderHook, act, RenderHookOptions } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { ContentClient } from '@kbn/content-management-plugin/public'; jest.mock('react-router-dom', () => { @@ -51,15 +51,16 @@ describe('use_workspace_loader', () => { }; it('should not redirect if outcome is exactMatch', async () => { - await act(async () => { - renderHook( - () => useWorkspaceLoader(defaultProps), - defaultProps as RenderHookOptions<UseWorkspaceLoaderProps> - ); + renderHook((props) => useWorkspaceLoader(props), { + initialProps: defaultProps, + }); + + await waitFor(() => { + expect(defaultProps.spaces?.ui.redirectLegacyUrl).not.toHaveBeenCalled(); + expect(defaultProps.store.dispatch).toHaveBeenCalled(); }); - expect(defaultProps.spaces?.ui.redirectLegacyUrl).not.toHaveBeenCalled(); - expect(defaultProps.store.dispatch).toHaveBeenCalled(); }); + it('should redirect if outcome is aliasMatch', async () => { const props = { ...defaultProps, @@ -77,16 +78,16 @@ describe('use_workspace_loader', () => { }, } as unknown as UseWorkspaceLoaderProps; - await act(async () => { - renderHook( - () => useWorkspaceLoader(props), - props as RenderHookOptions<UseWorkspaceLoaderProps> - ); - }); - expect(props.spaces?.ui.redirectLegacyUrl).toHaveBeenCalledWith({ - path: '#/workspace/aliasTargetId?query={}', - aliasPurpose: 'savedObjectConversion', - objectNoun: 'Graph', + renderHook((_props) => useWorkspaceLoader(_props), { + initialProps: props, }); + + await waitFor(() => + expect(props.spaces?.ui.redirectLegacyUrl).toHaveBeenCalledWith({ + path: '#/workspace/aliasTargetId?query={}', + aliasPurpose: 'savedObjectConversion', + objectNoun: 'Graph', + }) + ); }); }); diff --git a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx index f254c7d52575..20ca1fbc82a2 100644 --- a/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx +++ b/x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/edit_policy.tsx @@ -33,7 +33,6 @@ import { useKibana, useFormIsModified, } from '../../../shared_imports'; -import { toasts } from '../../services/notification'; import { getPoliciesListPath, getPolicyViewPath } from '../../services/navigation'; import { UseField } from './form'; import { savePolicy } from './save_policy'; @@ -137,25 +136,21 @@ export const EditPolicy: React.FunctionComponent = () => { const { data: policy, isValid } = await form.submit(); if (!isValid) { - toasts.addDanger( - i18n.translate('xpack.indexLifecycleMgmt.editPolicy.formErrorsMessage', { - defaultMessage: 'Please fix the errors on this page.', - }) - ); - } else { - const name = getPolicyName(); - setHasSubmittedForm(true); - const success = await savePolicy( - { - ...policy, - name, - }, - isNewPolicy || isClonedPolicy - ); - - if (success) { - backToPolicyList(name); - } + return; + } + + const name = getPolicyName(); + setHasSubmittedForm(true); + const success = await savePolicy( + { + ...policy, + name, + }, + isNewPolicy || isClonedPolicy + ); + + if (success) { + backToPolicyList(name); } }; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx index 9332509dc26b..e9d93e6baf63 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/create_enrich_policy/create_enrich_policy.test.tsx @@ -9,7 +9,11 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { setupEnvironment } from '../helpers'; -import { getMatchingIndices, getFieldsFromIndices } from '../helpers/fixtures'; +import { + getMatchingIndices, + getFieldsFromIndices, + getMatchingDataStreams, +} from '../helpers/fixtures'; import { CreateEnrichPoliciesTestBed, setup } from './create_enrich_policy.helpers'; import { getESPolicyCreationApiCall } from '../../../common/lib'; @@ -53,10 +57,7 @@ describe('Create enrich policy', () => { beforeEach(async () => { httpRequestsMockHelpers.setGetMatchingIndices(getMatchingIndices()); - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: true, - missingPrivileges: { cluster: [] }, - }); + httpRequestsMockHelpers.setGetMatchingDataStreams(getMatchingDataStreams()); await act(async () => { testBed = await setup(httpSetup); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/fixtures.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/fixtures.ts index a70ad0ea552e..0741b4449560 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/fixtures.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/fixtures.ts @@ -62,6 +62,9 @@ export const createTestEnrichPolicy = (name: string, type: EnrichPolicyType) => export const getMatchingIndices = () => ({ indices: ['test-1', 'test-2', 'test-3', 'test-4', 'test-5'], }); +export const getMatchingDataStreams = () => ({ + dataStreams: ['test-6', 'test-7', 'test-8', 'test-9', 'test-10'], +}); export const getFieldsFromIndices = () => ({ commonFields: [], diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts index 79daba4c7386..a9f1dac15ed1 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/http_requests.ts @@ -172,6 +172,13 @@ const registerHttpRequestMockHelpers = ( response, error ); + const setGetMatchingDataStreams = (response?: HttpResponse, error?: ResponseError) => + mockResponse( + 'POST', + `${INTERNAL_API_BASE_PATH}/enrich_policies/get_matching_data_streams`, + response, + error + ); const setGetFieldsFromIndices = (response?: HttpResponse, error?: ResponseError) => mockResponse( @@ -181,9 +188,6 @@ const registerHttpRequestMockHelpers = ( error ); - const setGetPrivilegesResponse = (response?: HttpResponse, error?: ResponseError) => - mockResponse('GET', `${INTERNAL_API_BASE_PATH}/enrich_policies/privileges`, response, error); - const setCreateEnrichPolicy = (response?: HttpResponse, error?: ResponseError) => mockResponse('POST', `${INTERNAL_API_BASE_PATH}/enrich_policies`, response, error); @@ -246,9 +250,9 @@ const registerHttpRequestMockHelpers = ( setCreateIndexResponse, setGetMatchingIndices, setGetFieldsFromIndices, - setGetPrivilegesResponse, setCreateEnrichPolicy, setInferenceModels, + setGetMatchingDataStreams, }; }; diff --git a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx index 633ed96ec822..24f641ae2833 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/helpers/setup_environment.tsx @@ -91,6 +91,11 @@ const appDependencies = { overlays: { openConfirm: jest.fn(), }, + privs: { + monitor: true, + manageEnrich: true, + monitorEnrich: true, + }, } as any; export const kibanaVersion = new SemVer(MAJOR_VERSION); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx index 77c7757fe920..040602a058e2 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/home/enrich_policies.test.tsx @@ -38,11 +38,6 @@ describe('Enrich policies tab', () => { describe('empty states', () => { beforeEach(async () => { setDelayResponse(false); - - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: true, - missingPrivileges: { cluster: [] }, - }); }); test('displays a loading prompt', async () => { @@ -82,24 +77,6 @@ describe('Enrich policies tab', () => { }); }); - describe('permissions check', () => { - it('shows a permissions error when the user does not have sufficient privileges', async () => { - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: false, - missingPrivileges: { cluster: ['manage_enrich'] }, - }); - - testBed = await setup(httpSetup); - await act(async () => { - testBed.actions.goToEnrichPoliciesTab(); - }); - - testBed.component.update(); - - expect(testBed.exists('enrichPoliciesInsuficientPrivileges')).toBe(true); - }); - }); - describe('policies list', () => { let testPolicy: ReturnType<typeof createTestEnrichPolicy>; beforeEach(async () => { @@ -110,11 +87,6 @@ describe('Enrich policies tab', () => { createTestEnrichPolicy('policy-range', 'range'), ]); - httpRequestsMockHelpers.setGetPrivilegesResponse({ - hasAllPrivileges: true, - missingPrivileges: { cluster: [] }, - }); - testBed = await setup(httpSetup); await act(async () => { testBed.actions.goToEnrichPoliciesTab(); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx index 5a97dadc870c..4badcc04540b 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/index_details_page.test.tsx @@ -727,6 +727,11 @@ describe('<IndexDetailsPage />', () => { isActive: true, hasAtLeast: jest.fn((type) => true), }; + const INFERENCE_LOCATOR = 'SEARCH_INFERENCE_ENDPOINTS'; + const createMockLocator = (id: string) => ({ + useUrl: jest.fn().mockReturnValue('https://redirect.me/to/inference_endpoints'), + }); + const mockInferenceManagementLocator = createMockLocator(INFERENCE_LOCATOR); beforeEach(async () => { httpRequestsMockHelpers.setInferenceModels({ data: [ @@ -750,7 +755,9 @@ describe('<IndexDetailsPage />', () => { docLinks: { links: { ml: '', - enterpriseSearch: '', + inferenceManagement: { + inferenceAPIDocumentation: 'https://abc.com/inference-api-create', + }, }, }, core: { @@ -819,6 +826,20 @@ describe('<IndexDetailsPage />', () => { }, }, }, + share: { + url: { + locators: { + get: jest.fn((id) => { + switch (id) { + case INFERENCE_LOCATOR: + return mockInferenceManagementLocator; + default: + throw new Error(`Unknown locator id: ${id}`); + } + }), + }, + }, + }, }, }, }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx index 2fb9165e8fd1..81272dc1c4c8 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_details_page/select_inference_id.test.tsx @@ -9,7 +9,7 @@ import { Form, useForm, } from '../../../public/application/components/mappings_editor/shared_imports'; -import { registerTestBed } from '@kbn/test-jest-helpers'; +import { findTestSubject, registerTestBed } from '@kbn/test-jest-helpers'; import { act } from 'react-dom/test-utils'; import { SelectInferenceId, @@ -20,6 +20,11 @@ import { InferenceAPIConfigResponse } from '@kbn/ml-trained-models-utils'; const createInferenceEndpointMock = jest.fn(); const mockDispatch = jest.fn(); +const INFERENCE_LOCATOR = 'SEARCH_INFERENCE_ENDPOINTS'; +const createMockLocator = (id: string) => ({ + useUrl: jest.fn().mockReturnValue('https://redirect.me/to/inference_endpoints'), +}); +const mockInferenceManagementLocator = createMockLocator(INFERENCE_LOCATOR); jest.mock('../../../public/application/app_context', () => ({ useAppContext: jest.fn().mockReturnValue({ @@ -33,8 +38,8 @@ jest.mock('../../../public/application/app_context', () => ({ }, docLinks: { links: { - enterpriseSearch: { - inferenceApiCreate: 'https://abc.com/inference-api-create', + inferenceManagement: { + inferenceAPIDocumentation: 'https://abc.com/inference-api-create', }, }, }, @@ -47,6 +52,20 @@ jest.mock('../../../public/application/app_context', () => ({ }, }, }, + share: { + url: { + locators: { + get: jest.fn((id) => { + switch (id) { + case INFERENCE_LOCATOR: + return mockInferenceManagementLocator; + default: + throw new Error(`Unknown locator id: ${id}`); + } + }), + }, + }, + }, }, }), })); @@ -133,4 +152,34 @@ describe('SelectInferenceId', () => { expect(find('data-inference-endpoint-list').contains('endpoint-2')).toBe(true); expect(find('data-inference-endpoint-list').contains('endpoint-3')).toBe(false); }); + + it('select the first endpoint by default', () => { + find('inferenceIdButton').simulate('click'); + const defaultElser = findTestSubject( + find('data-inference-endpoint-list'), + 'custom-inference_.preconfigured-elser' + ); + expect(defaultElser.prop('aria-checked')).toEqual(true); + }); + + it('does not select the other endpoints by default', () => { + find('inferenceIdButton').simulate('click'); + const defaultE5 = findTestSubject( + find('data-inference-endpoint-list'), + 'custom-inference_.preconfigured-e5' + ); + expect(defaultE5.prop('aria-checked')).toEqual(false); + + const endpoint1 = findTestSubject( + find('data-inference-endpoint-list'), + 'custom-inference_endpoint-1' + ); + expect(endpoint1.prop('aria-checked')).toEqual(false); + + const endpoint2 = findTestSubject( + find('data-inference-endpoint-list'), + 'custom-inference_endpoint-2' + ); + expect(endpoint2.prop('aria-checked')).toEqual(false); + }); }); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx index 7ba6832b8833..4992c1391635 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_create.test.tsx @@ -315,7 +315,7 @@ describe('<TemplateCreate />', () => { expect(exists('indexModeCallout')).toBe(true); expect(find('indexModeCallout').text()).toContain( - 'The index.mode setting has been set to Standard within template Logistics.' + 'The index.mode setting has been set to Standard within the Logistics step.' ); }); diff --git a/x-pack/plugins/index_management/__jest__/components/index_table.test.js b/x-pack/plugins/index_management/__jest__/components/index_table.test.js index 2ae162b42100..0a59fef7be6e 100644 --- a/x-pack/plugins/index_management/__jest__/components/index_table.test.js +++ b/x-pack/plugins/index_management/__jest__/components/index_table.test.js @@ -168,6 +168,11 @@ describe('index table', () => { enableIndexActions: true, enableIndexStats: true, }, + privs: { + monitor: true, + manageEnrich: true, + monitorEnrich: true, + }, }; component = ( diff --git a/x-pack/plugins/index_management/public/application/app_context.tsx b/x-pack/plugins/index_management/public/application/app_context.tsx index 1a8276d76b7f..3573ae33812d 100644 --- a/x-pack/plugins/index_management/public/application/app_context.tsx +++ b/x-pack/plugins/index_management/public/application/app_context.tsx @@ -79,6 +79,12 @@ export interface AppDependencies { docLinks: DocLinksStart; kibanaVersion: SemVer; overlays: OverlayStart; + canUseSyntheticSource: boolean; + privs: { + monitor: boolean; + manageEnrich: boolean; + monitorEnrich: boolean; + }; } export const AppContextProvider = ({ diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_datastreams_rollover/use_datastreams_rollover.test.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_datastreams_rollover/use_datastreams_rollover.test.tsx index 903a9187a733..d4ac28521b31 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_datastreams_rollover/use_datastreams_rollover.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/component_template_datastreams_rollover/use_datastreams_rollover.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useComponentTemplatesContext } from '../../component_templates_context'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/use_step_from_query_string.test.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/use_step_from_query_string.test.tsx index cb26f40c91ae..6e04cdc37e1f 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/use_step_from_query_string.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_wizard/use_step_from_query_string.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import { useStepFromQueryString } from './use_step_from_query_string'; diff --git a/x-pack/plugins/index_management/public/application/components/enrich_policies/with_privileges.tsx b/x-pack/plugins/index_management/public/application/components/enrich_policies/with_privileges.tsx deleted file mode 100644 index 09a79343b221..000000000000 --- a/x-pack/plugins/index_management/public/application/components/enrich_policies/with_privileges.tsx +++ /dev/null @@ -1,82 +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 { FormattedMessage } from '@kbn/i18n-react'; -import React, { FunctionComponent } from 'react'; - -import { - PageLoading, - PageError, - useAuthorizationContext, - WithPrivileges, - NotAuthorizedSection, -} from '../../../shared_imports'; -import { ENRICH_POLICIES_REQUIRED_PRIVILEGES } from '../../constants'; - -export const EnrichPoliciesWithPrivileges: FunctionComponent<{ - children?: React.ReactNode; -}> = ({ children }) => { - const { apiError } = useAuthorizationContext(); - - if (apiError) { - return ( - <PageError - title={ - <FormattedMessage - id="xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesErrorMessage" - defaultMessage="Error fetching user privileges from the server." - /> - } - error={apiError} - /> - ); - } - - return ( - <WithPrivileges - privileges={ENRICH_POLICIES_REQUIRED_PRIVILEGES.map((privilege) => `cluster.${privilege}`)} - > - {({ isLoading, hasPrivileges, privilegesMissing }) => { - if (isLoading) { - return ( - <PageLoading> - <FormattedMessage - id="xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesDescription" - defaultMessage="Checking privileges…" - /> - </PageLoading> - ); - } - - if (!hasPrivileges) { - return ( - <NotAuthorizedSection - dataTestSubj="enrichPoliciesInsuficientPrivileges" - title={ - <FormattedMessage - id="xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeTitle" - defaultMessage="Manage enrich privileges required" - /> - } - message={ - <FormattedMessage - id="xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeDescription" - defaultMessage="To use Enrich Policies, you must have the following cluster privileges: {missingPrivileges}." - values={{ - missingPrivileges: privilegesMissing.cluster!.join(', '), - }} - /> - } - /> - ); - } - - return <>{children}</>; - }} - </WithPrivileges> - ); -}; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/configuration_form.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/configuration_form.test.tsx index 4c73fd1037dd..5bc28052b73e 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/configuration_form.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/configuration_form.test.tsx @@ -28,6 +28,14 @@ const setup = (props: any = { onUpdate() {} }, appDependencies?: any) => { return testBed; }; +const getContext = (sourceFieldEnabled: boolean = true, canUseSyntheticSource: boolean = true) => + ({ + config: { + enableMappingsSourceFieldSection: sourceFieldEnabled, + }, + canUseSyntheticSource, + } as unknown as AppDependencies); + describe('Mappings editor: configuration form', () => { let testBed: TestBed<TestSubjects>; @@ -49,14 +57,8 @@ describe('Mappings editor: configuration form', () => { describe('_source field', () => { it('renders the _source field when it is enabled', async () => { - const ctx = { - config: { - enableMappingsSourceFieldSection: true, - }, - } as unknown as AppDependencies; - await act(async () => { - testBed = setup({ esNodesPlugins: [] }, ctx); + testBed = setup({ esNodesPlugins: [] }, getContext()); }); testBed.component.update(); const { exists } = testBed; @@ -65,19 +67,37 @@ describe('Mappings editor: configuration form', () => { }); it("doesn't render the _source field when it is disabled", async () => { - const ctx = { - config: { - enableMappingsSourceFieldSection: false, - }, - } as unknown as AppDependencies; - await act(async () => { - testBed = setup({ esNodesPlugins: [] }, ctx); + testBed = setup({ esNodesPlugins: [] }, getContext(false)); }); testBed.component.update(); const { exists } = testBed; expect(exists('sourceField')).toBe(false); }); + + it('has synthetic option if `canUseSyntheticSource` is set to true', async () => { + await act(async () => { + testBed = setup({ esNodesPlugins: [] }, getContext(true, true)); + }); + testBed.component.update(); + const { exists, find } = testBed; + + // Clicking on the field to open the options dropdown + find('sourceValueField').simulate('click'); + expect(exists('syntheticSourceFieldOption')).toBe(true); + }); + + it("doesn't have synthetic option if `canUseSyntheticSource` is set to false", async () => { + await act(async () => { + testBed = setup({ esNodesPlugins: [] }, getContext(true, false)); + }); + testBed.component.update(); + const { exists, find } = testBed; + + // Clicking on the field to open the options dropdown + find('sourceValueField').simulate('click'); + expect(exists('syntheticSourceFieldOption')).toBe(false); + }); }); }); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx index ee3b3e72e7c1..cb8a1efbf9c7 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/__jest__/client_integration/mappings_editor.test.tsx @@ -28,22 +28,9 @@ describe('Mappings editor: core', () => { let onChangeHandler: jest.Mock = jest.fn(); let getMappingsEditorData = getMappingsEditorDataFactory(onChangeHandler); let testBed: MappingsEditorTestBed; - let hasEnterpriseLicense = true; - const mockLicenseCheck = jest.fn((type: any) => hasEnterpriseLicense); const appDependencies = { plugins: { ml: { mlApi: {} }, - licensing: { - license$: { - subscribe: jest.fn((callback: any) => { - callback({ - isActive: true, - hasAtLeast: mockLicenseCheck, - }); - return { unsubscribe: jest.fn() }; - }), - }, - }, }, }; @@ -314,6 +301,7 @@ describe('Mappings editor: core', () => { config: { enableMappingsSourceFieldSection: true, }, + canUseSyntheticSource: true, ...appDependencies, }; @@ -512,8 +500,7 @@ describe('Mappings editor: core', () => { }); ['logsdb', 'time_series'].forEach((indexMode) => { - it(`defaults to 'synthetic' with ${indexMode} index mode prop on enterprise license`, async () => { - hasEnterpriseLicense = true; + it(`defaults to 'synthetic' with ${indexMode} index mode prop when 'canUseSyntheticSource' is set to true`, async () => { await act(async () => { testBed = setup( { @@ -537,8 +524,7 @@ describe('Mappings editor: core', () => { expect(find('sourceValueField').prop('value')).toBe('synthetic'); }); - it(`defaults to 'standard' with ${indexMode} index mode prop on basic license`, async () => { - hasEnterpriseLicense = false; + it(`defaults to 'standard' with ${indexMode} index mode prop when 'canUseSyntheticSource' is set to true`, async () => { await act(async () => { testBed = setup( { @@ -546,7 +532,7 @@ describe('Mappings editor: core', () => { onChange: onChangeHandler, indexMode, }, - ctx + { ...ctx, canUseSyntheticSource: false } ); }); testBed.component.update(); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx index 00ce2d02a1ba..6ddaf8e48fe4 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/configuration_form.tsx @@ -39,6 +39,31 @@ interface SerializedSourceField { excludes?: string[]; } +const serializeSourceField = (sourceField: any): SerializedSourceField | undefined => { + if (sourceField?.option === SYNTHETIC_SOURCE_OPTION) { + return { mode: SYNTHETIC_SOURCE_OPTION }; + } + if (sourceField?.option === DISABLED_SOURCE_OPTION) { + return { enabled: false }; + } + if (sourceField?.option === STORED_SOURCE_OPTION) { + return { + mode: 'stored', + includes: sourceField.includes, + excludes: sourceField.excludes, + }; + } + if (sourceField?.includes || sourceField?.excludes) { + // If sourceField?.option is undefined, the user hasn't explicitly selected + // this option, so don't include the `mode` property + return { + includes: sourceField.includes, + excludes: sourceField.excludes, + }; + } + return undefined; +}; + export const formSerializer = (formData: GenericObject) => { const { dynamicMapping, sourceField, metaField, _routing, _size, subobjects } = formData; @@ -48,30 +73,12 @@ export const formSerializer = (formData: GenericObject) => { ? 'strict' : dynamicMapping?.enabled; - const _source = - sourceField?.option === SYNTHETIC_SOURCE_OPTION - ? { mode: SYNTHETIC_SOURCE_OPTION } - : sourceField?.option === DISABLED_SOURCE_OPTION - ? { enabled: false } - : sourceField?.option === STORED_SOURCE_OPTION - ? { - mode: 'stored', - includes: sourceField?.includes, - excludes: sourceField?.excludes, - } - : sourceField?.includes || sourceField?.excludes - ? { - includes: sourceField?.includes, - excludes: sourceField?.excludes, - } - : undefined; - const serialized = { dynamic, numeric_detection: dynamicMapping?.numeric_detection, date_detection: dynamicMapping?.date_detection, dynamic_date_formats: dynamicMapping?.dynamic_date_formats, - _source: _source as SerializedSourceField, + _source: serializeSourceField(sourceField), _meta: metaField, _routing, _size, diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx index 2e8f9fb88f87..c1709fa13503 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/configuration_form/source_field_section/source_field_section.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiLink, EuiSpacer, EuiComboBox, EuiFormRow, EuiCallOut, EuiText } from '@elastic/eui'; -import { useMappingsState } from '../../../mappings_state_context'; +import { useAppContext } from '../../../../../app_context'; import { documentationService } from '../../../../../services/documentation'; import { UseField, FormDataProvider, FormRow, SuperSelectField } from '../../../shared_imports'; import { ComboBoxOption } from '../../../types'; @@ -24,7 +24,7 @@ import { } from './constants'; export const SourceFieldSection = () => { - const state = useMappingsState(); + const { canUseSyntheticSource } = useAppContext(); const renderOptionDropdownDisplay = (option: SourceOptionKey) => ( <Fragment> @@ -44,7 +44,7 @@ export const SourceFieldSection = () => { }, ]; - if (state.hasEnterpriseLicense) { + if (canUseSyntheticSource) { sourceValueOptions.push({ value: SYNTHETIC_SOURCE_OPTION, inputDisplay: sourceOptionLabels[SYNTHETIC_SOURCE_OPTION], diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx index a9c54aee8036..813cc1023c06 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/field_parameters/select_inference_id.tsx @@ -80,13 +80,15 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({ value, }) => { const { - core: { application, http }, + core: { application }, docLinks, - plugins: { ml }, + plugins: { ml, share }, } = useAppContext(); const config = getFieldConfig('inference_id'); - const inferenceEndpointsPageLink = `${http.basePath.get()}/app/enterprise_search/relevance/inference_endpoints`; + const inferenceEndpointsPageLink = share?.url.locators + .get('SEARCH_INFERENCE_ENDPOINTS') + ?.useUrl({}); const [isInferenceFlyoutVisible, setIsInferenceFlyoutVisible] = useState<boolean>(false); const [availableTrainedModels, setAvailableTrainedModels] = useState< @@ -130,6 +132,14 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({ 'data-test-subj': `custom-inference_${endpoint.inference_id}`, checked: value === endpoint.inference_id ? 'on' : undefined, })); + /** + * Adding this check to ensure we have the preconfigured elser endpoint selected by default. + */ + const hasInferenceSelected = newOptions.some((option) => option.checked === 'on'); + if (!hasInferenceSelected && newOptions.length > 0) { + newOptions[0].checked = 'on'; + } + if (value && !newOptions.find((option) => option.label === value)) { // Sometimes we create a new endpoint but the backend is slow in updating so we need to optimistically update const newOption: EuiSelectableOption = { @@ -224,24 +234,28 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({ panelPaddingSize="m" closePopover={() => setIsInferencePopoverVisible(!isInferencePopoverVisible)} > - <EuiContextMenuPanel> - <EuiContextMenuItem - key="manageInferenceEndpointButton" - icon="gear" - size="s" - data-test-subj="manageInferenceEndpointButton" - onClick={async () => { - application.navigateToUrl(inferenceEndpointsPageLink); - }} - > - {i18n.translate( - 'xpack.idxMgmt.mappingsEditor.parameters.inferenceId.popover.manageInferenceEndpointButton', - { - defaultMessage: 'Manage Inference Endpoints', - } - )} - </EuiContextMenuItem> - </EuiContextMenuPanel> + {inferenceEndpointsPageLink && ( + <EuiContextMenuPanel> + <EuiContextMenuItem + key="manageInferenceEndpointButton" + icon="gear" + size="s" + data-test-subj="manageInferenceEndpointButton" + href={inferenceEndpointsPageLink} + onClick={(e) => { + e.preventDefault(); + application.navigateToUrl(inferenceEndpointsPageLink); + }} + > + {i18n.translate( + 'xpack.idxMgmt.mappingsEditor.parameters.inferenceId.popover.manageInferenceEndpointButton', + { + defaultMessage: 'Manage Inference Endpoints', + } + )} + </EuiContextMenuItem> + </EuiContextMenuPanel> + )} <EuiHorizontalRule margin="none" /> <EuiPanel color="transparent" paddingSize="s"> <EuiTitle size="xxxs"> @@ -267,6 +281,7 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({ searchable isLoading={isLoading} singleSelection="always" + defaultChecked searchProps={{ compressed: true, placeholder: i18n.translate( @@ -292,7 +307,7 @@ const SelectInferenceIdContent: React.FC<SelectInferenceIdContentProps> = ({ <EuiHorizontalRule margin="none" /> <EuiContextMenuItem icon={<EuiIcon type="help" color="primary" />} size="s"> <EuiLink - href={docLinks.links.enterpriseSearch.inferenceApiCreate} + href={docLinks.links.inferenceManagement.inferenceAPIDocumentation} target="_blank" data-test-subj="learn-how-to-create-inference-endpoints" > diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts index 65415a287d94..e0ce2db2446e 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { CustomInferenceEndpointConfig, SemanticTextField } from '../../../../../types'; import { useSemanticText } from './use_semantic_text'; import { act } from 'react-dom/test-utils'; @@ -13,15 +13,15 @@ import { act } from 'react-dom/test-utils'; jest.mock('../../../../../../../../hooks/use_details_page_mappings_model_management', () => ({ useDetailsPageMappingsModelManagement: () => ({ fetchInferenceToModelIdMap: () => ({ - e5: { + '.preconfigured_elser': { isDeployed: false, isDeployable: true, - trainedModelId: '.multilingual-e5-small', + trainedModelId: '.elser_model_2', }, - elser_model_2: { + '.preconfigured_e5': { isDeployed: false, isDeployable: true, - trainedModelId: '.elser_model_2', + trainedModelId: '.multilingual-e5-small', }, openai: { isDeployed: false, @@ -49,13 +49,13 @@ const mockField: Record<string, SemanticTextField> = { elser_model_2: { name: 'name', type: 'semantic_text', - inference_id: 'elser_model_2', + inference_id: '.preconfigured_elser', reference_field: 'title', }, e5: { name: 'name', type: 'semantic_text', - inference_id: 'e5', + inference_id: '.preconfigured_e5', reference_field: 'title', }, openai: { @@ -100,15 +100,15 @@ const mockDispatch = jest.fn(); jest.mock('../../../../../mappings_state_context', () => ({ useMappingsState: jest.fn().mockReturnValue({ inferenceToModelIdMap: { - e5: { + '.preconfigured_elser': { isDeployed: false, isDeployable: true, - trainedModelId: '.multilingual-e5-small', + trainedModelId: '.elser_model_2', }, - elser_model_2: { + '.preconfigured_e5': { isDeployed: false, isDeployable: true, - trainedModelId: '.elser_model_2', + trainedModelId: '.multilingual-e5-small', }, openai: { isDeployed: false, @@ -142,7 +142,7 @@ jest.mock('../../../../../../../services/api', () => ({ getInferenceEndpoints: jest.fn().mockResolvedValue({ data: [ { - inference_id: 'e5', + inference_id: '.preconfigured_e5', task_type: 'text_embedding', service: 'elasticsearch', service_settings: { @@ -212,28 +212,6 @@ describe('useSemanticText', () => { mockConfig.openai.modelConfig ); }); - it('should handle semantic text with inference endpoint created from flyout correctly', async () => { - const { result } = renderHook(() => - useSemanticText({ - form: mockForm.elasticModelEndpointCreatedfromFlyout, - setErrorsInTrainedModelDeployment: jest.fn(), - ml: mlMock, - }) - ); - await act(async () => { - result.current.handleSemanticText(mockField.my_elser_endpoint, mockConfig.elser); - }); - - expect(mockDispatch).toHaveBeenCalledWith({ - type: 'field.add', - value: mockField.my_elser_endpoint, - }); - expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith( - 'my_elser_endpoint', - 'sparse_embedding', - mockConfig.elser.modelConfig - ); - }); it('should handle semantic text correctly', async () => { const { result } = renderHook(() => @@ -252,20 +230,6 @@ describe('useSemanticText', () => { type: 'field.add', value: mockField.elser_model_2, }); - expect(mlMock.mlApi.inferenceModels.createInferenceEndpoint).toHaveBeenCalledWith( - 'elser_model_2', - 'sparse_embedding', - { - service: 'elser', - service_settings: { - adaptive_allocations: { - enabled: true, - }, - num_threads: 1, - model_id: '.elser_model_2', - }, - } - ); }); it('does not call create inference endpoint api, if default endpoint already exists', async () => { const { result } = renderHook(() => diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts index a464a279a8dd..a7b380fd120c 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/create_field/semantic_text/use_semantic_text.ts @@ -19,7 +19,6 @@ import { useMLModelNotificationToasts } from '../../../../../../../../hooks/use_ import { getInferenceEndpoints } from '../../../../../../../services/api'; import { getFieldByPathName } from '../../../../../lib/utils'; -import { ELSER_PRECONFIGURED_ENDPOINTS } from '../../../../../constants'; interface UseSemanticTextProps { form: FormHook<Field, Field>; @@ -63,9 +62,6 @@ export function useSemanticText(props: UseSemanticTextProps) { if (!form.getFormData().reference_field) { form.setFieldValue('reference_field', referenceField); } - if (!form.getFormData().inference_id) { - form.setFieldValue('inference_id', ELSER_PRECONFIGURED_ENDPOINTS); - } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [fieldTypeValue]); diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx index a67a7df0acb7..33c51a3cb644 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/components/document_fields/fields/fields_list_item.tsx @@ -19,11 +19,7 @@ import { i18n } from '@kbn/i18n'; import { NormalizedField, NormalizedFields, State } from '../../../types'; import { getTypeLabelFromField } from '../../../lib'; -import { - CHILD_FIELD_INDENT_SIZE, - ELSER_PRECONFIGURED_ENDPOINTS, - LEFT_PADDING_SIZE_FIELD_ITEM_WRAPPER, -} from '../../../constants'; +import { CHILD_FIELD_INDENT_SIZE, LEFT_PADDING_SIZE_FIELD_ITEM_WRAPPER } from '../../../constants'; import { FieldsList } from './fields_list'; import { CreateField } from './create_field'; @@ -109,7 +105,6 @@ function FieldListItemComponent( const indent = treeDepth * CHILD_FIELD_INDENT_SIZE - substractIndentAmount; const isSemanticText = source.type === 'semantic_text'; - const inferenceId: string = (source.inference_id as string) ?? ELSER_PRECONFIGURED_ENDPOINTS; const indentCreateField = (treeDepth + 1) * CHILD_FIELD_INDENT_SIZE + @@ -298,7 +293,7 @@ function FieldListItemComponent( {isSemanticText && ( <EuiFlexItem grow={false}> - <EuiBadge color="hollow">{inferenceId}</EuiBadge> + <EuiBadge color="hollow">{source.inference_id as string}</EuiBadge> </EuiFlexItem> )} diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts index f8c6da8f7cdd..b839caf75b24 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/default_values.ts @@ -13,9 +13,3 @@ export const INDEX_DEFAULT = 'index_default'; export const STANDARD = 'standard'; - -/* - This will be repalce once we add default elser inference_id - with the index mapping response. -*/ -export const ELSER_PRECONFIGURED_ENDPOINTS = '.elser-2-elasticsearch'; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx index 7e10c5d5deaa..749150cf2d67 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/constants/parameters_definition.tsx @@ -1126,22 +1126,10 @@ export const PARAMETERS_DEFINITION: { [key in ParameterName]: ParameterDefinitio }, inference_id: { fieldConfig: { - defaultValue: 'elser_model_2', + defaultValue: '', label: i18n.translate('xpack.idxMgmt.mappingsEditor.parameters.inferenceIdLabel', { defaultMessage: 'Select an inference endpoint:', }), - validations: [ - { - validator: emptyField( - i18n.translate( - 'xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage', - { - defaultMessage: 'Inference ID is required.', - } - ) - ), - }, - ], }, schema: t.string, }, diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts index 872c62bc6f7a..58b40293f64f 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/lib/utils.test.ts @@ -421,7 +421,6 @@ describe('utils', () => { selectedDataTypes: ['Boolean'], }, inferenceToModelIdMap: {}, - hasEnterpriseLicense: true, mappingViewFields: { byId: {}, rootLevelFields: [], aliases: {}, maxNestedDepth: 0 }, }; test('returns list of matching fields with search term', () => { diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx index cc87c3cd614e..9f59f4959bed 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_editor.tsx @@ -9,7 +9,6 @@ import React, { useMemo, useState, useEffect, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiSpacer, EuiTabs, EuiTab } from '@elastic/eui'; -import { ILicense } from '@kbn/licensing-plugin/common/types'; import { useAppContext } from '../../app_context'; import { IndexMode } from '../../../../common/types/data_streams'; import { @@ -61,9 +60,7 @@ export interface Props { export const MappingsEditor = React.memo( ({ onChange, value, docLinks, indexSettings, esNodesPlugins, indexMode }: Props) => { - const { - plugins: { licensing }, - } = useAppContext(); + const { canUseSyntheticSource } = useAppContext(); const { parsedDefaultValue, multipleMappingsDeclared } = useMemo<MappingsEditorParsedMetadata>( () => parseMappings(value), [value] @@ -128,39 +125,22 @@ export const MappingsEditor = React.memo( [dispatch] ); - const [isLicenseCheckComplete, setIsLicenseCheckComplete] = useState(false); - useEffect(() => { - const subscription = licensing?.license$.subscribe((license: ILicense) => { - dispatch({ - type: 'hasEnterpriseLicense.update', - value: license.isActive && license.hasAtLeast('enterprise'), - }); - setIsLicenseCheckComplete(true); - }); - - return () => subscription?.unsubscribe(); - }, [dispatch, licensing]); - useEffect(() => { if ( - isLicenseCheckComplete && !state.configuration.defaultValue._source && (indexMode === LOGSDB_INDEX_MODE || indexMode === TIME_SERIES_MODE) ) { - if (state.hasEnterpriseLicense) { + if (canUseSyntheticSource) { + // If the source field is undefined (hasn't been set in the form) + // and if the user has selected a `logsdb` or `time_series` index mode in the Logistics step, + // update the form data with synthetic _source dispatch({ type: 'configuration.save', value: { ...state.configuration.defaultValue, _source: { mode: 'synthetic' } } as any, }); } } - }, [ - indexMode, - dispatch, - state.configuration, - state.hasEnterpriseLicense, - isLicenseCheckComplete, - ]); + }, [indexMode, dispatch, state.configuration, canUseSyntheticSource]); const tabToContentMap = { fields: ( diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state_context.tsx b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state_context.tsx index 4fd89ad0e25a..ac19c5395f97 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state_context.tsx +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/mappings_state_context.tsx @@ -60,7 +60,6 @@ export const StateProvider: React.FC<{ children?: React.ReactNode }> = ({ childr selectedDataTypes: [], }, inferenceToModelIdMap: {}, - hasEnterpriseLicense: false, mappingViewFields: { byId: {}, rootLevelFields: [], aliases: {}, maxNestedDepth: 0 }, }; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/reducer.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/reducer.ts index ecb9648c34d0..626ee0e839a8 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/reducer.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/reducer.ts @@ -629,11 +629,5 @@ export const reducer = (state: State, action: Action): State => { inferenceToModelIdMap: action.value.inferenceToModelIdMap, }; } - case 'hasEnterpriseLicense.update': { - return { - ...state, - hasEnterpriseLicense: action.value, - }; - } } }; diff --git a/x-pack/plugins/index_management/public/application/components/mappings_editor/types/state.ts b/x-pack/plugins/index_management/public/application/components/mappings_editor/types/state.ts index 43b3a7dde3b1..f40fe420eb3b 100644 --- a/x-pack/plugins/index_management/public/application/components/mappings_editor/types/state.ts +++ b/x-pack/plugins/index_management/public/application/components/mappings_editor/types/state.ts @@ -108,7 +108,6 @@ export interface State { }; templates: TemplatesFormState; inferenceToModelIdMap?: InferenceToModelIdMap; - hasEnterpriseLicense: boolean; mappingViewFields: NormalizedFields; // state of the incoming index mappings, separate from the editor state above } @@ -141,7 +140,6 @@ export type Action = | { type: 'fieldsJsonEditor.update'; value: { json: { [key: string]: any }; isValid: boolean } } | { type: 'search:update'; value: string } | { type: 'validity:update'; value: boolean } - | { type: 'filter:update'; value: { selectedOptions: EuiSelectableOption[] } } - | { type: 'hasEnterpriseLicense.update'; value: boolean }; + | { type: 'filter:update'; value: { selectedOptions: EuiSelectableOption[] } }; export type Dispatch = (action: Action) => void; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx b/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx index 38a11f03c7ee..cc12cfc988d5 100644 --- a/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx +++ b/x-pack/plugins/index_management/public/application/components/shared/components/wizard_steps/step_settings.tsx @@ -92,7 +92,7 @@ export const StepSettings: React.FunctionComponent<Props> = React.memo( title={ <FormattedMessage id="xpack.idxMgmt.formWizard.stepSettings.indexModeCallout.title" - defaultMessage="The {settingName} setting has been set to {indexMode} within template {logisticsLink}. Any changes to {settingName} set on this page will be overwritten by the Logistics selection." + defaultMessage="The {settingName} setting has been set to {indexMode} within the {logisticsLink}. Any changes to {settingName} set on this page will be overwritten by the Logistics selection." values={{ settingName: ( <EuiCode> @@ -110,7 +110,7 @@ export const StepSettings: React.FunctionComponent<Props> = React.memo( {i18n.translate( 'xpack.idxMgmt.formWizard.stepSettings.indexModeCallout.logisticsLinkLabel', { - defaultMessage: 'Logistics', + defaultMessage: 'Logistics step', } )} </EuiLink> diff --git a/x-pack/plugins/index_management/public/application/hooks/redirect_path.test.tsx b/x-pack/plugins/index_management/public/application/hooks/redirect_path.test.tsx index 5b189ccbc253..83bd06a8dd49 100644 --- a/x-pack/plugins/index_management/public/application/hooks/redirect_path.test.tsx +++ b/x-pack/plugins/index_management/public/application/hooks/redirect_path.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import { createMemoryHistory } from 'history'; import { useRedirectPath } from './redirect_path'; diff --git a/x-pack/plugins/index_management/public/application/mount_management_section.ts b/x-pack/plugins/index_management/public/application/mount_management_section.ts index da17bc4706c0..83cf620a0e8e 100644 --- a/x-pack/plugins/index_management/public/application/mount_management_section.ts +++ b/x-pack/plugins/index_management/public/application/mount_management_section.ts @@ -57,6 +57,7 @@ export function getIndexManagementDependencies({ cloud, startDependencies, uiMetricService, + canUseSyntheticSource, }: { core: CoreStart; usageCollection: UsageCollectionSetup; @@ -68,9 +69,12 @@ export function getIndexManagementDependencies({ cloud?: CloudSetup; startDependencies: StartDependencies; uiMetricService: UiMetricService; + canUseSyntheticSource: boolean; }): AppDependencies { const { docLinks, application, uiSettings, settings } = core; const { url } = startDependencies.share; + const { monitor, manageEnrich, monitorEnrich } = application.capabilities.index_management; + return { core: { getUrlForApp: application.getUrlForApp, @@ -100,6 +104,12 @@ export function getIndexManagementDependencies({ docLinks, kibanaVersion, overlays: core.overlays, + canUseSyntheticSource, + privs: { + monitor: !!monitor, + manageEnrich: !!manageEnrich, + monitorEnrich: !!monitorEnrich, + }, }; } @@ -112,6 +122,7 @@ export async function mountManagementSection({ kibanaVersion, config, cloud, + canUseSyntheticSource, }: { coreSetup: CoreSetup<StartDependencies>; usageCollection: UsageCollectionSetup; @@ -121,6 +132,7 @@ export async function mountManagementSection({ kibanaVersion: SemVer; config: AppDependencies['config']; cloud?: CloudSetup; + canUseSyntheticSource: boolean; }) { const { element, setBreadcrumbs, history } = params; const [core, startDependencies] = await coreSetup.getStartServices(); @@ -148,6 +160,7 @@ export async function mountManagementSection({ startDependencies, uiMetricService, usageCollection, + canUseSyntheticSource, }); const unmountAppCallback = renderApp(element, { core, dependencies: appDependencies }); diff --git a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/enrich_policy_create.tsx b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/enrich_policy_create.tsx index f7ef260b1465..321dee68ae8a 100644 --- a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/enrich_policy_create.tsx +++ b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/enrich_policy_create.tsx @@ -14,12 +14,8 @@ import { breadcrumbService, IndexManagementBreadcrumb } from '../../services/bre import { CreatePolicyWizard } from './create_policy_wizard'; import { CreatePolicyContextProvider } from './create_policy_context'; -import { - EnrichPoliciesAuthProvider, - EnrichPoliciesWithPrivileges, -} from '../../components/enrich_policies'; -const CreateView: React.FunctionComponent<RouteComponentProps> = () => { +export const EnrichPolicyCreate: React.FunctionComponent<RouteComponentProps> = () => { useEffect(() => { breadcrumbService.setBreadcrumbs(IndexManagementBreadcrumb.enrichPoliciesCreate); }, []); @@ -64,11 +60,3 @@ const CreateView: React.FunctionComponent<RouteComponentProps> = () => { </CreatePolicyContextProvider> ); }; - -export const EnrichPolicyCreate: React.FunctionComponent<RouteComponentProps> = (props) => ( - <EnrichPoliciesAuthProvider> - <EnrichPoliciesWithPrivileges> - <CreateView {...props} /> - </EnrichPoliciesWithPrivileges> - </EnrichPoliciesAuthProvider> -); diff --git a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/configuration.tsx b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/configuration.tsx index 6e743c6bd078..175bb812dbd5 100644 --- a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/configuration.tsx +++ b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/configuration.tsx @@ -94,18 +94,15 @@ export const configurationFormSchema: FormSchema = { }, sourceIndices: { - label: i18n.translate('xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesLabel', { - defaultMessage: 'Source indices', + label: i18n.translate('xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceLabel', { + defaultMessage: 'Source', }), validations: [ { validator: fieldValidators.emptyField( - i18n.translate( - 'xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesRequiredError', - { - defaultMessage: 'At least one source index is required.', - } - ) + i18n.translate('xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceRequiredError', { + defaultMessage: 'At least one source is required.', + }) ), }, ], diff --git a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx index 9181449f2dba..825a97763841 100644 --- a/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx +++ b/x-pack/plugins/index_management/public/application/sections/enrich_policy_create/steps/fields/indices_selector.tsx @@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n'; import { uniq, isEmpty } from 'lodash'; import { EuiFormRow, EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; import type { EuiComboBoxProps } from '@elastic/eui'; -import { getMatchingIndices } from '../../../../services/api'; +import { getMatchingDataStreams, getMatchingIndices } from '../../../../services/api'; import type { FieldHook } from '../../../../../shared_imports'; import { getFieldValidityAndErrorMessage } from '../../../../../shared_imports'; @@ -25,23 +25,76 @@ interface Props { [key: string]: any; } -const getIndexOptions = async (patternString: string) => { - const options: IOption[] = []; +interface GetMatchingOptionsParams { + matches: string[]; + optionsMessage: string; + noMatchingMessage: string; +} +const i18nTexts = { + indices: { + options: i18n.translate('xpack.idxMgmt.enrichPolicyCreate.indicesSelector.optionsLabel', { + defaultMessage: 'Based on your indices', + }), + noMatches: i18n.translate('xpack.idxMgmt.enrichPolicyCreate.indicesSelector.noMatchingOption', { + defaultMessage: 'No indices match your search criteria.', + }), + }, + dataStreams: { + options: i18n.translate( + 'xpack.idxMgmt.enrichPolicyCreate.indicesSelector.dataStream.optionsLabel', + { + defaultMessage: 'Based on your data streams', + } + ), + noMatches: i18n.translate( + 'xpack.idxMgmt.enrichPolicyCreate.indicesSelector.dataStream.noMatchingOption', + { + defaultMessage: 'No data streams match your search criteria.', + } + ), + }, + sourcePlaceholder: i18n.translate( + 'xpack.idxMgmt.enrichPolicyCreate.indicesSelector.placeholder', + { + defaultMessage: 'Select source indices and data streams.', + } + ), +}; + +const getIndexOptions = async (patternString: string) => { if (!patternString) { - return options; + return []; } - const { data } = await getMatchingIndices(patternString); - const matchingIndices = data.indices; + const { data: indicesData } = await getMatchingIndices(patternString); + const { data: dataStreamsData } = await getMatchingDataStreams(patternString); - if (matchingIndices.length) { - const matchingOptions = uniq([...matchingIndices]); + const indices = getMatchingOptions({ + matches: indicesData.indices, + optionsMessage: i18nTexts.indices.options, + noMatchingMessage: i18nTexts.indices.noMatches, + }); + const dataStreams = getMatchingOptions({ + matches: dataStreamsData.dataStreams, + optionsMessage: i18nTexts.dataStreams.options, + noMatchingMessage: i18nTexts.dataStreams.noMatches, + }); + + return [...indices, ...dataStreams]; +}; + +const getMatchingOptions = ({ + matches, + optionsMessage, + noMatchingMessage, +}: GetMatchingOptionsParams) => { + const options: IOption[] = []; + if (matches.length) { + const matchingOptions = uniq([...matches]); options.push({ - label: i18n.translate('xpack.idxMgmt.enrichPolicyCreate.indicesSelector.optionsLabel', { - defaultMessage: 'Based on your indices', - }), + label: optionsMessage, options: matchingOptions .map((match) => { return { @@ -53,13 +106,10 @@ const getIndexOptions = async (patternString: string) => { }); } else { options.push({ - label: i18n.translate('xpack.idxMgmt.enrichPolicyCreate.indicesSelector.noMatchingOption', { - defaultMessage: 'No indices match your search criteria.', - }), + label: noMatchingMessage, options: [], }); } - return options; }; @@ -71,7 +121,6 @@ export const IndicesSelector = ({ field, euiFieldProps, ...rest }: Props) => { const onSearchChange = useCallback( async (search: string) => { const indexPattern = isEmpty(search) ? '*' : search; - setIsIndiciesLoading(true); setIndexOptions(await getIndexOptions(indexPattern)); setIsIndiciesLoading(false); @@ -98,6 +147,7 @@ export const IndicesSelector = ({ field, euiFieldProps, ...rest }: Props) => { > <EuiComboBox async + placeholder={i18nTexts.sourcePlaceholder} isLoading={isIndiciesLoading} options={indexOptions} noSuggestions={!indexOptions.length} diff --git a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx index a036273ebdde..eeba7b9e03fd 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/enrich_policies_list.tsx @@ -17,10 +17,6 @@ import { APP_WRAPPER_CLASS, useExecutionContext } from '../../../../shared_impor import { useAppContext } from '../../../app_context'; import { useRedirectPath } from '../../../hooks/redirect_path'; -import { - EnrichPoliciesAuthProvider, - EnrichPoliciesWithPrivileges, -} from '../../../components/enrich_policies'; import { breadcrumbService, IndexManagementBreadcrumb } from '../../../services/breadcrumbs'; import { documentationService } from '../../../services/documentation'; import { useLoadEnrichPolicies } from '../../../services/api'; @@ -34,9 +30,13 @@ const getEnrichPolicyNameFromLocation = (location: Location) => { return policy; }; -const ListView: React.FunctionComponent<RouteComponentProps> = ({ history, location }) => { +export const EnrichPoliciesList: React.FunctionComponent<RouteComponentProps> = ({ + history, + location, +}) => { const { core: { executionContext }, + privs, } = useAppContext(); const redirectTo = useRedirectPath(history); @@ -79,7 +79,7 @@ const ListView: React.FunctionComponent<RouteComponentProps> = ({ history, locat return <ErrorState error={error} resendRequest={reloadPolicies} />; } - if (policies?.length === 0) { + if (privs.manageEnrich && policies?.length === 0) { return <EmptyState />; } @@ -151,11 +151,3 @@ const ListView: React.FunctionComponent<RouteComponentProps> = ({ history, locat </div> ); }; - -export const EnrichPoliciesList: React.FunctionComponent<RouteComponentProps> = (props) => ( - <EnrichPoliciesAuthProvider> - <EnrichPoliciesWithPrivileges> - <ListView {...props} /> - </EnrichPoliciesWithPrivileges> - </EnrichPoliciesAuthProvider> -); diff --git a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx index e78e08b82999..61574a70fa54 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/enrich_policies_list/policies_table/policies_table.tsx @@ -33,43 +33,84 @@ export const PoliciesTable: FunctionComponent<Props> = ({ onDeletePolicyClick, onExecutePolicyClick, }) => { - const { history } = useAppContext(); + const { history, privs } = useAppContext(); - const renderToolsRight = () => { - return [ - <EuiButton - key="reloadPolicies" - data-test-subj="reloadPoliciesButton" - iconType="refresh" - color="success" - onClick={onReloadClick} - > - <FormattedMessage - id="xpack.idxMgmt.enrichPolicies.table.reloadButton" - defaultMessage="Reload" - /> - </EuiButton>, - <EuiButton - key="createPolicy" - fill - iconType="plusInCircle" - {...reactRouterNavigate(history, '/enrich_policies/create')} - > - <FormattedMessage - id="xpack.idxMgmt.enrichPolicies.table.createPolicyButton" - defaultMessage="Create enrich policy" - /> - </EuiButton>, - ]; - }; + const createBtn = ( + <EuiButton + key="createPolicy" + fill + iconType="plusInCircle" + data-test-subj="createPolicyButton" + {...reactRouterNavigate(history, '/enrich_policies/create')} + > + <FormattedMessage + id="xpack.idxMgmt.enrichPolicies.table.createPolicyButton" + defaultMessage="Create enrich policy" + /> + </EuiButton> + ); + + const toolsRight = [ + <EuiButton + key="reloadPolicies" + data-test-subj="reloadPoliciesButton" + iconType="refresh" + color="success" + onClick={onReloadClick} + > + <FormattedMessage + id="xpack.idxMgmt.enrichPolicies.table.reloadButton" + defaultMessage="Reload" + /> + </EuiButton>, + ]; + + if (privs.manageEnrich) { + toolsRight.push(createBtn); + } const search: EuiSearchBarProps = { - toolsRight: renderToolsRight(), + toolsRight, box: { incremental: true, }, }; + const actions: EuiBasicTableColumn<SerializedEnrichPolicy> = { + name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.actionsField', { + defaultMessage: 'Actions', + }), + actions: [ + { + isPrimary: true, + name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeAction', { + defaultMessage: 'Execute', + }), + description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeDescription', { + defaultMessage: 'Execute this enrich policy', + }), + type: 'icon', + icon: 'play', + 'data-test-subj': 'executePolicyButton', + onClick: ({ name }) => onExecutePolicyClick(name), + }, + { + isPrimary: true, + name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteAction', { + defaultMessage: 'Delete', + }), + description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteDescription', { + defaultMessage: 'Delete this enrich policy', + }), + type: 'icon', + icon: 'trash', + color: 'danger', + 'data-test-subj': 'deletePolicyButton', + onClick: ({ name }) => onDeletePolicyClick(name), + }, + ], + }; + const columns: Array<EuiBasicTableColumn<SerializedEnrichPolicy>> = [ { field: 'name', @@ -120,42 +161,12 @@ export const PoliciesTable: FunctionComponent<Props> = ({ truncateText: true, render: (fields: string[]) => <span className="eui-textTruncate">{fields.join(', ')}</span>, }, - { - name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.actionsField', { - defaultMessage: 'Actions', - }), - actions: [ - { - isPrimary: true, - name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeAction', { - defaultMessage: 'Execute', - }), - description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.executeDescription', { - defaultMessage: 'Execute this enrich policy', - }), - type: 'icon', - icon: 'play', - 'data-test-subj': 'executePolicyButton', - onClick: ({ name }) => onExecutePolicyClick(name), - }, - { - isPrimary: true, - name: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteAction', { - defaultMessage: 'Delete', - }), - description: i18n.translate('xpack.idxMgmt.enrichPolicies.table.deleteDescription', { - defaultMessage: 'Delete this enrich policy', - }), - type: 'icon', - icon: 'trash', - color: 'danger', - 'data-test-subj': 'deletePolicyButton', - onClick: ({ name }) => onDeletePolicyClick(name), - }, - ], - }, ]; + if (privs.manageEnrich) { + columns.push(actions); + } + const { pageSize, sorting, onTableChange } = useEuiTablePersist<SerializedEnrichPolicy>({ tableId: 'enrichPolicies', initialPageSize: 50, diff --git a/x-pack/plugins/index_management/public/application/sections/home/home.tsx b/x-pack/plugins/index_management/public/application/sections/home/home.tsx index e7de896fa4b3..2d0fc7d4ec10 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/home.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/home.tsx @@ -41,6 +41,7 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma }) => { const { plugins: { console: consolePlugin }, + privs, } = useAppContext(); const tabs = [ { @@ -74,7 +75,10 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma /> ), }, - { + ]; + + if (privs.monitorEnrich) { + tabs.push({ id: Section.EnrichPolicies, name: ( <FormattedMessage @@ -82,8 +86,8 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma defaultMessage="Enrich Policies" /> ), - }, - ]; + }); + } const onSectionChange = (newSection: Section) => { history.push(`/${newSection}`); @@ -143,7 +147,9 @@ export const IndexManagementHome: React.FunctionComponent<RouteComponentProps<Ma ]} component={ComponentTemplateList} /> - <Route exact path={`/${Section.EnrichPolicies}`} component={EnrichPoliciesList} /> + {privs.monitorEnrich && ( + <Route exact path={`/${Section.EnrichPolicies}`} component={EnrichPoliciesList} /> + )} </Routes> {consolePlugin?.EmbeddableConsole ? <consolePlugin.EmbeddableConsole /> : null} </> diff --git a/x-pack/plugins/index_management/public/application/services/api.ts b/x-pack/plugins/index_management/public/application/services/api.ts index 9f03007014c4..5e4f88ebb6b1 100644 --- a/x-pack/plugins/index_management/public/application/services/api.ts +++ b/x-pack/plugins/index_management/public/application/services/api.ts @@ -400,6 +400,16 @@ export async function getMatchingIndices(pattern: string) { return result; } +export async function getMatchingDataStreams(pattern: string) { + const result = sendRequest({ + path: `${INTERNAL_API_BASE_PATH}/enrich_policies/get_matching_data_streams`, + method: 'post', + body: JSON.stringify({ pattern }), + }); + + return result; +} + export async function getFieldsFromIndices(indices: string[]) { const result = sendRequest<FieldFromIndicesRequest>({ path: `${INTERNAL_API_BASE_PATH}/enrich_policies/get_fields_from_indices`, diff --git a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts index 62746791510c..4de34b584aec 100644 --- a/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts +++ b/x-pack/plugins/index_management/public/hooks/use_details_page_mappings_model_management.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { NormalizedFields } from '../application/components/mappings_editor/types'; import { useDetailsPageMappingsModelManagement } from './use_details_page_mappings_model_management'; diff --git a/x-pack/plugins/index_management/public/plugin.ts b/x-pack/plugins/index_management/public/plugin.ts index 5d857d8d8ac9..06adcc75d80b 100644 --- a/x-pack/plugins/index_management/public/plugin.ts +++ b/x-pack/plugins/index_management/public/plugin.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { Subject } from 'rxjs'; import SemVer from 'semver/classes/semver'; import { @@ -14,12 +15,14 @@ import { Plugin, PluginInitializerContext, ScopedHistory, + Capabilities, } from '@kbn/core/public'; import { IndexManagementPluginSetup, IndexManagementPluginStart, } from '@kbn/index-management-shared-types'; import { IndexManagementLocator } from '@kbn/index-management-shared-types'; +import { Subscription } from 'rxjs'; import { setExtensionsService } from './application/store/selectors/extension_service'; import { ExtensionsService } from './services/extensions_service'; @@ -57,6 +60,10 @@ export class IndexMgmtUIPlugin enableProjectLevelRetentionChecks: boolean; enableSemanticText: boolean; }; + private canUseSyntheticSource: boolean = false; + private licensingSubscription?: Subscription; + + private capabilities$ = new Subject<Capabilities>(); constructor(ctx: PluginInitializerContext) { // Temporary hack to provide the service instances in module files in order to avoid a big refactor @@ -95,28 +102,34 @@ export class IndexMgmtUIPlugin coreSetup: CoreSetup<StartDependencies>, plugins: SetupDependencies ): IndexManagementPluginSetup { - if (this.config.isIndexManagementUiEnabled) { - const { fleet, usageCollection, management, cloud } = plugins; + const { fleet, usageCollection, management, cloud } = plugins; - management.sections.section.data.registerApp({ - id: PLUGIN.id, - title: i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management' }), - order: 0, - mount: async (params) => { - const { mountManagementSection } = await import('./application/mount_management_section'); - return mountManagementSection({ - coreSetup, - usageCollection, - params, - extensionsService: this.extensionsService, - isFleetEnabled: Boolean(fleet), - kibanaVersion: this.kibanaVersion, - config: this.config, - cloud, - }); - }, - }); - } + this.capabilities$.subscribe((capabilities) => { + const { monitor, manageEnrich, monitorEnrich } = capabilities.index_management; + if (this.config.isIndexManagementUiEnabled && (monitor || manageEnrich || monitorEnrich)) { + management.sections.section.data.registerApp({ + id: PLUGIN.id, + title: i18n.translate('xpack.idxMgmt.appTitle', { defaultMessage: 'Index Management' }), + order: 0, + mount: async (params) => { + const { mountManagementSection } = await import( + './application/mount_management_section' + ); + return mountManagementSection({ + coreSetup, + usageCollection, + params, + extensionsService: this.extensionsService, + isFleetEnabled: Boolean(fleet), + kibanaVersion: this.kibanaVersion, + config: this.config, + cloud, + canUseSyntheticSource: this.canUseSyntheticSource, + }); + }, + }); + } + }); this.locator = plugins.share.url.locators.create( new IndexManagementLocatorDefinition({ @@ -133,6 +146,13 @@ export class IndexMgmtUIPlugin public start(coreStart: CoreStart, plugins: StartDependencies): IndexManagementPluginStart { const { fleet, usageCollection, cloud, share, console, ml, licensing } = plugins; + + this.capabilities$.next(coreStart.application.capabilities); + + this.licensingSubscription = licensing?.license$.subscribe((next) => { + this.canUseSyntheticSource = next.hasAtLeast('enterprise'); + }); + return { extensionsService: this.extensionsService.setup(), getIndexMappingComponent: (deps: { history: ScopedHistory<unknown> }) => { @@ -213,5 +233,7 @@ export class IndexMgmtUIPlugin }, }; } - public stop() {} + public stop() { + this.licensingSubscription?.unsubscribe(); + } } diff --git a/x-pack/plugins/index_management/server/plugin.ts b/x-pack/plugins/index_management/server/plugin.ts index 0ba15c463d4e..ab6b058cddc7 100644 --- a/x-pack/plugins/index_management/server/plugin.ts +++ b/x-pack/plugins/index_management/server/plugin.ts @@ -37,15 +37,20 @@ export class IndexMgmtServerPlugin implements Plugin<IndexManagementPluginSetup, ): IndexManagementPluginSetup { features.registerElasticsearchFeature({ id: PLUGIN.id, - management: { - data: ['index_management'], - }, privileges: [ + { + requiredClusterPrivileges: ['monitor_enrich'], + ui: ['monitorEnrich'], + }, + { + requiredClusterPrivileges: ['manage_enrich'], + ui: ['manageEnrich'], + }, { // manage_index_templates is also required, but we will disable specific parts of the // UI if this privilege is missing. requiredClusterPrivileges: ['monitor'], - ui: [], + ui: ['monitor'], }, ], }); diff --git a/x-pack/plugins/index_management/server/routes/api/enrich_policies/enrich_policies.test.ts b/x-pack/plugins/index_management/server/routes/api/enrich_policies/enrich_policies.test.ts index fb548b49623e..98a9c7f34d01 100644 --- a/x-pack/plugins/index_management/server/routes/api/enrich_policies/enrich_policies.test.ts +++ b/x-pack/plugins/index_management/server/routes/api/enrich_policies/enrich_policies.test.ts @@ -366,4 +366,33 @@ describe('Enrich policies API', () => { expect(searchMock).toHaveBeenCalled(); }); }); + + describe('Get matching indices - POST /api/index_management/enrich_policies/get_matching_data_streams', () => { + const getDataStreamsMock = router.getMockESApiFn('indices.getDataStream'); + + it('Return matching data streams', async () => { + const mockRequest: RequestMock = { + method: 'post', + path: addInternalBasePath('/enrich_policies/get_matching_data_streams'), + body: { + pattern: 'test', + }, + }; + + getDataStreamsMock.mockResolvedValue({ + body: {}, + statusCode: 200, + }); + + const res = await router.runRequest(mockRequest); + + expect(res).toEqual({ + body: { + dataStreams: [], + }, + }); + + expect(getDataStreamsMock).toHaveBeenCalledWith({ name: '*test*', expand_wildcards: 'open' }); + }); + }); }); diff --git a/x-pack/plugins/index_management/server/routes/api/enrich_policies/helpers.ts b/x-pack/plugins/index_management/server/routes/api/enrich_policies/helpers.ts index 6ecc6e9eb7ad..32b7d0b64718 100644 --- a/x-pack/plugins/index_management/server/routes/api/enrich_policies/helpers.ts +++ b/x-pack/plugins/index_management/server/routes/api/enrich_policies/helpers.ts @@ -145,3 +145,15 @@ export async function getIndices(dataClient: IScopedClusterClient, pattern: stri return indices.buckets ? indices.buckets.map((bucket) => bucket.key) : []; } +export async function getDataStreams( + dataClient: IScopedClusterClient, + pattern: string, + limit = 10 +) { + const response = await dataClient.asCurrentUser.indices.getDataStream({ + name: pattern, + expand_wildcards: 'open', + }); + + return response.data_streams ? response.data_streams.map((dataStream) => dataStream.name) : []; +} diff --git a/x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts b/x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts index bb6ef8b1fff5..ff165876a6ee 100644 --- a/x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts +++ b/x-pack/plugins/index_management/server/routes/api/enrich_policies/register_create_route.ts @@ -13,7 +13,13 @@ import { RouteDependencies } from '../../../types'; import { addInternalBasePath } from '..'; import { enrichPoliciesActions } from '../../../lib/enrich_policies'; import { serializeAsESPolicy } from '../../../../common/lib'; -import { normalizeFieldsList, getIndices, FieldCapsList, getCommonFields } from './helpers'; +import { + normalizeFieldsList, + getIndices, + FieldCapsList, + getCommonFields, + getDataStreams, +} from './helpers'; const validationSchema = schema.object({ policy: schema.object({ @@ -105,6 +111,33 @@ export function registerCreateRoute({ router, lib: { handleEsError } }: RouteDep } } ); + router.post( + { + path: addInternalBasePath('/enrich_policies/get_matching_data_streams'), + validate: { body: getMatchingIndicesSchema }, + }, + async (context, request, response) => { + let { pattern } = request.body; + const client = (await context.core).elasticsearch.client as IScopedClusterClient; + + // Add wildcards to the search query to match the behavior of the + // index pattern search in the Kibana UI. + if (!pattern.startsWith('*')) { + pattern = `*${pattern}`; + } + if (!pattern.endsWith('*')) { + pattern = `${pattern}*`; + } + + try { + const dataStreams = await getDataStreams(client, pattern); + + return response.ok({ body: { dataStreams } }); + } catch (error) { + return handleEsError({ error, response }); + } + } + ); router.post( { diff --git a/x-pack/plugins/inference/common/index.ts b/x-pack/plugins/inference/common/index.ts index 79433cbc71a6..6098c3fbd932 100644 --- a/x-pack/plugins/inference/common/index.ts +++ b/x-pack/plugins/inference/common/index.ts @@ -5,13 +5,7 @@ * 2.0. */ -export { - correctCommonEsqlMistakes, - splitIntoCommands, -} from './tasks/nl_to_esql/correct_common_esql_mistakes'; - +export { correctCommonEsqlMistakes, splitIntoCommands } from './tasks/nl_to_esql'; export { generateFakeToolCallId } from './utils/generate_fake_tool_call_id'; - export { createOutputApi } from './output'; - export type { ChatCompleteRequestBody, GetConnectorsResponseBody } from './http_apis'; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/ast_tools/timespan.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/ast_tools/timespan.ts new file mode 100644 index 000000000000..25ff8c1a0048 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/ast_tools/timespan.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ESQLTimeInterval } from '@kbn/esql-ast'; + +const units = [ + 'millisecond', + 'milliseconds', + 'ms', + // + 'second', + 'seconds', + 'sec', + 's', + // + 'minute', + 'minutes', + 'min', + // + 'hour', + 'hours', + 'h', + // + 'day', + 'days', + 'd', + // + 'week', + 'weeks', + 'w', + // + 'month', + 'months', + 'mo', + // + 'quarter', + 'quarters', + 'q', + // + 'year', + 'years', + 'yr', + 'y', +]; + +const timespanStringRegexp = new RegExp(`^["']?([0-9]+)?\\s*?(${units.join('|')})["']?$`, 'i'); + +export function createTimespanLiteral(unit: string, quantity: number): ESQLTimeInterval { + return { + type: 'timeInterval', + quantity, + unit, + text: `${unit}${quantity}`, + name: `${unit} ${quantity}`, + incomplete: false, + location: { min: 0, max: 0 }, + }; +} + +export function isTimespanString(str: string): boolean { + return Boolean(str.match(timespanStringRegexp)); +} + +export function stringToTimespanLiteral(str: string): ESQLTimeInterval { + const match = timespanStringRegexp.exec(str); + if (!match) { + throw new Error(`String "${str}" cannot be converted to timespan literal`); + } + const [_, quantity, unit] = match; + + return createTimespanLiteral(unit.toLowerCase(), quantity ? parseInt(quantity, 10) : 1); +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/correct_with_ast.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/correct_with_ast.ts new file mode 100644 index 000000000000..b3a90b79e03a --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/correct_with_ast.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BasicPrettyPrinter, parse } from '@kbn/esql-ast'; +import { correctAll, type QueryCorrection } from './corrections'; + +interface CorrectWithAstResult { + output: string; + corrections: QueryCorrection[]; +} + +export const correctQueryWithAst = (query: string): CorrectWithAstResult => { + const { root, errors } = parse(query); + // don't try modifying anything if the query is not syntactically correct + if (errors) { + return { + output: query, + corrections: [], + }; + } + + const corrections = correctAll(root); + + const multiline = /\r?\n/.test(query); + const formattedQuery = BasicPrettyPrinter.print(root, { multiline, pipeTab: '' }); + + return { + output: formattedQuery, + corrections, + }; +}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/index.ts new file mode 100644 index 000000000000..76ffd993bb9a --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/index.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ESQLAstQueryExpression } from '@kbn/esql-ast'; +import type { QueryCorrection } from './types'; +import { correctTimespanLiterals } from './timespan_literals'; +import { correctLikeWildcards } from './like'; + +export type { QueryCorrection } from './types'; + +export const correctAll = (query: ESQLAstQueryExpression): QueryCorrection[] => { + const corrections: QueryCorrection[] = []; + corrections.push(...correctTimespanLiterals(query)); + corrections.push(...correctLikeWildcards(query)); + return corrections; +}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.test.ts new file mode 100644 index 000000000000..81779188c553 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.test.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { parse, BasicPrettyPrinter } from '@kbn/esql-ast'; +import { correctLikeWildcards } from './like'; + +describe('correctLikeWildcards', () => { + it('replaces badly used "_" wildcard', () => { + const query = 'FROM logs | WHERE message LIKE "ba_"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "ba?"'); + }); + + it('replaces badly used "%" wildcard', () => { + const query = 'FROM logs | WHERE message LIKE "b%"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "b*"'); + }); + + it('replaces multiple bad wildcards', () => { + const query = 'FROM logs | WHERE message LIKE "a__t%"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "a??t*"'); + }); + + it('replaces bad wildcards in multiple commands and functions', () => { + const query = + 'FROM logs | WHERE message LIKE "a%" AND TO_UPPER(level) LIKE "err%" | WHERE foo LIKE "ba_"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual( + 'FROM logs | WHERE message LIKE "a*" AND TO_UPPER(level) LIKE "err*" | WHERE foo LIKE "ba?"' + ); + }); + + it('does not replace escaped characters', () => { + const query = 'FROM logs | WHERE message LIKE "ba\\\\_"'; + const { root } = parse(query); + correctLikeWildcards(root); + + const output = BasicPrettyPrinter.print(root); + expect(output).toEqual('FROM logs | WHERE message LIKE "ba\\\\_"'); + }); +}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.ts new file mode 100644 index 000000000000..be61bd216284 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/like.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Walker, type ESQLAstQueryExpression } from '@kbn/esql-ast'; +import { isLikeOperatorNode, isStringLiteralNode } from '../typeguards'; +import type { ESQLLikeOperator, ESQLStringLiteral } from '../types'; +import type { QueryCorrection } from './types'; + +/** + * Correct wrong LIKE wildcard mistakes. + * The LLM can make mistake and use SQL wildcards for LIKE operators. + * + * E.g. + * `column LIKE "ba_"` => `column LIKE "ba?"` + * `column LIKE "ba%"` => `column LIKE "ba*"` + */ +export const correctLikeWildcards = (query: ESQLAstQueryExpression): QueryCorrection[] => { + const corrections: QueryCorrection[] = []; + + Walker.walk(query, { + visitFunction: (node) => { + if (isLikeOperatorNode(node)) { + corrections.push(...checkLikeNode(node)); + } + }, + }); + + return corrections; +}; + +function checkLikeNode(node: ESQLLikeOperator): QueryCorrection[] { + if (node.args.length !== 2 || !isStringLiteralNode(node.args[1])) { + return []; + } + const likeExpression = node.args[1] as ESQLStringLiteral; + + const initialValue = likeExpression.value; + + likeExpression.value = likeExpression.value + .replaceAll(/(?<!\\)%/g, '*') + .replaceAll(/(?<!\\)_/g, '?'); + + if (likeExpression.value !== initialValue) { + likeExpression.name = likeExpression.value; + + const correction: QueryCorrection = { + type: 'wrong_like_wildcard', + node, + description: `Replaced wrong like wildcard in LIKE operator at position ${node.location.min}`, + }; + return [correction]; + } + + return []; +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.test.ts new file mode 100644 index 000000000000..0febe4e8c249 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { parse, BasicPrettyPrinter } from '@kbn/esql-ast'; +import { correctTimespanLiterals } from './timespan_literals'; + +describe('correctTimespanLiterals', () => { + describe('with DATE_TRUNC', () => { + it('replaces a timespan with a proper timespan literal', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("1 year", date)'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | EVAL truncated = DATE_TRUNC(1 year, date)"` + ); + }); + + it('replaces a timespan without quantity', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("month", date)'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | EVAL truncated = DATE_TRUNC(1 month, date)"` + ); + }); + + it('replaces uppercase literals', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("1 YEAR", date)'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | EVAL truncated = DATE_TRUNC(1 year, date)"` + ); + }); + + it('returns info about the correction', () => { + const query = 'FROM logs | EVAL truncated = DATE_TRUNC("1 year", date)'; + const { root } = parse(query); + + const corrections = correctTimespanLiterals(root); + + expect(corrections).toHaveLength(1); + expect(corrections[0]).toEqual({ + type: 'string_as_timespan_literal', + description: + 'Replaced string literal with timespan literal in DATE_TRUNC function at position 29', + node: expect.any(Object), + }); + }); + }); + + describe('with BUCKET', () => { + it('replaces a timespan with a proper timespan literal', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, "1 week")'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, 1 week)"` + ); + }); + + it('replaces a timespan without quantity', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, "hour")'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, 1 hour)"` + ); + }); + + it('replaces uppercase literals', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, "1 WEEK")'; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root); + + expect(output).toMatchInlineSnapshot( + `"FROM logs | STATS hires = COUNT(*) BY week = BUCKET(hire_date, 1 week)"` + ); + }); + + it('returns info about the correction', () => { + const query = 'FROM logs | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, "hour")'; + const { root } = parse(query); + + const corrections = correctTimespanLiterals(root); + + expect(corrections).toHaveLength(1); + expect(corrections[0]).toEqual({ + type: 'string_as_timespan_literal', + description: + 'Replaced string literal with timespan literal in BUCKET function at position 45', + node: expect.any(Object), + }); + }); + }); + + describe('with mixed usages', () => { + it('find all occurrences in a complex query', () => { + const query = `FROM logs + | EVAL trunc_year = DATE_TRUNC("1 year", date) + | EVAL trunc_month = DATE_TRUNC("month", date) + | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, "3 hour")`; + const { root } = parse(query); + + correctTimespanLiterals(root); + + const output = BasicPrettyPrinter.print(root, { multiline: true, pipeTab: '' }); + + expect(output).toMatchInlineSnapshot(` + "FROM logs + | EVAL trunc_year = DATE_TRUNC(1 year, date) + | EVAL trunc_month = DATE_TRUNC(1 month, date) + | STATS hires = COUNT(*) BY hour = BUCKET(hire_date, 3 hour)" + `); + }); + }); +}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.ts new file mode 100644 index 000000000000..039632c3d103 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/timespan_literals.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Walker, type ESQLAstQueryExpression } from '@kbn/esql-ast'; +import { isDateTruncFunctionNode, isBucketFunctionNode, isStringLiteralNode } from '../typeguards'; +import type { ESQLDateTruncFunction, ESQLBucketFunction } from '../types'; +import { stringToTimespanLiteral, isTimespanString } from '../ast_tools/timespan'; +import { QueryCorrection } from './types'; + +/** + * Correct timespan literal grammar mistakes, and returns the list of corrections that got applied. + * + * E.g. + * `DATE_TRUNC("YEAR", @timestamp)` => `DATE_TRUNC(1 year, @timestamp)` + * `BUCKET(@timestamp, "1 week")` => `BUCKET(@timestamp, 1 week)` + * + */ +export const correctTimespanLiterals = (query: ESQLAstQueryExpression): QueryCorrection[] => { + const corrections: QueryCorrection[] = []; + + Walker.walk(query, { + visitFunction: (node) => { + if (isDateTruncFunctionNode(node)) { + corrections.push(...checkDateTrunc(node)); + } + if (isBucketFunctionNode(node)) { + corrections.push(...checkBucket(node)); + } + }, + }); + + return corrections; +}; + +function checkDateTrunc(node: ESQLDateTruncFunction): QueryCorrection[] { + if (node.args.length !== 2) { + return []; + } + + const firstArg = node.args[0]; + + if (isStringLiteralNode(firstArg) && isTimespanString(firstArg.value)) { + const replacement = stringToTimespanLiteral(firstArg.value); + node.args[0] = replacement; + + const correction: QueryCorrection = { + type: 'string_as_timespan_literal', + node, + description: `Replaced string literal with timespan literal in DATE_TRUNC function at position ${node.location.min}`, + }; + return [correction]; + } + + return []; +} + +function checkBucket(node: ESQLBucketFunction): QueryCorrection[] { + // only checking the 2 args version - e.g. BUCKET(hire_date, 1 week) + if (node.args.length !== 2) { + return []; + } + + const secondArg = node.args[1]; + + if (isStringLiteralNode(secondArg) && isTimespanString(secondArg.value)) { + const replacement = stringToTimespanLiteral(secondArg.value); + node.args[1] = replacement; + + const correction: QueryCorrection = { + type: 'string_as_timespan_literal', + node, + description: `Replaced string literal with timespan literal in BUCKET function at position ${node.location.min}`, + }; + return [correction]; + } + + return []; +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/types.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/types.ts new file mode 100644 index 000000000000..dc1210c84acc --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/corrections/types.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ESQLSingleAstItem } from '@kbn/esql-ast'; + +/** + * Represents a correction that was applied to the query + */ +export interface QueryCorrection { + /** The type of correction */ + type: string; + /** A human-friendly-ish description of the correction */ + description: string; + /** The parent node the correction was applied to */ + node: ESQLSingleAstItem; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/index.ts similarity index 81% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/index.ts rename to x-pack/plugins/inference/common/tasks/nl_to_esql/ast/index.ts index 59ac4e0e37ef..d0e1a4808829 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_content/components/error_connecting/index.ts +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ErrorConnecting } from './error_connecting'; +export { correctQueryWithAst } from './correct_with_ast'; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/typeguards.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/typeguards.ts new file mode 100644 index 000000000000..54bbe2f7300a --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/typeguards.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + ESQLSingleAstItem, + ESQLAstItem, + ESQLFunction, + ESQLLiteral, + ESQLColumn, +} from '@kbn/esql-ast'; +import type { + ESQLStringLiteral, + ESQLDateTruncFunction, + ESQLBucketFunction, + ESQLLikeOperator, +} from './types'; + +export function isSingleItem(item: ESQLAstItem): item is ESQLSingleAstItem { + return Object.hasOwn(item, 'type'); +} + +export function isFunctionNode(node: ESQLAstItem): node is ESQLFunction { + return isSingleItem(node) && node.type === 'function'; +} + +export function isColumnNode(node: ESQLAstItem): node is ESQLColumn { + return isSingleItem(node) && node.type === 'column'; +} + +export function isLiteralNode(node: ESQLAstItem): node is ESQLLiteral { + return isSingleItem(node) && node.type === 'literal'; +} + +export function isStringLiteralNode(node: ESQLAstItem): node is ESQLStringLiteral { + return isLiteralNode(node) && node.literalType === 'keyword'; +} + +export function isDateTruncFunctionNode(node: ESQLAstItem): node is ESQLDateTruncFunction { + return isFunctionNode(node) && node.subtype === 'variadic-call' && node.name === 'date_trunc'; +} + +export function isBucketFunctionNode(node: ESQLAstItem): node is ESQLBucketFunction { + return isFunctionNode(node) && node.subtype === 'variadic-call' && node.name === 'bucket'; +} + +export function isLikeOperatorNode(node: ESQLAstItem): node is ESQLLikeOperator { + return isFunctionNode(node) && node.subtype === 'binary-expression' && node.name === 'like'; +} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/types.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/types.ts new file mode 100644 index 000000000000..6444f1490f3d --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/ast/types.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ESQLFunction, ESQLLiteral } from '@kbn/esql-ast'; + +/** + * represents a DATE_TRUNC function node. + */ +export type ESQLDateTruncFunction = ESQLFunction<'variadic-call', 'date_trunc'>; + +/** + * represents a LIKE function node. + */ +export type ESQLLikeOperator = ESQLFunction<'binary-expression', 'like'>; + +/** + * represents a BUCKET function node. + */ +export type ESQLBucketFunction = ESQLFunction<'variadic-call', 'bucket'>; + +/** + * represents an ESQL string literal. + */ +export type ESQLStringLiteral = Extract<ESQLLiteral, { literalType: 'keyword' }>; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.test.ts new file mode 100644 index 000000000000..22ae55f772e9 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.test.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { correctCommonEsqlMistakes } from './correct_esql_query'; + +jest.mock('./ast'); +jest.mock('./non_ast'); +import { correctQueryWithAst } from './ast'; +import { correctCommonEsqlMistakes as correctQueryWithoutAst } from './non_ast'; + +const correctQueryWithAstMock = correctQueryWithAst as jest.MockedFn<typeof correctQueryWithAst>; +const correctQueryWithoutAstMock = correctQueryWithoutAst as jest.MockedFn< + typeof correctQueryWithoutAst +>; + +describe('correctCommonEsqlMistakes', () => { + beforeEach(() => { + correctQueryWithoutAstMock.mockImplementation((query) => { + return { + input: query, + output: query, + isCorrection: false, + }; + }); + correctQueryWithAstMock.mockImplementation((query) => { + return { + output: query, + corrections: [], + }; + }); + }); + + afterEach(() => { + correctQueryWithoutAstMock.mockReset(); + correctQueryWithAstMock.mockReset(); + }); + + it('calls correctQueryWithoutAst with the right parameters', () => { + const inputQuery = 'FROM logs | WHERE foo > bar'; + correctCommonEsqlMistakes(inputQuery); + + expect(correctQueryWithoutAstMock).toHaveBeenCalledTimes(1); + expect(correctQueryWithoutAstMock).toHaveBeenCalledWith(inputQuery); + }); + + it('calls correctQueryWithAst with the right parameters', () => { + const inputQuery = 'FROM logs | WHERE foo > bar'; + const correctQueryWithoutAstResult = 'FROM logs | WHERE foo > dolly'; + + correctQueryWithoutAstMock.mockImplementation((query) => { + return { + input: inputQuery, + output: correctQueryWithoutAstResult, + isCorrection: true, + }; + }); + + correctCommonEsqlMistakes(inputQuery); + + expect(correctQueryWithAstMock).toHaveBeenCalledTimes(1); + expect(correctQueryWithAstMock).toHaveBeenCalledWith(correctQueryWithoutAstResult); + }); + + it('returns the corrected query', () => { + const inputQuery = 'FROM logs | WHERE foo > bar'; + const correctQueryWithAstResult = 'FROM logs | WHERE foo > dolly'; + + correctQueryWithAstMock.mockImplementation((query) => { + return { + output: correctQueryWithAstResult, + corrections: [], + }; + }); + + const { input, output } = correctCommonEsqlMistakes(inputQuery); + + expect(input).toEqual(inputQuery); + expect(output).toEqual(correctQueryWithAstResult); + }); +}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts new file mode 100644 index 000000000000..4ad96323cc7e --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_esql_query.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { correctQueryWithAst } from './ast'; +import { correctCommonEsqlMistakes as correctQueryWithoutAst } from './non_ast'; + +/** + * Correct some common ES|QL syntax and grammar mistakes that LLM can potentially do. + * + * Correcting the query is done in two steps: + * 1. we try to correct the *syntax*, without AST (given it requires a valid syntax) + * 2. we try to correct the *grammar*, using AST this time. + */ +export const correctCommonEsqlMistakes = (query: string) => { + const { output: outputWithoutAst, isCorrection: correctionWithoutAst } = + correctQueryWithoutAst(query); + const { output: corrected, corrections } = correctQueryWithAst(outputWithoutAst); + return { + input: query, + output: corrected, + isCorrection: correctionWithoutAst || corrections.length > 0, + }; +}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.test.ts deleted file mode 100644 index 818f4854e038..000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.test.ts +++ /dev/null @@ -1,46 +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 { correctQueryWithActions } from './correct_query_with_actions'; - -describe('correctQueryWithActions', () => { - it(`fixes errors correctly for a query with one syntax error for stats`, async () => { - const fixedQuery = await correctQueryWithActions('from logstash-* | stats aveg(bytes)'); - expect(fixedQuery).toBe('from logstash-* | stats avg(bytes)'); - }); - - it(`fixes errors correctly for a query with 2 syntax errors for stats`, async () => { - const fixedQuery = await correctQueryWithActions( - 'from logstash-* | stats aveg(bytes), max2(bytes)' - ); - expect(fixedQuery).toBe('from logstash-* | stats avg(bytes), max(bytes)'); - }); - - it(`fixes errors correctly for a query with one syntax error for eval`, async () => { - const fixedQuery = await correctQueryWithActions( - 'from logstash-* | stats var0 = max(bytes) | eval ab(var0) | limit 1' - ); - expect(fixedQuery).toBe('from logstash-* | stats var0 = max(bytes) | eval abs(var0) | limit 1'); - }); - - it(`fixes errors correctly for a query with two syntax error for eval`, async () => { - const fixedQuery = await correctQueryWithActions( - 'from logstash-* | stats var0 = max2(bytes) | eval ab(var0) | limit 1' - ); - expect(fixedQuery).toBe('from logstash-* | stats var0 = max(bytes) | eval abs(var0) | limit 1'); - }); - - it(`doesnt complain for @timestamp column`, async () => { - const queryWithTimestamp = `FROM logstash-* - | WHERE @timestamp >= NOW() - 15 minutes - | EVAL bucket = DATE_TRUNC(1 minute, @timestamp) - | STATS avg_cpu = AVG(system.cpu.total.norm.pct) BY service.name, bucket - | SORT avg_cpu DESC - | LIMIT 10`; - const fixedQuery = await correctQueryWithActions(queryWithTimestamp); - expect(fixedQuery).toBe(queryWithTimestamp); - }); -}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts deleted file mode 100644 index 30e2c11adb6d..000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_query_with_actions.ts +++ /dev/null @@ -1,63 +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 { validateQuery, getActions } from '@kbn/esql-validation-autocomplete'; -import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; - -const fixedQueryByOneAction = async (queryString: string) => { - const { errors } = await validateQuery(queryString, getAstAndSyntaxErrors, { - ignoreOnMissingCallbacks: true, - }); - - const actions = await getActions(queryString, errors, getAstAndSyntaxErrors, { - relaxOnMissingCallbacks: true, - }); - - if (actions.length) { - const [firstAction] = actions; - const range = firstAction.edits[0].range; - const correctText = firstAction.edits[0].text; - const problematicString = queryString.substring(range.startColumn - 1, range.endColumn - 1); - const fixedQuery = queryString.replace(problematicString, correctText); - - return { - query: fixedQuery, - shouldRunAgain: Boolean(actions.length), - }; - } - return { - query: queryString, - shouldRunAgain: false, - }; -}; - -/** - * @param queryString - * @returns corrected queryString - * The cases that are handled are: - * - Query stats / eval functions have typos e.g. aveg instead of avg - * - Unquoted fields e.g. keep field-1 instead of keep `field-1` - * - Unquoted fields in stats or eval e.g. stats avg(field-1) instead of stats avg(`field-1`) - * - Combination of the above - */ - -export const correctQueryWithActions = async (queryString: string) => { - let shouldCorrectQuery = true; - let fixedQuery = queryString; - // this is an escape hatch, the loop will end automatically if the ast doesnt return more actions - // in case it goes wrong, we allow it to loop 10 times - let limit = 10; - - while (shouldCorrectQuery && limit >= 0) { - const { query, shouldRunAgain } = await fixedQueryByOneAction(fixedQuery); - shouldCorrectQuery = shouldRunAgain; - fixedQuery = query; - limit--; - } - - return fixedQuery; -}; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.test.ts deleted file mode 100644 index 04d99aede62b..000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { getErrorsWithCommands } from './get_errors_with_commands'; - -describe('getErrorsWithCommands', () => { - it('returns the command associated with the error', () => { - expect( - getErrorsWithCommands(`FROM logs-* | WHERE @timestamp <= NOW() | STATS BY host.name`, [ - { - type: 'error', - text: 'Syntax error', - code: '', - location: { - min: 24, - max: 36, - }, - }, - ]) - ).toEqual(['Error in `| WHERE @timestamp <= NOW()`:\n Syntax error']); - }); -}); diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.ts deleted file mode 100644 index b25c79161f79..000000000000 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/get_errors_with_commands.ts +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { EditorError, ESQLMessage } from '@kbn/esql-ast'; -import { splitIntoCommands } from './correct_common_esql_mistakes'; - -export function getErrorsWithCommands(query: string, errors: Array<ESQLMessage | EditorError>) { - const asCommands = splitIntoCommands(query); - - const errorMessages = errors.map((error) => { - if ('location' in error) { - const commandsUntilEndOfError = splitIntoCommands(query.substring(0, error.location.max)); - const lastCompleteCommand = asCommands[commandsUntilEndOfError.length - 1]; - if (lastCompleteCommand) { - return `Error in \`| ${lastCompleteCommand.command}\`:\n ${error.text}`; - } - } - return 'text' in error ? error.text : error.message; - }); - - return errorMessages; -} diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/index.ts new file mode 100644 index 000000000000..2efacc374e8c --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { correctCommonEsqlMistakes } from './correct_esql_query'; +export { splitIntoCommands } from './non_ast'; diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.test.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.test.ts similarity index 99% rename from x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.test.ts rename to x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.test.ts index 8c6b90bca76a..9d4b064b35f6 100644 --- a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.test.ts +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.test.ts @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ + import { correctCommonEsqlMistakes } from './correct_common_esql_mistakes'; describe('correctCommonEsqlMistakes', () => { diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts similarity index 100% rename from x-pack/plugins/inference/common/tasks/nl_to_esql/correct_common_esql_mistakes.ts rename to x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/correct_common_esql_mistakes.ts diff --git a/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/index.ts b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/index.ts new file mode 100644 index 000000000000..2752f82ce9c4 --- /dev/null +++ b/x-pack/plugins/inference/common/tasks/nl_to_esql/non_ast/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { correctCommonEsqlMistakes, splitIntoCommands } from './correct_common_esql_mistakes'; diff --git a/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts b/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts index a35491a47604..fba1d75956bf 100644 --- a/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts +++ b/x-pack/plugins/inference/scripts/load_esql_docs/load_esql_docs.ts @@ -13,7 +13,7 @@ import Path from 'path'; import yargs, { Argv } from 'yargs'; import { REPO_ROOT } from '@kbn/repo-info'; import { INLINE_ESQL_QUERY_REGEX } from '../../common/tasks/nl_to_esql/constants'; -import { correctCommonEsqlMistakes } from '../../common/tasks/nl_to_esql/correct_common_esql_mistakes'; +import { correctCommonEsqlMistakes } from '../../common/tasks/nl_to_esql'; import { connectorIdOption, elasticsearchOption, kibanaOption } from '../util/cli_options'; import { getServiceUrls } from '../util/get_service_urls'; import { KibanaClient } from '../util/kibana_client'; diff --git a/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts b/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts index 823344f52a89..049e627303d1 100644 --- a/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts +++ b/x-pack/plugins/inference/server/tasks/nl_to_esql/validate_esql_query.ts @@ -11,7 +11,7 @@ import type { ElasticsearchClient } from '@kbn/core/server'; import { ESQLSearchResponse, ESQLRow } from '@kbn/es-types'; import { esFieldTypeToKibanaFieldType } from '@kbn/field-types'; import { DatatableColumn, DatatableColumnType } from '@kbn/expressions-plugin/common'; -import { splitIntoCommands } from '../../../common/tasks/nl_to_esql/correct_common_esql_mistakes'; +import { splitIntoCommands } from '../../../common'; export async function runAndValidateEsqlQuery({ query, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/foreach.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/foreach.test.tsx new file mode 100644 index 000000000000..e4ca33fbffad --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/foreach.test.tsx @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { setup, SetupResult, getProcessorValue, setupEnvironment } from './processor.helpers'; + +const FOREACH_TYPE = 'foreach'; + +describe('Processor: Foreach', () => { + let onUpdate: jest.Mock; + let testBed: SetupResult; + const { httpSetup } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers({ legacyFakeTimers: true }); + // disable all react-beautiful-dnd development warnings + (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = true; + }); + + afterAll(() => { + jest.useRealTimers(); + // enable all react-beautiful-dnd development warnings + (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = false; + }); + + beforeEach(async () => { + onUpdate = jest.fn(); + + await act(async () => { + testBed = await setup(httpSetup, { + value: { + processors: [], + }, + onFlyoutOpen: jest.fn(), + onUpdate, + }); + }); + + const { component, actions } = testBed; + + component.update(); + + // Open flyout to add new processor + actions.addProcessor(); + // Add type (the other fields are not visible until a type is selected) + await actions.addProcessorType(FOREACH_TYPE); + }); + + test('prevents form submission if required fields are not provided', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Click submit button with only the type defined + await saveNewProcessor(); + + // Expect form error as "field" is a required parameter + expect(form.getErrorsMessages()).toEqual(['A field value is required.']); + }); + + test('saves with default parameter values', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Add "field" value + form.setInputValue('fieldNameField.input', 'test_foreach_processor'); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, FOREACH_TYPE); + + expect(processors[0][FOREACH_TYPE]).toEqual({ + field: 'test_foreach_processor', + }); + }); + + test('accepts processor definitions that contains escaped characters', async () => { + const { + actions: { saveNewProcessor }, + form, + find, + component, + } = testBed; + + // Add "field" value + form.setInputValue('fieldNameField.input', 'test_foreach_processor'); + + await act(async () => { + find('processorField').simulate('change', { + jsonContent: '{"def_1":"""aaa"bbb""", "def_2":"aaa(bbb"}', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, FOREACH_TYPE); + + expect(processors[0][FOREACH_TYPE]).toEqual({ + field: 'test_foreach_processor', + // eslint-disable-next-line prettier/prettier + processor: { def_1: 'aaa\"bbb', def_2: 'aaa(bbb' }, + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts index 3f98b95ba8b6..84e494849569 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/grok.test.ts @@ -126,4 +126,41 @@ describe('Processor: Grok', () => { expect(processors[0][GROK_TYPE].patterns).toEqual([escapedValue]); }); + + test('accepts pattern definitions that contains escaped characters', async () => { + const { + actions: { saveNewProcessor }, + form, + find, + component, + } = testBed; + + // Add "field" value + form.setInputValue('fieldNameField.input', 'test_grok_processor'); + + // Add pattern 1 + form.setInputValue('droppableList.input-0', 'pattern1'); + + await act(async () => { + find('patternDefinitionsField').simulate('change', { + jsonContent: '{"pattern_1":"""aaa"bbb""", "pattern_2":"aaa(bbb"}', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, GROK_TYPE); + + expect(processors[0][GROK_TYPE]).toEqual({ + field: 'test_grok_processor', + patterns: ['pattern1'], + // eslint-disable-next-line prettier/prettier + pattern_definitions: { pattern_1: 'aaa\"bbb', pattern_2: 'aaa(bbb' }, + }); + }); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/inference.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/inference.test.tsx new file mode 100644 index 000000000000..5a07fc63d087 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/inference.test.tsx @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act } from 'react-dom/test-utils'; +import { setup, SetupResult, getProcessorValue, setupEnvironment } from './processor.helpers'; + +const INFERENCE_TYPE = 'inference'; + +describe('Processor: Script', () => { + let onUpdate: jest.Mock; + let testBed: SetupResult; + const { httpSetup } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers({ legacyFakeTimers: true }); + // disable all react-beautiful-dnd development warnings + (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = true; + }); + + afterAll(() => { + jest.useRealTimers(); + // enable all react-beautiful-dnd development warnings + (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = false; + }); + + beforeEach(async () => { + onUpdate = jest.fn(); + + await act(async () => { + testBed = await setup(httpSetup, { + value: { + processors: [], + }, + onFlyoutOpen: jest.fn(), + onUpdate, + }); + }); + + const { component, actions } = testBed; + + component.update(); + + // Open flyout to add new processor + actions.addProcessor(); + // Add type (the other fields are not visible until a type is selected) + await actions.addProcessorType(INFERENCE_TYPE); + }); + + test('prevents form submission if required fields are not provided', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Click submit button with only the type defined + await saveNewProcessor(); + + // Expect form error as "field" is a required parameter + expect(form.getErrorsMessages()).toEqual([ + 'A deployment, an inference, or a model ID value is required.', + ]); + }); + + test('accepts inference config and field maps that contains escaped characters', async () => { + const { + actions: { saveNewProcessor }, + find, + form, + component, + } = testBed; + + form.setInputValue('inferenceModelId.input', 'test_inference_processor'); + + await act(async () => { + find('inferenceConfig').simulate('change', { + jsonContent: '{"inf_conf_1":"""aaa"bbb""", "inf_conf_2": "aaa(bbb"}', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + await act(async () => { + find('fieldMap').simulate('change', { + jsonContent: '{"field_map_1":"""aaa"bbb""", "field_map_2": "aaa(bbb"}', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, INFERENCE_TYPE); + + expect(processors[0][INFERENCE_TYPE]).toEqual({ + model_id: 'test_inference_processor', + // eslint-disable-next-line prettier/prettier + inference_config: { inf_conf_1: 'aaa\"bbb', inf_conf_2: 'aaa(bbb' }, + // eslint-disable-next-line prettier/prettier + field_map: { field_map_1: 'aaa\"bbb', field_map_2: 'aaa(bbb' }, + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx index 0f3ea833a311..3eeff809999b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/processor.helpers.tsx @@ -199,4 +199,10 @@ type TestSubject = | 'ignoreMissingPipelineSwitch.input' | 'destinationField.input' | 'datasetField.input' - | 'namespaceField.input'; + | 'namespaceField.input' + | 'processorField' + | 'paramsField' + | 'scriptSource' + | 'inferenceModelId.input' + | 'inferenceConfig' + | 'fieldMap'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/redact.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/redact.test.tsx index d34e4d1476bb..eda4bac8266d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/redact.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/redact.test.tsx @@ -138,4 +138,40 @@ describe('Processor: Redact', () => { pattern_definitions: { GITHUB_NAME: '@%{USERNAME}' }, }); }); + test('accepts pattern definitions that contains escaped characters', async () => { + const { + actions: { saveNewProcessor }, + component, + find, + form, + } = testBed; + + // Add "field" value + form.setInputValue('fieldNameField.input', 'test_redact_processor'); + + // Add one pattern to the list + form.setInputValue('droppableList.input-0', 'pattern1'); + + await act(async () => { + find('patternDefinitionsField').simulate('change', { + jsonContent: '{"pattern_1":"""aaa"bbb""", "pattern_2":"aaa(bbb"}', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, REDACT_TYPE); + + expect(processors[0][REDACT_TYPE]).toEqual({ + field: 'test_redact_processor', + patterns: ['pattern1'], + + pattern_definitions: { pattern_1: 'aaa"bbb', pattern_2: 'aaa(bbb' }, + }); + }); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/script.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/script.test.tsx new file mode 100644 index 000000000000..428c87ea6a7e --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/__jest__/processors/script.test.tsx @@ -0,0 +1,104 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 } from 'react-dom/test-utils'; +import { setup, SetupResult, getProcessorValue, setupEnvironment } from './processor.helpers'; + +const SCRIPT_TYPE = 'script'; + +describe('Processor: Script', () => { + let onUpdate: jest.Mock; + let testBed: SetupResult; + const { httpSetup } = setupEnvironment(); + + beforeAll(() => { + jest.useFakeTimers({ legacyFakeTimers: true }); + // disable all react-beautiful-dnd development warnings + (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = true; + }); + + afterAll(() => { + jest.useRealTimers(); + // enable all react-beautiful-dnd development warnings + (window as any)['__@hello-pangea/dnd-disable-dev-warnings'] = false; + }); + + beforeEach(async () => { + onUpdate = jest.fn(); + + await act(async () => { + testBed = await setup(httpSetup, { + value: { + processors: [], + }, + onFlyoutOpen: jest.fn(), + onUpdate, + }); + }); + + const { component, actions } = testBed; + + component.update(); + + // Open flyout to add new processor + actions.addProcessor(); + // Add type (the other fields are not visible until a type is selected) + await actions.addProcessorType(SCRIPT_TYPE); + }); + + test('prevents form submission if required fields are not provided', async () => { + const { + actions: { saveNewProcessor }, + form, + } = testBed; + + // Click submit button with only the type defined + await saveNewProcessor(); + + // Expect form error as "field" is a required parameter + expect(form.getErrorsMessages()).toEqual(['A value is required.']); + }); + + test('accepts params that contains escaped characters', async () => { + const { + actions: { saveNewProcessor }, + find, + component, + } = testBed; + + await act(async () => { + find('scriptSource').simulate('change', { + jsonContent: 'ctx._source[params.sum_field]', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + await act(async () => { + find('paramsField').simulate('change', { + jsonContent: '{"sum_field":"""aaa"bbb"""}', + }); + + // advance timers to allow the form to validate + jest.advanceTimersByTime(0); + }); + component.update(); + + // Save the field + await saveNewProcessor(); + + const processors = getProcessorValue(onUpdate, SCRIPT_TYPE); + + expect(processors[0][SCRIPT_TYPE]).toEqual({ + source: 'ctx._source[params.sum_field]', + // eslint-disable-next-line prettier/prettier + params: { sum_field: 'aaa\"bbb' }, + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/field_components/xjson_editor.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/field_components/xjson_editor.tsx index 5134df09ac93..b5f98c260661 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/field_components/xjson_editor.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/field_components/xjson_editor.tsx @@ -7,9 +7,7 @@ import { XJsonLang } from '@kbn/monaco'; import React, { FunctionComponent, useCallback } from 'react'; -import { FieldHook, XJson } from '../../../../../../shared_imports'; - -const { useXJsonMode } = XJson; +import { FieldHook } from '../../../../../../shared_imports'; import { TextEditor } from './text_editor'; @@ -25,20 +23,17 @@ const defaultEditorOptions = { export const XJsonEditor: FunctionComponent<Props> = ({ field, editorProps }) => { const { value, setValue } = field; - const { xJson, setXJson, convertToJson } = useXJsonMode(value); - const onChange = useCallback( (s: any) => { - setXJson(s); - setValue(convertToJson(s)); + setValue(s); }, - [setValue, setXJson, convertToJson] + [setValue] ); return ( <TextEditor field={field} editorProps={{ - value: xJson, + value, languageId: XJsonLang.ID, options: defaultEditorOptions, onChange, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processor_form.container.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processor_form.container.tsx index e6a47c52657e..d32ea6d222b8 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processor_form.container.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processor_form.container.tsx @@ -79,7 +79,7 @@ export const ProcessorFormContainer: FunctionComponent<Props> = ({ type: formState.type, fields: formState.customOptions ? { - ...formState.customOptions, + customOptions: formState.customOptions, } : { ...formState.fields, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/custom.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/custom.tsx index 30cc54439f26..7aa55418552d 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/custom.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/custom.tsx @@ -15,30 +15,20 @@ import { UseField, } from '../../../../../../shared_imports'; -const { emptyField, isJsonField } = fieldValidators; +const { emptyField } = fieldValidators; import { XJsonEditor } from '../field_components'; import { Fields } from '../processor_form.container'; -import { EDITOR_PX_HEIGHT } from './shared'; +import { EDITOR_PX_HEIGHT, from, isXJsonField, to } from './shared'; const customConfig: FieldConfig<any> = { type: FIELD_TYPES.TEXT, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.customForm.optionsFieldLabel', { defaultMessage: 'Configuration', }), - serializer: (value: string) => { - try { - return JSON.parse(value); - } catch (error) { - // swallow error and return non-parsed value; - return value; - } - }, + serializer: from.optionalXJson, deserializer: (value: any) => { - if (value === '') { - return '{\n\n}'; - } - return JSON.stringify(value, null, 2); + return to.xJsonString(value.customOptions ? value.customOptions : value); }, validations: [ { @@ -52,7 +42,7 @@ const customConfig: FieldConfig<any> = { ), }, { - validator: isJsonField( + validator: isXJsonField( i18n.translate('xpack.ingestPipelines.pipelineEditor.customForm.invalidJsonError', { defaultMessage: 'The input is not valid.', }) diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/foreach.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/foreach.tsx index 55c3a3ac1115..2bcf2847ad77 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/foreach.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/foreach.tsx @@ -13,16 +13,16 @@ import { FIELD_TYPES, fieldValidators, UseField } from '../../../../../../shared import { XJsonEditor } from '../field_components'; import { FieldNameField } from './common_fields/field_name_field'; -import { FieldsConfig, to, EDITOR_PX_HEIGHT } from './shared'; +import { FieldsConfig, to, EDITOR_PX_HEIGHT, from, isXJsonField } from './shared'; -const { emptyField, isJsonField } = fieldValidators; +const { emptyField } = fieldValidators; const fieldsConfig: FieldsConfig = { /* Required fields config */ processor: { type: FIELD_TYPES.TEXT, - deserializer: to.jsonString, - serializer: JSON.parse, + deserializer: to.xJsonString, + serializer: from.optionalXJson, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.foreachForm.processorFieldLabel', { defaultMessage: 'Processor', }), @@ -41,7 +41,7 @@ const fieldsConfig: FieldsConfig = { ), }, { - validator: isJsonField( + validator: isXJsonField( i18n.translate( 'xpack.ingestPipelines.pipelineEditor.foreachForm.processorInvalidJsonError', { @@ -68,6 +68,7 @@ export const Foreach: FunctionComponent = () => { component={XJsonEditor} componentProps={{ editorProps: { + 'data-test-subj': 'processorField', height: EDITOR_PX_HEIGHT.medium, 'aria-label': i18n.translate( 'xpack.ingestPipelines.pipelineEditor.foreachForm.optionsFieldAriaLabel', diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/grok.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/grok.tsx index ae56d3b30a62..f07fb32aa64b 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/grok.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/grok.tsx @@ -18,13 +18,13 @@ import { ArrayItem, } from '../../../../../../shared_imports'; -import { XJsonEditor, DragAndDropTextList } from '../field_components'; +import { DragAndDropTextList, XJsonEditor } from '../field_components'; import { FieldNameField } from './common_fields/field_name_field'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FieldsConfig, to, from, EDITOR_PX_HEIGHT } from './shared'; +import { FieldsConfig, to, from, EDITOR_PX_HEIGHT, isXJsonField } from './shared'; -const { isJsonField, emptyField } = fieldValidators; +const { emptyField } = fieldValidators; const i18nTexts = { addPatternLabel: i18n.translate( @@ -70,8 +70,8 @@ const fieldsConfig: FieldsConfig = { /* Optional field configs */ pattern_definitions: { type: FIELD_TYPES.TEXT, - deserializer: to.jsonString, - serializer: from.optionalJson, + deserializer: to.xJsonString, + serializer: from.optionalXJson, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.grokForm.patternDefinitionsLabel', { defaultMessage: 'Pattern definitions (optional)', }), @@ -84,7 +84,7 @@ const fieldsConfig: FieldsConfig = { ), validations: [ { - validator: isJsonField( + validator: isXJsonField( i18n.translate( 'xpack.ingestPipelines.pipelineEditor.grokForm.patternsDefinitionsInvalidJSONError', { defaultMessage: 'Invalid JSON' } @@ -153,6 +153,7 @@ export const Grok: FunctionComponent = () => { config={fieldsConfig.pattern_definitions} componentProps={{ editorProps: { + 'data-test-subj': 'patternDefinitionsField', height: EDITOR_PX_HEIGHT.medium, 'aria-label': i18n.translate( 'xpack.ingestPipelines.pipelineEditor.grokForm.patternDefinitionsAriaLabel', @@ -163,6 +164,7 @@ export const Grok: FunctionComponent = () => { }, }} path="fields.pattern_definitions" + data-test-subj="patternDefinitions" /> <UseField diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx index a2623ca2aea9..a9dee127f0f7 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/inference.tsx @@ -18,13 +18,12 @@ import { useKibana, } from '../../../../../../shared_imports'; -import { XJsonEditor } from '../field_components'; - import { TargetField } from './common_fields/target_field'; -import { FieldsConfig, to, from, EDITOR_PX_HEIGHT } from './shared'; +import { FieldsConfig, to, from, EDITOR_PX_HEIGHT, isXJsonField } from './shared'; +import { XJsonEditor } from '../field_components'; -const { emptyField, isJsonField } = fieldValidators; +const { emptyField } = fieldValidators; const INFERENCE_CONFIG_DOCS = { documentation: { @@ -83,8 +82,8 @@ const fieldsConfig: FieldsConfig = { /* Optional fields config */ field_map: { type: FIELD_TYPES.TEXT, - deserializer: to.jsonString, - serializer: from.optionalJson, + deserializer: to.xJsonString, + serializer: from.optionalXJson, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.inferenceForm.fieldMapLabel', { defaultMessage: 'Field map (optional)', }), @@ -97,7 +96,7 @@ const fieldsConfig: FieldsConfig = { ), validations: [ { - validator: isJsonField( + validator: isXJsonField( i18n.translate( 'xpack.ingestPipelines.pipelineEditor.inferenceForm.fieldMapInvalidJSONError', { defaultMessage: 'Invalid JSON' } @@ -112,8 +111,8 @@ const fieldsConfig: FieldsConfig = { inference_config: { type: FIELD_TYPES.TEXT, - deserializer: to.jsonString, - serializer: from.optionalJson, + deserializer: to.xJsonString, + serializer: from.optionalXJson, label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.inferenceForm.inferenceConfigLabel', { @@ -122,7 +121,7 @@ const fieldsConfig: FieldsConfig = { ), validations: [ { - validator: isJsonField( + validator: isXJsonField( i18n.translate( 'xpack.ingestPipelines.pipelineEditor.grokForm.patternsDefinitionsInvalidJSONError', { defaultMessage: 'Invalid JSON' } @@ -141,7 +140,12 @@ export const Inference: FunctionComponent = () => { const documentationDocsLink = services.documentation.getDocumentationUrl(); return ( <> - <UseField config={fieldsConfig.model_id} component={Field} path="fields.model_id" /> + <UseField + config={fieldsConfig.model_id} + component={Field} + path="fields.model_id" + data-test-subj="inferenceModelId" + /> <TargetField helpText={ @@ -158,6 +162,7 @@ export const Inference: FunctionComponent = () => { component={XJsonEditor} componentProps={{ editorProps: { + 'data-test-subj': 'fieldMap', height: EDITOR_PX_HEIGHT.medium, options: { minimap: { enabled: false } }, }, @@ -173,6 +178,7 @@ export const Inference: FunctionComponent = () => { component={XJsonEditor} componentProps={{ editorProps: { + 'data-test-subj': 'inferenceConfig', height: EDITOR_PX_HEIGHT.medium, options: { minimap: { enabled: false } }, }, diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/redact.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/redact.tsx index 743a5b6b7275..37e488996dbe 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/redact.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/redact.tsx @@ -19,13 +19,13 @@ import { ValidationFunc, } from '../../../../../../shared_imports'; -import { XJsonEditor, InputList } from '../field_components'; +import { InputList, XJsonEditor } from '../field_components'; import { FieldNameField } from './common_fields/field_name_field'; import { IgnoreMissingField } from './common_fields/ignore_missing_field'; -import { FieldsConfig, to, from, EDITOR_PX_HEIGHT } from './shared'; +import { FieldsConfig, to, from, EDITOR_PX_HEIGHT, isXJsonField } from './shared'; -const { isJsonField, emptyField } = fieldValidators; +const { emptyField } = fieldValidators; const i18nTexts = { addPatternLabel: i18n.translate( @@ -68,8 +68,8 @@ const fieldsConfig: FieldsConfig = { /* Optional field configs */ pattern_definitions: { type: FIELD_TYPES.TEXT, - deserializer: to.jsonString, - serializer: from.optionalJson, + deserializer: to.xJsonString, + serializer: from.optionalXJson, label: i18n.translate( 'xpack.ingestPipelines.pipelineEditor.redactForm.patternDefinitionsLabel', { @@ -85,7 +85,7 @@ const fieldsConfig: FieldsConfig = { ), validations: [ { - validator: isJsonField( + validator: isXJsonField( i18n.translate( 'xpack.ingestPipelines.pipelineEditor.redactForm.patternsDefinitionsInvalidJSONError', { defaultMessage: 'Invalid JSON' } diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/script.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/script.tsx index 18da4097eaf2..bdbf90971621 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/script.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/script.tsx @@ -21,9 +21,16 @@ import { import { XJsonEditor, TextEditor } from '../field_components'; -import { FieldsConfig, to, from, FormFieldsComponent, EDITOR_PX_HEIGHT } from './shared'; +import { + FieldsConfig, + to, + from, + FormFieldsComponent, + EDITOR_PX_HEIGHT, + isXJsonField, +} from './shared'; -const { isJsonField, emptyField } = fieldValidators; +const { emptyField } = fieldValidators; const fieldsConfig: FieldsConfig = { /* Required fields config */ @@ -98,8 +105,8 @@ const fieldsConfig: FieldsConfig = { params: { type: FIELD_TYPES.TEXT, - deserializer: to.jsonString, - serializer: from.optionalJson, + deserializer: to.xJsonString, + serializer: from.optionalXJson, label: i18n.translate('xpack.ingestPipelines.pipelineEditor.scriptForm.paramsFieldLabel', { defaultMessage: 'Parameters', }), @@ -113,7 +120,7 @@ const fieldsConfig: FieldsConfig = { { validator: (value) => { if (value.value) { - return isJsonField( + return isXJsonField( i18n.translate( 'xpack.ingestPipelines.pipelineEditor.scriptForm.processorInvalidJsonError', { @@ -166,6 +173,7 @@ export const Script: FormFieldsComponent = ({ initialFieldValues }) => { component={TextEditor} componentProps={{ editorProps: { + 'data-test-subj': 'scriptSource', languageId: scriptLanguage, suggestionProvider: scriptLanguage === PainlessLang.ID ? suggestionProvider : undefined, @@ -191,6 +199,7 @@ export const Script: FormFieldsComponent = ({ initialFieldValues }) => { component={XJsonEditor} componentProps={{ editorProps: { + 'data-test-subj': 'paramsField', height: EDITOR_PX_HEIGHT.medium, 'aria-label': i18n.translate( 'xpack.ingestPipelines.pipelineEditor.scriptForm.paramsFieldAriaLabel', diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.test.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.test.ts index 4b01f22a9383..a3b77293c66f 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.test.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.test.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { from, to } from './shared'; +import { ValidationFuncArg } from '@kbn/console-plugin/public/shared_imports'; +import { from, isXJsonField, to } from './shared'; describe('shared', () => { describe('deserialization helpers', () => { @@ -28,6 +29,21 @@ describe('shared', () => { '%{clientip} %{ident} %{auth} [%{@timestamp}] \\"%{verb} %{request} HTTP/%{httpversion}\\" %{status} %{size}' ); }); + test('to.xJsonString', () => { + const input1 = ''; + expect(to.xJsonString(input1)).toBe('{}'); + + // eslint-disable-next-line prettier/prettier + const input2 = '{"ISSUE": "aaa\"bbb","ISSUE2": "aaa\\(bbb","ISSUE3": """aaa\"bbb"""}'; + expect(to.xJsonString(input2)).toBe( + // eslint-disable-next-line prettier/prettier + '{"ISSUE": "aaa\"bbb","ISSUE2": "aaa\\(bbb","ISSUE3": """aaa\"bbb"""}' + ); + + // eslint-disable-next-line prettier/prettier + const input3 = { ISSUE: "aaa\"bbb", ISSUE2: "aaa\\(bbb" }; + expect(to.xJsonString(input3)).toBe(JSON.stringify(input3, null, 2)); + }); }); describe('serialization helpers', () => { @@ -49,5 +65,33 @@ describe('shared', () => { `%{clientip} %{ident} %{auth} [%{@timestamp}] \"%{verb} %{request} HTTP/%{httpversion}\" %{status} %{size}` ); }); + test('from.optionalXJson', () => { + const input1 = ''; + expect(from.optionalXJson(input1)).toBe(undefined); + + const input2 = '{}'; + expect(from.optionalXJson(input2)).toBe(undefined); + + const input3 = '{"ISSUE": "aaa","ISSUE2": "bbb"}'; + expect(from.optionalXJson(input3)).toBe(input3); + }); + }); + describe('validators', () => { + test('isXJsonField', () => { + const message = 'test error message'; + const code = 'ERR_JSON_FORMAT'; + + const validate = isXJsonField(message); + const validator = (value: unknown) => validate({ value } as ValidationFuncArg<any, any>); + + // Valid JSON + const input1 = '{"ISSUE": """aaa"bbb""", "ISSUE2": """aaa\bbb"""}'; + expect(validator(input1)).toBeUndefined(); + + // Invalid JSON + // eslint-disable-next-line prettier/prettier + const input2 = '{"ISSUE": """"aaa\"bbb""'; + expect(validator(input2)).toMatchObject({ message, code }); + }); }); }); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.ts index a14944a33a8c..f6f7f2b105de 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/components/processor_form/processors/shared.ts @@ -10,9 +10,11 @@ import * as rt from 'io-ts'; import { i18n } from '@kbn/i18n'; import { isRight } from 'fp-ts/lib/Either'; +import { ERROR_CODE } from '@kbn/es-ui-shared-plugin/static/forms/helpers/field_validators/types'; import { FieldConfig, ValidationFunc, fieldValidators } from '../../../../../../shared_imports'; +import { collapseEscapedStrings } from '../../../utils'; -const { emptyField } = fieldValidators; +const { emptyField, isJsonField } = fieldValidators; export const arrayOfStrings = rt.array(rt.string); @@ -21,6 +23,35 @@ export function isArrayOfStrings(v: unknown): v is string[] { return isRight(res); } +/** + * Format a XJson string input as parsed JSON. Replaces the invalid characters + * with a placeholder, parses the new string in a JSON format with the expected + * indentantion and then replaces the placeholders with the original values. + */ +const formatXJsonString = (input: string) => { + let placeholder = 'PLACEHOLDER'; + const INVALID_STRING_REGEX = /"""(.*?)"""/gs; + while (input.includes(placeholder)) { + placeholder += '_'; + } + const modifiedInput = input.replace(INVALID_STRING_REGEX, () => `"${placeholder}"`); + + let jsonObject; + try { + jsonObject = JSON.parse(modifiedInput); + } catch (error) { + return input; + } + let formattedJsonString = JSON.stringify(jsonObject, null, 2); + const invalidStrings = input.match(INVALID_STRING_REGEX); + if (invalidStrings) { + invalidStrings.forEach((invalidString) => { + formattedJsonString = formattedJsonString.replace(`"${placeholder}"`, invalidString); + }); + } + return formattedJsonString; +}; + /** * Shared deserializer functions. * @@ -50,6 +81,15 @@ export const to = { } return v; }, + xJsonString: (v: unknown) => { + if (!v) { + return '{}'; + } + if (typeof v === 'string') { + return formatXJsonString(v); + } + return JSON.stringify(v, null, 2); + }, }; /** @@ -98,6 +138,12 @@ export const from = { } } }, + optionalXJson: (v: string) => { + if (v && v !== '{}') { + return v; + } + return undefined; + }, }; const isJSONString = (v: string) => { @@ -120,6 +166,16 @@ export const isJSONStringValidator: ValidationFunc = ({ value }) => { } }; +export const isXJsonField = + (message: string, { allowEmptyString = false }: { allowEmptyString?: boolean } = {}) => + (...args: Parameters<ValidationFunc>): ReturnType<ValidationFunc<any, ERROR_CODE>> => { + const [{ value, ...rest }] = args; + return isJsonField(message, { allowEmptyString })({ + ...rest, + value: collapseEscapedStrings(value as string), + }); + }; + /** * Similar to the emptyField validator but we accept whitespace characters. */ diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/serialize.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/serialize.ts index e0a8fb49d5d0..3edc4ad02d6a 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/serialize.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/serialize.ts @@ -8,6 +8,7 @@ import { Processor } from '../../../../common/types'; import { ProcessorInternal } from './types'; +import { convertProccesorsToJson } from './utils'; interface SerializeArgs { /** @@ -33,9 +34,10 @@ const convertProcessorInternalToProcessor = ( copyIdToTag?: boolean ): Processor => { const { options, onFailure, type, id } = processor; + const outProcessor = { [type]: { - ...options, + ...convertProccesorsToJson(options), }, }; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.test.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.test.ts index 6e367a83bf8d..8b75afd98578 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.test.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.test.ts @@ -5,7 +5,13 @@ * 2.0. */ -import { getValue, setValue, hasTemplateSnippet } from './utils'; +import { + getValue, + setValue, + hasTemplateSnippet, + collapseEscapedStrings, + convertProccesorsToJson, +} from './utils'; describe('get and set values', () => { const testObject = Object.freeze([{ onFailure: [{ onFailure: 1 }] }]); @@ -51,3 +57,42 @@ describe('template snippets', () => { expect(hasTemplateSnippet('{{{hello.world}}}')).toBe(true); }); }); + +describe('collapse escaped strings', () => { + it('returns escaped literal strings', () => { + expect(collapseEscapedStrings('{"1": """aaa\bbb""", "2": """ccc"""}')).toBe( + '{"1": "aaa\\bbb", "2": "ccc"}' + ); + }); +}); + +describe('convert processors to json', () => { + it('returns converted processors', () => { + const obj = { + field1: 'mustNotChange', + field2: 123, + field3: '{1: "mustNotChange"}', + pattern_definitions: '{"1": """aaa"bbb"""}', + processor: '{"1": """aaa"bbb"""}', + inference_config: '{"1": """aaa"bbb"""}', + field_map: '{"1": """aaa"bbb"""}', + customOptions: '{"customProcessor": """aaa"bbb"""}', + }; + + expect(convertProccesorsToJson(obj)).toEqual({ + field1: 'mustNotChange', + field2: 123, + field3: '{1: "mustNotChange"}', + // eslint-disable-next-line prettier/prettier + pattern_definitions: { 1: "aaa\"bbb" }, + // eslint-disable-next-line prettier/prettier + processor: { 1: "aaa\"bbb" }, + // eslint-disable-next-line prettier/prettier + inference_config: { 1: "aaa\"bbb" }, + // eslint-disable-next-line prettier/prettier + field_map: { 1: "aaa\"bbb" }, + // eslint-disable-next-line prettier/prettier + customProcessor: "aaa\"bbb" + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.ts index d7e6fc4a4d9a..533f9621bbec 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.ts +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_editor/utils.ts @@ -119,3 +119,54 @@ export const hasTemplateSnippet = (str: string = '') => { // * And followed by }}} return /{{{.+}}}/.test(str); }; + +const escapeLiteralStrings = (data: string): string[] => { + const splitData = data.split(`"""`); + for (let i = 1; i < splitData.length - 1; i += 2) { + splitData[i] = JSON.stringify(splitData[i]); + } + return splitData; +}; + +const convertProcessorValueToJson = (data: string): any => { + if (!data) { + return undefined; + } + + try { + const escapedData = escapeLiteralStrings(data); + return JSON.parse(escapedData.join('')); + } catch (error) { + return data; + } +}; + +export const collapseEscapedStrings = (data: string): string => { + if (data) { + return escapeLiteralStrings(data).join(''); + } + return data; +}; + +const fieldToConvertToJson = [ + 'inference_config', + 'field_map', + 'params', + 'pattern_definitions', + 'processor', +]; + +export const convertProccesorsToJson = (obj: { [key: string]: any }): { [key: string]: any } => { + return Object.fromEntries( + Object.entries(obj).flatMap(([key, value]) => { + if (key === 'customOptions') { + const convertedValue = convertProcessorValueToJson(value); + return Object.entries(convertedValue); + } else if (fieldToConvertToJson.includes(key)) { + return [[key, convertProcessorValueToJson(value)]]; + } else { + return [[key, value]]; + } + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/hooks/redirect_path.test.tsx b/x-pack/plugins/ingest_pipelines/public/application/hooks/redirect_path.test.tsx index a387661fc1b5..25729f5ba255 100644 --- a/x-pack/plugins/ingest_pipelines/public/application/hooks/redirect_path.test.tsx +++ b/x-pack/plugins/ingest_pipelines/public/application/hooks/redirect_path.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import { useRedirectPath } from './redirect_path'; import { useKibana } from '../../shared_imports'; diff --git a/x-pack/plugins/integration_assistant/__jest__/fixtures/ecs_mapping.ts b/x-pack/plugins/integration_assistant/__jest__/fixtures/ecs_mapping.ts index 67e6c7d8f6a5..8b905ccd64f9 100644 --- a/x-pack/plugins/integration_assistant/__jest__/fixtures/ecs_mapping.ts +++ b/x-pack/plugins/integration_assistant/__jest__/fixtures/ecs_mapping.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { EcsMappingState } from '../../server/types'; import { SamplesFormatName } from '../../common'; export const ecsMappingExpectedResults = { @@ -480,3 +481,383 @@ export const ecsTestState = { combinedSamples: '{"test1": "test1"}', additionalProcessors: [], }; + +export const ecsPipelineState: EcsMappingState = { + lastExecutedChain: 'validateMappings', + rawSamples: [], + additionalProcessors: [], + prefixedSamples: [ + '{"xdfsfs":{"ds":{"ei":0,"event":"cert.create","uid":"efd326fc-dd13-4df8-erre-3102c2d717d3","code":"TC000I","time":"2024-02-24T06:56:50.648137154Z","cluster_name":"teleport.ericbeahan.com","cert_type":"user","identity":{"user":"teleport-admin","roles":["access","editor"],"logins":["root","ubuntu","ec2-user","-teleport-internal-join"],"expires":"2024-02-24T06:56:50.648137154Z","route_to_cluster":"teleport.ericbeahan.com","traits":{"aws_role_arns":null,"azure_identities":null,"db_names":null,"db_roles":null,"db_users":null,"gcp_service_accounts":null,"host_user_gid":[""],"host_user_uid":[""],"kubernetes_groups":null,"kubernetes_users":null,"logins":["root","ubuntu","ec2-user"],"windows_logins":null},"teleport_cluster":"teleport.ericbeahan.com","client_ip":"1.2.3.4","prev_identity_expires":"0001-01-01T00:00:00Z","private_key_policy":"none"}}}}', + '{"xdfsfs":{"ds":{"ei":0,"event":"session.start","uid":"fff30583-13be-49e8-b159-32952c6ea34f","code":"T2000I","time":"2024-02-23T18:56:57.648137154Z","cluster_name":"teleport.ericbeahan.com","user":"teleport-admin","login":"ec2-user","user_kind":1,"sid":"293fda2d-2266-4d4d-b9d1-bd5ea9dd9fc3","private_key_policy":"none","namespace":"default","server_id":"face0091-2bf1-54er-a16a-f1514b4119f4","server_hostname":"ip-172-31-8-163.us-east-2.compute.internal","server_labels":{"hostname":"ip-172-31-8-163.us-east-2.compute.internal","teleport.internal/resource-id":"dccb2999-9fb8-4169-aded-ec7a1c0a26de"},"addr.remote":"1.2.3.4:50339","proto":"ssh","size":"80:25","initial_command":[""],"session_recording":"node"}}}', + ], + combinedSamples: + '{\n "xdfsfs": {\n "ds": {\n "identity": {\n "client_ip": "1.2.3.4",\n "prev_identity_expires": "0001-01-01T00:00:00Z",\n "private_key_policy": "none"\n },\n "user": "teleport-admin",\n "login": "ec2-user",\n "user_kind": 1,\n "sid": "293fda2d-2266-4d4d-b9d1-bd5ea9dd9fc3",\n "private_key_policy": "none",\n "namespace": "default",\n "server_id": "face0091-2bf1-43fd-a16a-f1514b4119f4",\n "server_hostname": "ip-172-31-8-163.us-east-2.compute.internal",\n "server_labels": {\n "hostname": "ip-172-31-8-163.us-east-2.compute.internal",\n "teleport.internal/resource-id": "dccb2999-9fb8-4169-aded-ec7a1c0a26de"\n },\n "addr.remote": "1.2.3.4:50339",\n "proto": "ssh",\n "size": "80:25",\n "initial_command": [\n ""\n ],\n "session_recording": "node"\n }\n }\n}', + sampleChunks: [], + exAnswer: + '{\n "crowdstrike": {\n "falcon": {\n "metadata": {\n "customerIDString": null,\n "offset": null,\n "eventType": {\n "target": "event.code",\n "confidence": 0.94,\n "type": "string",\n "date_formats": []\n },\n "eventCreationTime": {\n "target": "event.created",\n "confidence": 0.85,\n "type": "date",\n "date_formats": [\n "UNIX"\n ]\n },\n "version": null,\n "event": {\n "DeviceId": null,\n "CustomerId": null,\n "Ipv": {\n "target": "network.type",\n "confidence": 0.99,\n "type": "string",\n "date_formats": []\n }\n }\n }\n }\n }\n}', + packageName: 'xdfsfs', + dataStreamName: 'ds', + finalized: false, + currentMapping: { + xdfsfs: { + ds: { + identity: { + client_ip: { + target: 'client.ip', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + prev_identity_expires: { + target: 'event.end', + confidence: 0.7, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss'Z'"], + }, + private_key_policy: null, + }, + user: { + target: 'user.name', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + login: { + target: 'user.id', + confidence: 0.8, + type: 'string', + date_formats: [], + }, + user_kind: null, + sid: { + target: 'event.id', + confidence: 0.85, + type: 'string', + date_formats: [], + }, + private_key_policy: null, + namespace: null, + server_id: { + target: 'host.id', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + server_hostname: { + target: 'host.hostname', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + server_labels: { + hostname: null, + 'teleport.internal/resource-id': null, + }, + 'addr.remote': { + target: 'source.address', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + proto: { + target: 'network.protocol', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + size: null, + initial_command: null, + session_recording: null, + }, + }, + }, + chunkMapping: { + xdfsfs: { + ds: { + ei: null, + event: { + target: 'event.action', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + uid: { + target: 'event.id', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + code: { + target: 'event.code', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + time: { + target: 'event.created', + confidence: 0.95, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'"], + }, + cluster_name: { + target: 'cloud.account.name', + confidence: 0.8, + type: 'string', + date_formats: [], + }, + cert_type: null, + identity: { + user: { + target: 'user.name', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + roles: { + target: 'user.roles', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + logins: null, + expires: { + target: 'user.changes.name', + confidence: 0.7, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'"], + }, + route_to_cluster: null, + traits: { + aws_role_arns: null, + azure_identities: null, + db_names: null, + db_roles: null, + db_users: null, + gcp_service_accounts: null, + host_user_gid: null, + host_user_uid: null, + kubernetes_groups: null, + kubernetes_users: null, + logins: null, + windows_logins: null, + }, + teleport_cluster: null, + client_ip: { + target: 'client.ip', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + prev_identity_expires: { + target: 'event.end', + confidence: 0.7, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss'Z'"], + }, + private_key_policy: null, + }, + user: { + target: 'user.name', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + login: { + target: 'user.id', + confidence: 0.8, + type: 'string', + date_formats: [], + }, + user_kind: null, + sid: { + target: 'event.id', + confidence: 0.85, + type: 'string', + date_formats: [], + }, + private_key_policy: null, + namespace: null, + server_id: { + target: 'host.id', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + server_hostname: { + target: 'host.hostname', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + server_labels: { + hostname: null, + 'teleport.internal/resource-id': null, + }, + 'addr.remote': { + target: 'source.address', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + proto: { + target: 'network.protocol', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + size: null, + initial_command: null, + session_recording: null, + }, + }, + }, + finalMapping: { + xdfsfs: { + ds: { + ei: null, + event: { + target: 'event.action', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + uid: { + target: 'event.id', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + code: { + target: 'event.code', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + '@timestamp': { + target: '@timestamp', + confidence: 0.95, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'"], + }, + cluster_name: { + target: 'cloud.account.name', + confidence: 0.8, + type: 'string', + date_formats: [], + }, + cert_type: null, + identity: { + user: { + target: 'user.name', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + roles: { + target: 'user.roles', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + logins: null, + expires: { + target: 'user.changes.name', + confidence: 0.7, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'"], + }, + route_to_cluster: null, + traits: { + aws_role_arns: null, + azure_identities: null, + db_names: null, + db_roles: null, + db_users: null, + gcp_service_accounts: null, + host_user_gid: null, + host_user_uid: null, + kubernetes_groups: null, + kubernetes_users: null, + logins: null, + windows_logins: null, + }, + teleport_cluster: null, + client_ip: { + target: 'client.ip', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + prev_identity_expires: { + target: 'event.end', + confidence: 0.7, + type: 'date', + date_formats: ["yyyy-MM-dd'T'HH:mm:ss'Z'"], + }, + private_key_policy: null, + }, + user: { + target: 'user.name', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + login: { + target: 'user.id', + confidence: 0.8, + type: 'string', + date_formats: [], + }, + user_kind: null, + sid: null, + private_key_policy: null, + namespace: null, + server_id: { + target: 'host.id', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + server_hostname: { + target: 'host.hostname', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + server_labels: { + hostname: null, + 'teleport.internal/resource-id': null, + }, + 'addr.remote': { + target: 'source.address', + confidence: 0.9, + type: 'string', + date_formats: [], + }, + proto: { + target: 'network.protocol', + confidence: 0.95, + type: 'string', + date_formats: [], + }, + size: null, + initial_command: null, + session_recording: null, + }, + }, + }, + useFinalMapping: true, + hasTriedOnce: true, + currentPipeline: {}, + duplicateFields: [], + missingKeys: [], + invalidEcsFields: [], + results: {}, + samplesFormat: { + name: 'json', + json_path: [], + }, + ecsVersion: '8.11.0', + ecs: '', + chunkSize: 0, +}; diff --git a/x-pack/plugins/integration_assistant/common/api/generation_error.test.ts b/x-pack/plugins/integration_assistant/common/api/generation_error.test.ts new file mode 100644 index 000000000000..b18414610664 --- /dev/null +++ b/x-pack/plugins/integration_assistant/common/api/generation_error.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { GenerationErrorCode } from '../constants'; +import { isGenerationErrorBody } from './generation_error'; +import type { GenerationErrorBody } from './generation_error'; + +describe('isGenerationErrorBody', () => { + it('should return true for a valid GenerationErrorBody object', () => { + const validErrorBody: GenerationErrorBody = { + message: 'An error occurred', + attributes: { + errorCode: GenerationErrorCode.CEF_ERROR, + underlyingMessages: ['Error message 1', 'Error message 2'], + }, + }; + + expect(isGenerationErrorBody(validErrorBody)).toBe(true); + }); + + it('should return false for an object without a message', () => { + const invalidErrorBody = { + attributes: { + errorCode: 'ERROR_CODE', + underlyingMessages: ['Error message 1', 'Error message 2'], + }, + }; + + expect(isGenerationErrorBody(invalidErrorBody)).toBe(false); + }); + + it('should return false for an object without attributes', () => { + const invalidErrorBody = { + message: 'An error occurred', + }; + + expect(isGenerationErrorBody(invalidErrorBody)).toBe(false); + }); + + it('should return false for an object with invalid attributes', () => { + const invalidErrorBody = { + message: 'An error occurred', + attributes: { + errorCode: 123, // errorCode should be a string + underlyingMessages: 'Error message', // underlyingMessages should be an array + }, + }; + + expect(isGenerationErrorBody(invalidErrorBody)).toBe(false); + }); + + it('should return false for a non-object value', () => { + expect(isGenerationErrorBody(null)).toBe(false); + expect(isGenerationErrorBody(undefined)).toBe(false); + expect(isGenerationErrorBody('string')).toBe(false); + expect(isGenerationErrorBody(123)).toBe(false); + expect(isGenerationErrorBody(true)).toBe(false); + }); +}); diff --git a/x-pack/plugins/integration_assistant/common/api/generation_error.ts b/x-pack/plugins/integration_assistant/common/api/generation_error.ts index e96ad8bff9b5..03f01e96bee5 100644 --- a/x-pack/plugins/integration_assistant/common/api/generation_error.ts +++ b/x-pack/plugins/integration_assistant/common/api/generation_error.ts @@ -13,6 +13,12 @@ export interface GenerationErrorBody { attributes: GenerationErrorAttributes; } +export interface ErrorMessageWithLink { + link: string; + linkText: string; + errorMessage: string; +} + export function isGenerationErrorBody(obj: unknown | undefined): obj is GenerationErrorBody { return ( typeof obj === 'object' && @@ -27,7 +33,8 @@ export function isGenerationErrorBody(obj: unknown | undefined): obj is Generati export interface GenerationErrorAttributes { errorCode: GenerationErrorCode; - underlyingMessages: string[] | undefined; + underlyingMessages?: string[] | undefined; + errorMessageWithLink?: ErrorMessageWithLink | undefined; } export function isGenerationErrorAttributes(obj: unknown): obj is GenerationErrorAttributes { diff --git a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts index 803f9b8a6c3a..3b8dac7af22c 100644 --- a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts +++ b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.gen.ts @@ -84,6 +84,7 @@ export const SamplesFormatName = z.enum([ 'structured', 'unstructured', 'unsupported', + 'cef', ]); export type SamplesFormatNameEnum = typeof SamplesFormatName.enum; export const SamplesFormatNameEnum = SamplesFormatName.enum; diff --git a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml index 900b6e362a75..23ad137d8d83 100644 --- a/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml +++ b/x-pack/plugins/integration_assistant/common/api/model/common_attributes.schema.yaml @@ -64,6 +64,7 @@ components: - structured - unstructured - unsupported + - cef SamplesFormat: type: object diff --git a/x-pack/plugins/integration_assistant/common/constants.ts b/x-pack/plugins/integration_assistant/common/constants.ts index 4d791341e34f..3026101ebf54 100644 --- a/x-pack/plugins/integration_assistant/common/constants.ts +++ b/x-pack/plugins/integration_assistant/common/constants.ts @@ -35,6 +35,7 @@ export enum GenerationErrorCode { RECURSION_LIMIT_ANALYZE_LOGS = 'recursion-limit-analyze-logs', UNSUPPORTED_LOG_SAMPLES_FORMAT = 'unsupported-log-samples-format', UNPARSEABLE_CSV_DATA = 'unparseable-csv-data', + CEF_ERROR = 'cef-not-supported', } // Size limits diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.test.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.test.tsx new file mode 100644 index 000000000000..105bacf45e92 --- /dev/null +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.test.tsx @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import { ErrorMessage, isErrorMessageWithLink, MessageLink } from './error_with_link'; + +describe('isErrorMessageWithLink', () => { + it('should return true when error is an ErrorMessageWithLink', () => { + const error = { + link: 'http://example.com', + errorMessage: 'An error occurred', + linkText: 'decode_cef', + }; + expect(isErrorMessageWithLink(error)).toBe(true); + }); + + it('should return false when error is a string', () => { + const error = 'An error occurred'; + expect(isErrorMessageWithLink(error)).toBe(false); + }); + + describe('MessageLink', () => { + it('should render link with correct href and text', () => { + const { getByText } = render(<MessageLink link="http://example.com" linkText="decode_cef" />); + const linkElement = getByText('decode_cef'); + expect(linkElement).toBeInTheDocument(); + expect(linkElement).toHaveAttribute('href', 'http://example.com'); + }); + }); + + describe('ErrorMessage', () => { + it('should render error message when error is a string', () => { + const error = 'An error occurred'; + const { getByText } = render(<ErrorMessage error={error} />); + expect(getByText('An error occurred')).toBeInTheDocument(); + }); + }); +}); diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.tsx new file mode 100644 index 000000000000..8791e9f03a0f --- /dev/null +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/error_with_link.tsx @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiLink } from '@elastic/eui'; +import type { ErrorMessageWithLink } from '../../../../../../common/api/generation_error'; + +interface ErrorMessageProps { + error: string | null | ErrorMessageWithLink; +} + +interface MessageLinkProps { + link: string; + linkText: string; +} + +export const isErrorMessageWithLink = ( + error: string | ErrorMessageWithLink | null +): error is ErrorMessageWithLink => { + return ( + (error as ErrorMessageWithLink).link !== undefined && + (error as ErrorMessageWithLink).linkText !== undefined && + (error as ErrorMessageWithLink).errorMessage !== undefined + ); +}; + +export const MessageLink = React.memo<MessageLinkProps>(({ link, linkText }) => { + return ( + <EuiLink href={link} target="_blank"> + {linkText} + </EuiLink> + ); +}); +MessageLink.displayName = 'MessageLink'; + +export const ErrorMessage = React.memo<ErrorMessageProps>(({ error }) => { + return ( + <> + {isErrorMessageWithLink(error) ? ( + <FormattedMessage + id="xpack.integrationAssistant.createIntegration.generateErrorWithLink" + defaultMessage="{errorMessage} {link}" + values={{ + errorMessage: error.errorMessage, + link: <MessageLink link={error.link} linkText={error.linkText} />, + }} + /> + ) : typeof error === 'string' ? ( + <>{error}</> + ) : null} + </> + ); +}); +ErrorMessage.displayName = 'ErrorMessage'; diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx index ba57d83618c1..9d8d52a5b878 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/generation_modal.tsx @@ -28,6 +28,7 @@ import * as i18n from './translations'; import type { OnComplete, ProgressItem } from './use_generation'; import { ProgressOrder, useGeneration } from './use_generation'; +import { ErrorMessage } from './error_with_link'; const progressText: Record<ProgressItem, string> = { analyzeLogs: i18n.PROGRESS_ANALYZE_LOGS, @@ -87,7 +88,7 @@ export const GenerationModal = React.memo<GenerationModalProps>( iconType="alert" data-test-subj="generationErrorCallout" > - {error} + <ErrorMessage error={error} /> </EuiCallOut> </EuiFlexItem> ) : ( diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts index ec90568da0ef..8f2aab49622f 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/translations.ts @@ -188,6 +188,13 @@ export const RETRY = i18n.translate('xpack.integrationAssistant.step.dataStream. defaultMessage: 'Retry', }); +export const DECODE_CEF_LINK = i18n.translate( + 'xpack.integrationAssistant.errors.cefFormat.decodeLink', + { + defaultMessage: 'CEF format not supported yet. Instead please use CEF Integration:', + } +); + export const GENERATION_ERROR_TRANSLATION: Record< GenerationErrorCode, string | ((attributes: GenerationErrorAttributes) => string) @@ -211,6 +218,11 @@ export const GENERATION_ERROR_TRANSLATION: Record< defaultMessage: 'Unsupported log format in the samples.', } ), + [GenerationErrorCode.CEF_ERROR]: i18n.translate('xpack.integrationAssistant.errors.cefError', { + // This is a default error message if the linking does not work. + defaultMessage: + 'CEF format detected. Please decode the CEF logs into JSON format using filebeat decode_cef processor.', + }), [GenerationErrorCode.UNPARSEABLE_CSV_DATA]: (attributes) => { if ( attributes.underlyingMessages !== undefined && diff --git a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx index 566451d624c5..de6b2eed038e 100644 --- a/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx +++ b/x-pack/plugins/integration_assistant/public/components/create_integration/create_integration_assistant/steps/data_stream_step/use_generation.tsx @@ -28,6 +28,8 @@ import type { State } from '../../state'; import * as i18n from './translations'; import { useTelemetry } from '../../../telemetry'; import type { AIConnector, IntegrationSettings } from '../../types'; +import type { ErrorMessageWithLink } from '../../../../../../common/api/generation_error'; +import { GenerationErrorCode } from '../../../../../../common/constants'; export type OnComplete = (result: State['result']) => void; export const ProgressOrder = ['analyzeLogs', 'ecs', 'categorization', 'related'] as const; @@ -48,12 +50,23 @@ interface RunGenerationProps { // If the result is classified as a generation error, produce an error message // as defined in the i18n file. Otherwise, return undefined. -function generationErrorMessage(body: unknown | undefined): string | undefined { +function generationErrorMessage( + body: unknown | undefined +): string | ErrorMessageWithLink | undefined { if (!isGenerationErrorBody(body)) { return; } const errorCode = body.attributes.errorCode; + if (errorCode === GenerationErrorCode.CEF_ERROR) { + if (body.attributes.errorMessageWithLink !== undefined) { + return { + link: body.attributes.errorMessageWithLink.link, + errorMessage: i18n.DECODE_CEF_LINK, + linkText: body.attributes.errorMessageWithLink.linkText, + }; + } + } const translation = i18n.GENERATION_ERROR_TRANSLATION[errorCode]; return typeof translation === 'function' ? translation(body.attributes) : translation; } @@ -72,7 +85,7 @@ export const useGeneration = ({ const { reportGenerationComplete } = useTelemetry(); const { http, notifications } = useKibana().services; const [progress, setProgress] = useState<ProgressItem>(); - const [error, setError] = useState<null | string>(null); + const [error, setError] = useState<null | string | ErrorMessageWithLink>(null); const [isRequesting, setIsRequesting] = useState<boolean>(true); useEffect(() => { diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.test.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.test.ts new file mode 100644 index 000000000000..3dda9208c309 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.test.ts @@ -0,0 +1,306 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ecsPipelineState } from '../../../__jest__/fixtures/ecs_mapping'; +import type { EcsMappingState } from '../../types'; +import { createPipeline } from './pipeline'; + +const state: EcsMappingState = ecsPipelineState; + +describe('Testing pipeline templates', () => { + it('handle pipeline creation', async () => { + const pipeline = createPipeline(state); + expect(pipeline.processors).toEqual([ + { + set: { field: 'ecs.version', tag: 'set_ecs_version', value: '8.11.0' }, + }, + { + set: { + field: 'originalMessage', + copy_from: 'message', + tag: 'copy_original_message', + }, + }, + { + rename: { + field: 'originalMessage', + target_field: 'event.original', + tag: 'rename_message', + ignore_missing: true, + if: 'ctx.event?.original == null', + }, + }, + { + remove: { + field: 'originalMessage', + ignore_missing: true, + tag: 'remove_copied_message', + if: 'ctx.event?.original != null', + }, + }, + { + remove: { field: 'message', ignore_missing: true, tag: 'remove_message' }, + }, + { + json: { + field: 'event.original', + tag: 'json_original', + target_field: 'xdfsfs.ds', + }, + }, + { + rename: { + field: 'xdfsfs.ds.event', + target_field: 'event.action', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.uid', + target_field: 'event.id', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.code', + target_field: 'event.code', + ignore_missing: true, + }, + }, + { + date: { + field: 'xdfsfs.ds.@timestamp', + target_field: '@timestamp', + formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'", 'ISO8601'], + tag: 'date_processor_xdfsfs.ds.@timestamp', + if: 'ctx.xdfsfs?.ds?.@timestamp != null', + }, + }, + { + rename: { + field: 'xdfsfs.ds.cluster_name', + target_field: 'cloud.account.name', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.identity.user', + target_field: 'user.name', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.identity.roles', + target_field: 'user.roles', + ignore_missing: true, + }, + }, + { + script: { + description: 'Ensures the date processor does not receive an array value.', + tag: 'script_convert_array_to_string', + lang: 'painless', + source: + 'if (ctx.xdfsfs?.ds?.identity?.expires != null &&\n' + + ' ctx.xdfsfs.ds.identity.expires instanceof ArrayList){\n' + + ' ctx.xdfsfs.ds.identity.expires = ctx.xdfsfs.ds.identity.expires[0];\n' + + '}\n', + }, + }, + { + date: { + field: 'xdfsfs.ds.identity.expires', + target_field: 'user.changes.name', + formats: ["yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z'", 'ISO8601'], + tag: 'date_processor_xdfsfs.ds.identity.expires', + if: 'ctx.xdfsfs?.ds?.identity?.expires != null', + }, + }, + { + convert: { + field: 'xdfsfs.ds.identity.client_ip', + target_field: 'client.ip', + ignore_missing: true, + ignore_failure: true, + type: 'ip', + }, + }, + { + script: { + description: 'Ensures the date processor does not receive an array value.', + tag: 'script_convert_array_to_string', + lang: 'painless', + source: + 'if (ctx.xdfsfs?.ds?.identity?.prev_identity_expires != null &&\n' + + ' ctx.xdfsfs.ds.identity.prev_identity_expires instanceof ArrayList){\n' + + ' ctx.xdfsfs.ds.identity.prev_identity_expires = ctx.xdfsfs.ds.identity.prev_identity_expires[0];\n' + + '}\n', + }, + }, + { + date: { + field: 'xdfsfs.ds.identity.prev_identity_expires', + target_field: 'event.end', + formats: ["yyyy-MM-dd'T'HH:mm:ss'Z'", 'ISO8601'], + tag: 'date_processor_xdfsfs.ds.identity.prev_identity_expires', + if: 'ctx.xdfsfs?.ds?.identity?.prev_identity_expires != null', + }, + }, + { + rename: { + field: 'xdfsfs.ds.user', + target_field: 'user.name', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.login', + target_field: 'user.id', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.server_id', + target_field: 'host.id', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.server_hostname', + target_field: 'host.hostname', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.addr.remote', + target_field: 'source.address', + ignore_missing: true, + }, + }, + { + rename: { + field: 'xdfsfs.ds.proto', + target_field: 'network.protocol', + ignore_missing: true, + }, + }, + { + script: { + description: 'Drops null/empty values recursively.', + tag: 'script_drop_null_empty_values', + lang: 'painless', + source: + 'boolean dropEmptyFields(Object object) {\n' + + ' if (object == null || object == "") {\n' + + ' return true;\n' + + ' } else if (object instanceof Map) {\n' + + ' ((Map) object).values().removeIf(value -> dropEmptyFields(value));\n' + + ' return (((Map) object).size() == 0);\n' + + ' } else if (object instanceof List) {\n' + + ' ((List) object).removeIf(value -> dropEmptyFields(value));\n' + + ' return (((List) object).length == 0);\n' + + ' }\n' + + ' return false;\n' + + '}\n' + + 'dropEmptyFields(ctx);\n', + }, + }, + { + geoip: { + field: 'source.ip', + tag: 'geoip_source_ip', + target_field: 'source.geo', + ignore_missing: true, + }, + }, + { + geoip: { + ignore_missing: true, + database_file: 'GeoLite2-ASN.mmdb', + field: 'source.ip', + tag: 'geoip_source_asn', + target_field: 'source.as', + properties: ['asn', 'organization_name'], + }, + }, + { + rename: { + field: 'source.as.asn', + tag: 'rename_source_as_asn', + target_field: 'source.as.number', + ignore_missing: true, + }, + }, + { + rename: { + field: 'source.as.organization_name', + tag: 'rename_source_as_organization_name', + target_field: 'source.as.organization.name', + ignore_missing: true, + }, + }, + { + geoip: { + field: 'destination.ip', + tag: 'geoip_destination_ip', + target_field: 'destination.geo', + ignore_missing: true, + }, + }, + { + geoip: { + database_file: 'GeoLite2-ASN.mmdb', + field: 'destination.ip', + tag: 'geoip_destination_asn', + target_field: 'destination.as', + properties: ['asn', 'organization_name'], + ignore_missing: true, + }, + }, + { + rename: { + field: 'destination.as.asn', + tag: 'rename_destination_as_asn', + target_field: 'destination.as.number', + ignore_missing: true, + }, + }, + { + rename: { + field: 'destination.as.organization_name', + tag: 'rename_destination_as_organization_name', + target_field: 'destination.as.organization.name', + ignore_missing: true, + }, + }, + { + remove: { + field: ['xdfsfs.ds.identity.client_ip'], + ignore_missing: true, + tag: 'remove_fields', + }, + }, + { + remove: { + field: 'event.original', + tag: 'remove_original_event', + if: 'ctx?.tags == null || !(ctx.tags.contains("preserve_original_event"))', + ignore_failure: true, + ignore_missing: true, + }, + }, + ]); + }); +}); diff --git a/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.ts b/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.ts index b5a6e23000d3..dda48c97bdf9 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/ecs/pipeline.ts @@ -186,6 +186,9 @@ export function createPipeline(state: EcsMappingState): IngestPipeline { const env = new Environment(new FileSystemLoader(templatesPath), { autoescape: false, }); + env.addFilter('includes', function (str, substr) { + return str.includes(substr); + }); env.addFilter('startswith', function (str, prefix) { return str.startsWith(prefix); }); diff --git a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts index b6e777a87888..09a7249a3786 100644 --- a/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts +++ b/x-pack/plugins/integration_assistant/server/graphs/log_type_detection/prompts.ts @@ -23,6 +23,7 @@ Follow these steps to do this: b. If there is no csv header then set "header: false" and try to find good names for the columns in the "columns" array by looking into the values of data in those columns. For each column, if you are unable to find good name candidate for it then output an empty string, like in the example. * 'structured': If the log samples have structured message body with key-value pairs then classify it as "name: structured". Look for a flat list of key-value pairs, often separated by some delimiters. Consider variations in formatting, such as quotes around values ("key=value", key="value"), special characters in keys or values, or escape sequences. * 'unstructured': If the log samples have unstructured body like a free-form text then classify it as "name: unstructured". + * 'cef': If the log samples have Common Event Format (CEF) then classify it as "name: cef". * 'unsupported': If you cannot put the format into any of the above categories then classify it with "name: unsupported". 2. Header: for structured and unstructured format: - if the samples have any or all of priority, timestamp, loglevel, hostname, ipAddress, messageId in the beginning information then set "header: true". diff --git a/x-pack/plugins/integration_assistant/server/lib/errors/cef_error.ts b/x-pack/plugins/integration_assistant/server/lib/errors/cef_error.ts new file mode 100644 index 000000000000..16889b30c1a1 --- /dev/null +++ b/x-pack/plugins/integration_assistant/server/lib/errors/cef_error.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaResponseFactory } from '@kbn/core/server'; +import { + GenerationErrorAttributes, + GenerationErrorBody, +} from '../../../common/api/generation_error'; +import { ErrorThatHandlesItsOwnResponse } from './types'; +import { GenerationErrorCode } from '../../../common/constants'; + +export class CefError extends Error implements ErrorThatHandlesItsOwnResponse { + private readonly errorCode: GenerationErrorCode = GenerationErrorCode.CEF_ERROR; + attributes: GenerationErrorAttributes; + + constructor(message: string) { + super(message); + this.attributes = { + errorCode: this.errorCode, + errorMessageWithLink: { + linkText: 'cef-integration', + link: 'https://www.elastic.co/docs/current/integrations/cef', + errorMessage: '', // Will be set using translation in the UI. + }, + }; + } + + public sendResponse(res: KibanaResponseFactory) { + const body: GenerationErrorBody = { + message: this.errorCode, + attributes: this.attributes, + }; + return res.customError({ + statusCode: 501, + body, + }); + } +} diff --git a/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts b/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts index 34f05fcc8202..37926dac1915 100644 --- a/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts +++ b/x-pack/plugins/integration_assistant/server/routes/analyze_logs_routes.ts @@ -19,6 +19,7 @@ import { withAvailability } from './with_availability'; import { isErrorThatHandlesItsOwnResponse, UnsupportedLogFormatError } from '../lib/errors'; import { handleCustomErrors } from './routes_util'; import { GenerationErrorCode } from '../../common/constants'; +import { CefError } from '../lib/errors/cef_error'; export function registerAnalyzeLogsRoutes( router: IRouter<IntegrationAssistantRouteHandlerContext> @@ -102,9 +103,16 @@ export function registerAnalyzeLogsRoutes( .withConfig({ runName: 'Log Format' }) .invoke(logFormatParameters, options); const graphLogFormat = graphResults.results.samplesFormat.name; - if (graphLogFormat === 'unsupported') { - throw new UnsupportedLogFormatError(GenerationErrorCode.UNSUPPORTED_LOG_SAMPLES_FORMAT); + + switch (graphLogFormat) { + case 'unsupported': + throw new UnsupportedLogFormatError( + GenerationErrorCode.UNSUPPORTED_LOG_SAMPLES_FORMAT + ); + case 'cef': + throw new CefError(GenerationErrorCode.CEF_ERROR); } + return res.ok({ body: AnalyzeLogsResponse.parse(graphResults) }); } catch (err) { try { diff --git a/x-pack/plugins/integration_assistant/server/templates/manifest/http_endpoint_manifest.yml.njk b/x-pack/plugins/integration_assistant/server/templates/manifest/http_endpoint_manifest.yml.njk index b62a582a1cfc..b35471ad4a63 100644 --- a/x-pack/plugins/integration_assistant/server/templates/manifest/http_endpoint_manifest.yml.njk +++ b/x-pack/plugins/integration_assistant/server/templates/manifest/http_endpoint_manifest.yml.njk @@ -42,12 +42,6 @@ The Ingest Node pipeline ID to be used by the integration. required: false show_user: true - - name: preserve_original_event - type: bool - title: Preserve Original Event - description: This option copies the raw unmodified body of the incoming request to the event.original field as a string before sending the event to Elasticsearch. - required: false - show_user: true - name: prefix type: text title: Prefix diff --git a/x-pack/plugins/integration_assistant/server/templates/pipeline.yml.njk b/x-pack/plugins/integration_assistant/server/templates/pipeline.yml.njk index ba846dc50fba..116d5cc66719 100644 --- a/x-pack/plugins/integration_assistant/server/templates/pipeline.yml.njk +++ b/x-pack/plugins/integration_assistant/server/templates/pipeline.yml.njk @@ -35,6 +35,7 @@ processors: target_field: {% if value.target_field | startswith('@') %}"{{ value.target_field }}"{% else %}{{ value.target_field }}{% endif %} ignore_missing: true{% endif %} {% if key == 'date' %} + {% if not value.field | includes('.@') %} {# Leaving fields of type 'test.log.@timestamp' #} - script: description: Ensures the date processor does not receive an array value. tag: script_convert_array_to_string @@ -43,7 +44,7 @@ processors: if (ctx.{% endraw %}{{ value.field.replaceAll('.', '?.') }}{% raw %} != null && ctx.{% endraw %}{{ value.field }}{% raw %} instanceof ArrayList){ ctx.{% endraw %}{{ value.field }}{% raw %} = ctx.{% endraw %}{{ value.field }}{% raw %}[0]; - }{% endraw %} + }{% endraw %}{% endif %} - {{ key }}: field: {{ value.field }} target_field: {% if value.target_field | startswith('@') %}"{{ value.target_field }}"{% else %}{{ value.target_field }}{% endif %} diff --git a/x-pack/plugins/lens/common/constants.ts b/x-pack/plugins/lens/common/constants.ts index 955d260abe8a..b8154c4bc543 100644 --- a/x-pack/plugins/lens/common/constants.ts +++ b/x-pack/plugins/lens/common/constants.ts @@ -10,13 +10,17 @@ import type { RefreshInterval, TimeRange } from '@kbn/data-plugin/common/query'; import type { Filter } from '@kbn/es-query'; export const PLUGIN_ID = 'lens'; -export const APP_ID = 'lens'; -export const LENS_APP_NAME = 'lens'; -export const LENS_EMBEDDABLE_TYPE = 'lens'; +export const APP_ID = PLUGIN_ID; export const DOC_TYPE = 'lens'; +export const LENS_APP_NAME = APP_ID; +export const LENS_EMBEDDABLE_TYPE = DOC_TYPE; export const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations'; export const BASE_API_URL = '/api/lens'; export const LENS_EDIT_BY_VALUE = 'edit_by_value'; +export const LENS_ICON = 'lensApp'; +export const STAGE_ID = 'production'; + +export const INDEX_PATTERN_TYPE = 'index-pattern'; export const PieChartTypes = { PIE: 'pie', diff --git a/x-pack/plugins/lens/common/embeddable_factory/index.ts b/x-pack/plugins/lens/common/embeddable_factory/index.ts index 68e6c77e9dae..62cd68e15e9d 100644 --- a/x-pack/plugins/lens/common/embeddable_factory/index.ts +++ b/x-pack/plugins/lens/common/embeddable_factory/index.ts @@ -6,47 +6,52 @@ */ import { cloneDeep } from 'lodash'; -import type { SerializableRecord, Serializable } from '@kbn/utility-types'; +import type { SerializableRecord } from '@kbn/utility-types'; import type { SavedObjectReference } from '@kbn/core/types'; -import type { - EmbeddableStateWithType, +import { EmbeddableRegistryDefinition, + EmbeddableStateWithType, } from '@kbn/embeddable-plugin/common'; +import type { LensRuntimeState } from '../../public'; export type LensEmbeddablePersistableState = EmbeddableStateWithType & { attributes: SerializableRecord; }; -export const inject: EmbeddableRegistryDefinition['inject'] = (state, references) => { - // We need to clone the state because we can not modify the original state object. - const typedState = cloneDeep(state) as LensEmbeddablePersistableState; +export const inject: NonNullable<EmbeddableRegistryDefinition['inject']> = ( + state, + references +): EmbeddableStateWithType => { + const typedState = cloneDeep(state) as unknown as LensRuntimeState; - if ('attributes' in typedState && typedState.attributes !== undefined) { - // match references based on name, so only references associated with this lens panel are injected. - const matchedReferences: SavedObjectReference[] = []; - - if (Array.isArray(typedState.attributes.references)) { - typedState.attributes.references.forEach((serializableRef) => { - const internalReference = serializableRef as unknown as SavedObjectReference; - const matchedReference = references.find( - (reference) => reference.name === internalReference.name - ); - if (matchedReference) matchedReferences.push(matchedReference); - }); - } - - typedState.attributes.references = matchedReferences as unknown as Serializable[]; + if (typedState.savedObjectId) { + return typedState as unknown as EmbeddableStateWithType; } - return typedState; + // match references based on name, so only references associated with this lens panel are injected. + const matchedReferences: SavedObjectReference[] = []; + + if (Array.isArray(typedState.attributes.references)) { + typedState.attributes.references.forEach((serializableRef) => { + const internalReference = serializableRef; + const matchedReference = references.find( + (reference) => reference.name === internalReference.name + ); + if (matchedReference) matchedReferences.push(matchedReference); + }); + } + + typedState.attributes.references = matchedReferences; + + return typedState as unknown as EmbeddableStateWithType; }; -export const extract: EmbeddableRegistryDefinition['extract'] = (state) => { +export const extract: NonNullable<EmbeddableRegistryDefinition['extract']> = (state) => { let references: SavedObjectReference[] = []; - const typedState = state as LensEmbeddablePersistableState; + const typedState = state as unknown as LensRuntimeState; if ('attributes' in typedState && typedState.attributes !== undefined) { - references = typedState.attributes.references as unknown as SavedObjectReference[]; + references = typedState.attributes.references; } return { state, references }; diff --git a/x-pack/plugins/lens/common/locator/locator.ts b/x-pack/plugins/lens/common/locator/locator.ts index ea0e54136ffc..7b0b12416f14 100644 --- a/x-pack/plugins/lens/common/locator/locator.ts +++ b/x-pack/plugins/lens/common/locator/locator.ts @@ -9,7 +9,7 @@ import rison from '@kbn/rison'; import type { SerializableRecord } from '@kbn/utility-types'; import type { GlobalQueryStateFromUrl } from '@kbn/data-plugin/public'; import type { LocatorDefinition, LocatorPublic } from '@kbn/share-plugin/common'; -import type { Filter, Query } from '@kbn/es-query'; +import type { AggregateQuery, Filter, Query } from '@kbn/es-query'; import type { DataViewSpec, SavedQuery } from '@kbn/data-plugin/common'; import { SavedObjectReference } from '@kbn/core-saved-objects-common'; import type { DateRange } from '../types'; @@ -26,7 +26,7 @@ interface LensShareableState { /** * Optionally set a query. */ - query?: Query; + query?: Query | AggregateQuery; /** * Optionally set the date range in the date picker. @@ -88,7 +88,7 @@ export interface LensAppLocatorParams extends SerializableRecord { /** * Optionally set a query. */ - query?: Query; + query?: Query | AggregateQuery; /** * Optionally set the date range in the date picker. diff --git a/x-pack/plugins/lens/kibana.jsonc b/x-pack/plugins/lens/kibana.jsonc index 4b0b14141474..012a077abb12 100644 --- a/x-pack/plugins/lens/kibana.jsonc +++ b/x-pack/plugins/lens/kibana.jsonc @@ -45,6 +45,7 @@ "expressionLegacyMetricVis", "expressionPartitionVis", "usageCollection", + "embeddableEnhanced", "taskManager", "globalSearch", "savedObjectsTagging", diff --git a/x-pack/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/plugins/lens/public/app_plugin/app.test.tsx index 8aebc4778e20..73fb52bbe668 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.test.tsx @@ -5,23 +5,20 @@ * 2.0. */ -import React, { PropsWithChildren } from 'react'; +import React from 'react'; import { Observable, Subject } from 'rxjs'; -import { ReactWrapper } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { App } from './app'; import { LensAppProps, LensAppServices } from './types'; -import { EditorFrameInstance, EditorFrameProps } from '../types'; -import { Document, SavedObjectIndexStore } from '../persistence'; +import { LensDocument, SavedObjectIndexStore } from '../persistence'; import { visualizationMap, datasourceMap, makeDefaultServices, - mountWithProvider, + renderWithReduxStore, mockStoreDeps, + defaultDoc, } from '../mocks'; -import { I18nProvider } from '@kbn/i18n-react'; -import { SavedObjectSaveModal } from '@kbn/saved-objects-plugin/public'; import { checkForDuplicateTitle } from '../persistence'; import { createMemoryHistory } from 'history'; import type { Query } from '@kbn/es-query'; @@ -29,55 +26,52 @@ import { FilterManager } from '@kbn/data-plugin/public'; import type { DataView } from '@kbn/data-views-plugin/public'; import { buildExistsFilter, FilterStateStore } from '@kbn/es-query'; import type { FieldSpec } from '@kbn/data-plugin/common'; -import { TopNavMenuData } from '@kbn/navigation-plugin/public'; -import { LensByValueInput } from '../embeddable/embeddable'; -import { SavedObjectReference } from '@kbn/core/types'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { serverlessMock } from '@kbn/serverless/public/mocks'; +import { cloneDeep } from 'lodash'; import moment from 'moment'; - import { setState, LensAppState } from '../state_management'; import { coreMock } from '@kbn/core/public/mocks'; -jest.mock('../editor_frame_service/editor_frame/expression_helpers'); -jest.mock('@kbn/core/public'); +import { LensSerializedState } from '..'; +import { createMockedField, createMockedIndexPattern } from '../datasources/form_based/mocks'; +import faker from 'faker'; +import { screen, waitFor } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { VisualizeEditorContext } from '../types'; +import { setMockedPresentationUtilServices } from '@kbn/presentation-util-plugin/public/mocks'; + jest.mock('../persistence/saved_objects_utils/check_for_duplicate_title', () => ({ checkForDuplicateTitle: jest.fn(), })); +jest.mock('lodash', () => ({ + ...jest.requireActual('lodash'), + debounce: (fn: unknown) => fn, +})); -jest.mock('lodash', () => { - const original = jest.requireActual('lodash'); - - return { - ...original, - debounce: (fn: unknown) => fn, - }; -}); +const defaultSavedObjectId: string = faker.random.uuid(); -// const navigationStartMock = navigationPluginMock.createStartContract(); +const waitToLoad = async () => + await act(async () => new Promise((resolve) => setTimeout(resolve, 0))); -const sessionIdSubject = new Subject<string>(); +function getLensDocumentMock(propsOverrides?: Partial<LensDocument>) { + return cloneDeep({ ...defaultDoc, ...propsOverrides }); +} describe('Lens App', () => { - let defaultDoc: Document; - let defaultSavedObjectId: string; - - function createMockFrame(): jest.Mocked<EditorFrameInstance> { - return { - EditorFrameContainer: jest.fn((props: EditorFrameProps) => <div />), - datasourceMap, - visualizationMap, - }; - } - - const navMenuItems = { - expectedSaveButton: { emphasize: true, testId: 'lnsApp_saveButton' }, - expectedSaveAsButton: { emphasize: false, testId: 'lnsApp_saveButton' }, - expectedSaveAndReturnButton: { emphasize: true, testId: 'lnsApp_saveAndReturnButton' }, - }; + let props: jest.Mocked<LensAppProps>; + let services: jest.Mocked<LensAppServices> = makeDefaultServices( + new Subject<string>(), + 'sessionId-1' + ); + beforeAll(() => setMockedPresentationUtilServices()); - function makeDefaultProps(): jest.Mocked<LensAppProps> { - return { - editorFrame: createMockFrame(), + beforeEach(() => { + props = { + editorFrame: { + EditorFrameContainer: jest.fn((_) => <div>Editor frame</div>), + datasourceMap, + visualizationMap, + }, history: createMemoryHistory(), redirectTo: jest.fn(), redirectToOrigin: jest.fn(), @@ -94,93 +88,60 @@ describe('Lens App', () => { search: jest.fn(), } as unknown as SavedObjectIndexStore, }; - } - const makeDefaultServicesForApp = () => makeDefaultServices(sessionIdSubject, 'sessionId-1'); + services = makeDefaultServices(new Subject<string>(), 'sessionId-1'); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); - async function mountWith({ - props = makeDefaultProps(), - services = makeDefaultServicesForApp(), + async function renderApp({ preloadedState, }: { - props?: jest.Mocked<LensAppProps>; - services?: jest.Mocked<LensAppServices>; preloadedState?: Partial<LensAppState>; - }) { - const wrappingComponent: React.FC<PropsWithChildren<{}>> = ({ children }) => { - return ( - <I18nProvider> - <KibanaContextProvider services={services}>{children}</KibanaContextProvider> - </I18nProvider> - ); - }; - const storeDeps = mockStoreDeps({ lensServices: services }); - const { instance, lensStore } = await mountWithProvider( + } = {}) { + const Wrapper = ({ children }: { children: React.ReactNode }) => ( + <KibanaContextProvider services={services}>{children}</KibanaContextProvider> + ); + + const { + store, + render: renderRtl, + rerender, + ...rest + } = renderWithReduxStore( <App {...props} />, + { wrapper: Wrapper }, { - storeDeps, + storeDeps: mockStoreDeps({ lensServices: services }), preloadedState, - }, - { wrappingComponent } + } ); - const frame = props.editorFrame as ReturnType<typeof createMockFrame>; - lensStore.dispatch(setState({ ...preloadedState })); - return { instance, frame, props, services, lensStore }; - } + const rerenderWithProps = (newProps: Partial<LensAppProps>) => { + rerender(<App {...props} {...newProps} />, { + wrapper: Wrapper, + }); + }; - beforeEach(() => { - defaultSavedObjectId = '1234'; - defaultDoc = { - savedObjectId: defaultSavedObjectId, - visualizationType: 'testVis', - type: 'lens', - title: 'An extremely cool default document!', - expression: 'definitely a valid expression', - state: { - query: 'lucene', - filters: [{ query: { match_phrase: { src: 'test' } }, meta: { index: 'index-pattern-0' } }], - }, - references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - } as unknown as Document; - }); + await act(async () => await store.dispatch(setState({ ...preloadedState }))); + return { props, lensStore: store, rerender: rerenderWithProps, ...rest }; + } it('renders the editor frame', async () => { - const { frame } = await mountWith({}); - expect(frame.EditorFrameContainer).toHaveBeenLastCalledWith( - { - indexPatternService: expect.any(Object), - getUserMessages: expect.any(Function), - addUserMessages: expect.any(Function), - lensInspector: { - adapters: { - expression: expect.any(Object), - requests: expect.any(Object), - tables: expect.any(Object), - }, - close: expect.any(Function), - inspect: expect.any(Function), - }, - showNoDataPopover: expect.any(Function), - }, - {} - ); + await renderApp(); + expect(screen.getByText('Editor frame')).toBeInTheDocument(); }); it('updates global filters with store state', async () => { - const services = makeDefaultServicesForApp(); - const indexPattern = { id: 'index1', isPersisted: () => true } as unknown as DataView; - const pinnedField = { name: 'pinnedField' } as unknown as FieldSpec; + const pinnedField = createMockedField({ name: 'pinnedField', type: '' }); + const indexPattern = createMockedIndexPattern({ id: 'index1' }, [pinnedField]); const pinnedFilter = buildExistsFilter(pinnedField, indexPattern); - services.data.query.filterManager.getFilters = jest.fn().mockImplementation(() => { - return []; - }); - services.data.query.filterManager.getGlobalFilters = jest.fn().mockImplementation(() => { - return [pinnedFilter]; - }); - const { instance, lensStore } = await mountWith({ services }); + services.data.query.filterManager.getFilters = jest.fn().mockReturnValue([]); + services.data.query.filterManager.getGlobalFilters = jest.fn().mockReturnValue([pinnedFilter]); + const { lensStore } = await renderApp(); - instance.update(); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ query: { query: '', language: 'lucene' }, @@ -198,22 +159,19 @@ describe('Lens App', () => { describe('extra nav menu entries', () => { it('shows custom menu entry', async () => { const runFn = jest.fn(); - const { instance, services } = await mountWith({ - props: { - ...makeDefaultProps(), - topNavMenuEntryGenerators: [ - () => ({ - label: 'My entry', - run: runFn, - }), - ], - }, - }); - const navigationComponent = services.navigation.ui - .AggregateQueryTopNavMenu as unknown as React.ReactElement; - const extraEntry = instance.find(navigationComponent).prop('config')[0]; - expect(extraEntry.label).toEqual('My entry'); - expect(extraEntry.run).toBe(runFn); + props.topNavMenuEntryGenerators = [ + () => ({ + label: 'My entry', + run: runFn, + }), + ]; + await renderApp(); + expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( + expect.objectContaining({ + config: expect.arrayContaining([{ label: 'My entry', run: runFn }]), + }), + {} + ); }); it('passes current state, filter, query timerange and initial context into getter', async () => { @@ -244,15 +202,12 @@ describe('Lens App', () => { }, ], }; - await mountWith({ - props: { - ...makeDefaultProps(), - topNavMenuEntryGenerators: [getterFn], - initialContext: { - fieldName: 'a', - dataViewSpec: { id: '1' }, - }, - }, + props.topNavMenuEntryGenerators = [getterFn]; + props.initialContext = { + fieldName: 'a', + dataViewSpec: { id: '1' }, + }; + await renderApp({ preloadedState, }); @@ -278,19 +233,14 @@ describe('Lens App', () => { }); describe('breadcrumbs', () => { - const breadcrumbDocSavedObjectId = defaultSavedObjectId; - const breadcrumbDoc = { + const breadcrumbDocSavedObjectId = faker.random.uuid(); + const breadcrumbDoc = getLensDocumentMock({ savedObjectId: breadcrumbDocSavedObjectId, title: 'Daaaaaaadaumching!', - state: { - query: 'fake query', - filters: [], - }, - references: [], - } as unknown as Document; + }); it('sets breadcrumbs when the document title changes', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ { @@ -302,8 +252,7 @@ describe('Lens App', () => { ]); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); - lensStore.dispatch( + await lensStore.dispatch( setState({ persistedDoc: breadcrumbDoc, }) @@ -321,17 +270,10 @@ describe('Lens App', () => { }); it('sets originatingApp breadcrumb when the document title changes', async () => { - const props = makeDefaultProps(); - const services = makeDefaultServicesForApp(); - props.incomingState = { originatingApp: 'coolContainer' }; + props.incomingState = { originatingApp: 'dashboards' }; services.getOriginatingAppName = jest.fn(() => 'The Coolest Container Ever Made'); - - const { instance, lensStore } = await mountWith({ - props, - services, - preloadedState: { - isLinkedToOriginatingApp: false, - }, + const { lensStore, rerender } = await renderApp({ + preloadedState: { isLinkedToOriginatingApp: false }, }); expect(services.chrome.setBreadcrumbs).toHaveBeenCalledWith([ @@ -344,12 +286,7 @@ describe('Lens App', () => { ]); await act(async () => { - instance.setProps({ - initialInput: { savedObjectId: breadcrumbDocSavedObjectId }, - preloadedState: { - isLinkedToOriginatingApp: true, - }, - }); + await rerender({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); lensStore.dispatch( setState({ @@ -370,17 +307,13 @@ describe('Lens App', () => { it('sets serverless breadcrumbs when the document title changes when serverless service is available', async () => { const serverless = serverlessMock.createStart(); - const { instance, services, lensStore } = await mountWith({ - services: { - ...makeDefaultServices(), - serverless, - }, - }); + services.serverless = serverless; + const { lensStore, rerender } = await renderApp(); expect(services.chrome.setBreadcrumbs).not.toHaveBeenCalled(); expect(serverless.setBreadcrumbs).toHaveBeenCalledWith({ text: 'Create' }); await act(async () => { - instance.setProps({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); + rerender({ initialInput: { savedObjectId: breadcrumbDocSavedObjectId } }); lensStore.dispatch( setState({ persistedDoc: breadcrumbDoc, @@ -395,43 +328,40 @@ describe('Lens App', () => { describe('TopNavMenu#showDatePicker', () => { it('shows date picker if any used index pattern isTimeBased', async () => { - const customServices = makeDefaultServicesForApp(); - customServices.dataViews.get = jest + services.dataViews.get = jest .fn() - .mockImplementation((id) => - Promise.resolve({ id, isTimeBased: () => true, isPersisted: () => true } as DataView) + .mockImplementation( + async (id) => ({ id, isTimeBased: () => true, isPersisted: () => true } as DataView) ); - const { services } = await mountWith({ services: customServices }); + await renderApp(); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showDatePicker: true }), {} ); }); it('shows date picker if active datasource isTimeBased', async () => { - const customServices = makeDefaultServicesForApp(); - customServices.dataViews.get = jest + services.dataViews.get = jest .fn() - .mockImplementation((id) => - Promise.resolve({ id, isTimeBased: () => true, isPersisted: () => true } as DataView) + .mockImplementation( + async (id) => ({ id, isTimeBased: () => true, isPersisted: () => true } as DataView) ); - const customProps = makeDefaultProps(); - customProps.datasourceMap.testDatasource.isTimeBased = () => true; - const { services } = await mountWith({ props: customProps, services: customServices }); + + props.datasourceMap.testDatasource.isTimeBased = () => true; + await renderApp(); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showDatePicker: true }), {} ); }); it('does not show date picker if index pattern nor active datasource is not time based', async () => { - const customServices = makeDefaultServicesForApp(); - customServices.dataViews.get = jest + services.dataViews.get = jest .fn() - .mockImplementation((id) => - Promise.resolve({ id, isTimeBased: () => true, isPersisted: () => true } as DataView) + .mockImplementation( + async (id) => ({ id, isTimeBased: () => true, isPersisted: () => true } as DataView) ); - const customProps = makeDefaultProps(); - customProps.datasourceMap.testDatasource.isTimeBased = () => false; - const { services } = await mountWith({ props: customProps, services: customServices }); + + props.datasourceMap.testDatasource.isTimeBased = () => false; + await renderApp(); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ showDatePicker: false }), {} @@ -441,7 +371,7 @@ describe('Lens App', () => { describe('TopNavMenu#dataViewPickerProps', () => { it('calls the nav component with the correct dataview picker props if permissions are given', async () => { - const { instance, lensStore, services } = await mountWith({ preloadedState: {} }); + const { lensStore } = await renderApp(); services.dataViewEditor.userPermissions.editDataView = () => true; const document = { savedObjectId: defaultSavedObjectId, @@ -450,8 +380,9 @@ describe('Lens App', () => { filters: [{ query: { match_phrase: { src: 'test' } } }], }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - } as unknown as Document; + } as unknown as LensDocument; + (services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock).mockClear(); act(() => { lensStore.dispatch( setState({ @@ -460,46 +391,44 @@ describe('Lens App', () => { }) ); }); - instance.update(); - const props = instance - .find('[data-test-subj="lnsApp_topNav"]') - .prop('dataViewPickerComponentProps') as TopNavMenuData[]; - expect(props).toEqual( + expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ - currentDataViewId: 'mockip', - onChangeDataView: expect.any(Function), - onDataViewCreated: expect.any(Function), - onAddField: expect.any(Function), - }) + dataViewPickerComponentProps: expect.objectContaining({ + currentDataViewId: 'mockip', + onChangeDataView: expect.any(Function), + onDataViewCreated: expect.any(Function), + onAddField: expect.any(Function), + }), + }), + {} ); }); }); describe('persistence', () => { it('passes query and indexPatterns to TopNavMenu', async () => { - const { instance, lensStore, services } = await mountWith({ preloadedState: {} }); - const document = { + const { lensStore } = await renderApp(); + const query = { query: 'fake query', language: 'kuery' }; + const document = getLensDocumentMock({ savedObjectId: defaultSavedObjectId, state: { - query: 'fake query', - filters: [{ query: { match_phrase: { src: 'test' } } }], + ...defaultDoc.state, + query, + filters: [{ query: { match_phrase: { src: 'test' } }, meta: {} }], }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - } as unknown as Document; - - act(() => { - lensStore.dispatch( - setState({ - query: 'fake query' as unknown as Query, - persistedDoc: document, - }) - ); }); - instance.update(); + + await lensStore.dispatch( + setState({ + query, + persistedDoc: document, + }) + ); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ - query: 'fake query', + query, indexPatterns: [ { id: 'mockip', @@ -514,240 +443,155 @@ describe('Lens App', () => { ); }); it('handles rejected index pattern', async () => { - const customServices = makeDefaultServicesForApp(); - customServices.dataViews.get = jest + services.dataViews.get = jest .fn() - .mockImplementation((id) => Promise.reject({ reason: 'Could not locate that data view' })); - const customProps = makeDefaultProps(); - const { services } = await mountWith({ props: customProps, services: customServices }); + .mockResolvedValue(Promise.reject({ reason: 'Could not locate that data view' })); + await renderApp(); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ indexPatterns: [] }), {} ); }); - describe('save buttons', () => { - interface SaveProps { - newCopyOnSave: boolean; - returnToOrigin?: boolean; - newTitle: string; - } - function getButton(inst: ReactWrapper): TopNavMenuData { - return ( - inst.find('[data-test-subj="lnsApp_topNav"]').prop('config') as TopNavMenuData[] - ).find((button) => button.testId === 'lnsApp_saveButton')!; - } + describe('save buttons', () => { + const querySaveButton = () => screen.queryByTestId('lnsApp_saveButton'); + const clickSaveButton = async () => + await act(async () => await userEvent.click(screen.getByTestId('lnsApp_saveButton'))); - async function testSave(inst: ReactWrapper, saveProps: SaveProps) { - getButton(inst).run(inst.getDOMNode()); - // wait a tick since SaveModalContainer initializes asynchronously - await new Promise(process.nextTick); - const handler = inst.update().find('SavedObjectSaveModalOrigin').prop('onSave') as ( - p: unknown - ) => void; - handler(saveProps); - } + const querySaveAndReturnButton = () => screen.queryByTestId('lnsApp_saveAndReturnButton'); + const waitForModalVisible = async () => + await waitFor(() => screen.getByTestId('savedObjectTitle')); async function save({ preloadedState, - initialSavedObjectId, - ...saveProps - }: SaveProps & { + savedObjectId = defaultSavedObjectId, + prevSavedObjectId = undefined, + newTitle = 'hello there', + newCopyOnSave = false, + comesFromDashboard = true, + switchToAddToDashboardNone = false, + }: { + newCopyOnSave?: boolean; + newTitle?: string; preloadedState?: Partial<LensAppState>; - initialSavedObjectId?: string; + prevSavedObjectId?: string; + savedObjectId?: string; + comesFromDashboard?: boolean; + switchToAddToDashboardNone?: boolean; }) { - const props = { - ...makeDefaultProps(), - initialInput: initialSavedObjectId - ? { savedObjectId: initialSavedObjectId, id: '5678' } - : undefined, - }; - - props.incomingState = { - originatingApp: 'ultraDashboard', - }; - - const services = makeDefaultServicesForApp(); - services.attributeService.wrapAttributes = jest - .fn() - .mockImplementation(async ({ savedObjectId }) => ({ - savedObjectId: savedObjectId || 'aaa', - })); - services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ - metaInfo: { - sharingSavedObjectProps: { - outcome: 'exactMatch', - }, + services.attributeService.saveToLibrary = jest.fn().mockResolvedValue(savedObjectId); + services.attributeService.loadFromLibrary = jest.fn().mockResolvedValue({ + sharingSavedObjectProps: { + outcome: 'exactMatch', }, attributes: { - savedObjectId: initialSavedObjectId ?? 'aaa', + savedObjectId, references: [], state: { - query: 'fake query', + query: { query: 'fake query', language: 'kuery' }, filters: [], }, }, - } as jest.ResolvedValue<Document>); + managed: false, + }); + + props = { + ...props, + initialInput: prevSavedObjectId ? { savedObjectId: prevSavedObjectId } : undefined, + }; - const { frame, instance, lensStore } = await mountWith({ - services, - props, + if (comesFromDashboard) { + props.incomingState = { originatingApp: 'dashboards' }; + } + + const { lensStore } = await renderApp({ preloadedState: { isSaveable: true, - isLinkedToOriginatingApp: true, + isLinkedToOriginatingApp: comesFromDashboard, ...preloadedState, }, }); - expect(getButton(instance).disableButton).toEqual(false); - await act(async () => { - testSave(instance, { ...saveProps }); + await clickSaveButton(); + await waitForModalVisible(); + if (newCopyOnSave) { + await userEvent.click(screen.getByTestId('saveAsNewCheckbox')); + } + if (switchToAddToDashboardNone) { + await userEvent.click(screen.getByLabelText('None')); + } + await waitFor(async () => { + await userEvent.clear(screen.getByTestId('savedObjectTitle')); + expect(screen.getByTestId('savedObjectTitle')).toHaveValue(''); }); - return { props, services, instance, frame, lensStore }; + await userEvent.type(screen.getByTestId('savedObjectTitle'), `${newTitle}`); + await userEvent.click(screen.getByTestId('confirmSaveSavedObjectButton')); + await waitToLoad(); + return { props, lensStore }; } it('shows a disabled save button when the user does not have permissions', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { save: false, saveQuery: false, show: true }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { save: false, saveQuery: false, show: true }, + dashboard: { + showWriteControls: false, }, }; - const { instance, lensStore } = await mountWith({ services }); - expect(getButton(instance).disableButton).toEqual(true); - act(() => { - lensStore.dispatch( - setState({ - isSaveable: true, - }) - ); - }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(true); + await renderApp({ preloadedState: { isSaveable: true } }); + expect(querySaveButton()).toBeDisabled(); }); it('shows a save button that is enabled when the frame has provided its state and does not show save and return or save as', async () => { - const { instance, lensStore, services } = await mountWith({}); - expect(getButton(instance).disableButton).toEqual(true); - act(() => { - lensStore.dispatch( - setState({ - isSaveable: true, - }) - ); + await renderApp({ + preloadedState: { isSaveable: true }, }); - instance.update(); - expect(getButton(instance).disableButton).toEqual(false); - await act(async () => { - const topNavMenuConfig = instance - .find(services.navigation.ui.AggregateQueryTopNavMenu) - .prop('config'); - expect(topNavMenuConfig).not.toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) - ); - expect(topNavMenuConfig).not.toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveAsButton) - ); - expect(topNavMenuConfig).toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveButton) - ); - }); + expect(querySaveButton()).toHaveTextContent('Save'); + expect(querySaveAndReturnButton()).toBeFalsy(); }); - it('Shows Save and Return and Save As buttons in create by value mode with originating app', async () => { - const props = makeDefaultProps(); - const services = makeDefaultServicesForApp(); + it('Shows Save and Return and Save to library buttons in create by value mode with originating app', async () => { props.incomingState = { - originatingApp: 'ultraDashboard', + originatingApp: 'dashboards', valueInput: { id: 'whatchaGonnaDoWith', attributes: { title: 'whatcha gonna do with all these references? All these references in your value Input', - references: [] as SavedObjectReference[], + references: [], }, - } as LensByValueInput, + } as unknown as LensSerializedState, }; - - const { instance } = await mountWith({ - props, - services, + await renderApp({ preloadedState: { isLinkedToOriginatingApp: true, + isSaveable: true, }, }); - await act(async () => { - const topNavMenuConfig = instance - .find(services.navigation.ui.AggregateQueryTopNavMenu) - .prop('config'); - expect(topNavMenuConfig).toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) - ); - expect(topNavMenuConfig).toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveAsButton) - ); - expect(topNavMenuConfig).not.toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveButton) - ); - }); + expect(querySaveAndReturnButton()).toBeEnabled(); + expect(querySaveButton()).toHaveTextContent('Save to library'); }); it('Shows Save and Return and Save As buttons in edit by reference mode', async () => { - const props = makeDefaultProps(); - props.initialInput = { savedObjectId: defaultSavedObjectId, id: '5678' }; props.incomingState = { - originatingApp: 'ultraDashboard', + originatingApp: 'dashboards', }; - - const { instance, services } = await mountWith({ - props, + props.initialInput = { savedObjectId: defaultSavedObjectId, id: '5678' }; + await renderApp({ preloadedState: { + isSaveable: true, isLinkedToOriginatingApp: true, }, }); - await act(async () => { - const topNavMenuConfig = instance - .find(services.navigation.ui.AggregateQueryTopNavMenu) - .prop('config'); - expect(topNavMenuConfig).toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveAndReturnButton) - ); - expect(topNavMenuConfig).toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveAsButton) - ); - expect(topNavMenuConfig).not.toContainEqual( - expect.objectContaining(navMenuItems.expectedSaveButton) - ); - }); - }); - - it('saves new docs', async () => { - const { props, services } = await save({ - initialSavedObjectId: undefined, - newCopyOnSave: false, - newTitle: 'hello there', - }); - expect(services.attributeService.wrapAttributes).toHaveBeenCalledWith( - expect.objectContaining({ - savedObjectId: undefined, - title: 'hello there', - }), - true, - undefined - ); - expect(props.redirectTo).toHaveBeenCalledWith('aaa'); - expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( - "Saved 'hello there'" - ); + expect(querySaveAndReturnButton()).toBeEnabled(); + expect(querySaveButton()).toHaveTextContent('Save as'); }); it('applies all changes on-save', async () => { const { lensStore } = await save({ - initialSavedObjectId: undefined, + savedObjectId: undefined, newCopyOnSave: false, newTitle: 'hello there', preloadedState: { @@ -756,120 +600,91 @@ describe('Lens App', () => { }); expect(lensStore.getState().lens.applyChangesCounter).toBe(1); }); - it('adds to the recently accessed list on save', async () => { - const { services } = await save({ - initialSavedObjectId: undefined, - newCopyOnSave: false, - newTitle: 'hello there', - }); + const savedObjectId = faker.random.uuid(); + await save({ savedObjectId, prevSavedObjectId: 'prevId', comesFromDashboard: false }); expect(services.chrome.recentlyAccessed.add).toHaveBeenCalledWith( - '/app/lens#/edit/aaa', + `/app/lens#/edit/${savedObjectId}`, 'hello there', - 'aaa' + savedObjectId ); }); - it('saves the latest doc as a copy', async () => { - const { props, services, instance } = await save({ - initialSavedObjectId: defaultSavedObjectId, - newCopyOnSave: true, + it('saves new docs', async () => { + await save({ + prevSavedObjectId: undefined, + savedObjectId: defaultSavedObjectId, newTitle: 'hello there', - preloadedState: { persistedDoc: defaultDoc }, + comesFromDashboard: false, + switchToAddToDashboardNone: true, }); - expect(services.attributeService.wrapAttributes).toHaveBeenCalledWith( + expect(services.attributeService.saveToLibrary).toHaveBeenCalledWith( expect.objectContaining({ title: 'hello there', }), - true, + // from mocks + [ + { + id: 'mockip', + name: 'mockip', + type: 'index-pattern', + }, + ], undefined ); expect(props.redirectTo).toHaveBeenCalledWith(defaultSavedObjectId); - await act(async () => { - instance.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); - }); - expect(services.attributeService.wrapAttributes).toHaveBeenCalledTimes(1); expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( "Saved 'hello there'" ); }); - it('saves existing docs', async () => { - const { props, services, instance } = await save({ - initialSavedObjectId: defaultSavedObjectId, - newCopyOnSave: false, + it('saves existing docs as a copy', async () => { + const doc = getLensDocumentMock(); + await save({ + savedObjectId: doc.savedObjectId, + newCopyOnSave: true, newTitle: 'hello there', - preloadedState: { persistedDoc: defaultDoc }, + preloadedState: { persistedDoc: doc }, + prevSavedObjectId: 'prevId', + comesFromDashboard: false, }); - expect(services.attributeService.wrapAttributes).toHaveBeenCalledWith( + expect(services.attributeService.saveToLibrary).toHaveBeenCalledWith( expect.objectContaining({ - savedObjectId: defaultSavedObjectId, title: 'hello there', }), - true, - { id: '5678', savedObjectId: defaultSavedObjectId } + [{ id: 'mockip', name: 'mockip', type: 'index-pattern' }], + undefined ); - expect(props.redirectTo).not.toHaveBeenCalled(); - await act(async () => { - instance.setProps({ initialInput: { savedObjectId: defaultSavedObjectId } }); - }); + // new copy gets a new SO id + expect(props.redirectTo).toHaveBeenCalledWith(doc.savedObjectId); + expect(services.attributeService.saveToLibrary).toHaveBeenCalledTimes(1); expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( "Saved 'hello there'" ); }); - it('handles save failure by showing a warning, but still allows another save', async () => { - const mockedConsoleDir = jest.spyOn(console, 'dir'); // mocked console.dir to avoid messages in the console when running tests - mockedConsoleDir.mockImplementation(() => {}); - - const props = makeDefaultProps(); - - props.incomingState = { - originatingApp: 'ultraDashboard', - }; - - const services = makeDefaultServicesForApp(); - services.attributeService.wrapAttributes = jest - .fn() - .mockRejectedValue({ message: 'failed' }); - const { instance } = await mountWith({ - props, - services, - preloadedState: { - isSaveable: true, - isLinkedToOriginatingApp: true, - }, - }); - - await act(async () => { - testSave(instance, { newCopyOnSave: false, newTitle: 'hello there' }); - }); - expect(props.redirectTo).not.toHaveBeenCalled(); - expect(getButton(instance).disableButton).toEqual(false); - // eslint-disable-next-line no-console - expect(console.dir).toHaveBeenCalledTimes(1); - mockedConsoleDir.mockRestore(); - }); - - it('saves new doc and redirects to originating app', async () => { - const { props, services } = await save({ - initialSavedObjectId: undefined, - returnToOrigin: true, + it('saves existing docs', async () => { + await save({ + savedObjectId: defaultSavedObjectId, + prevSavedObjectId: defaultSavedObjectId, newCopyOnSave: false, newTitle: 'hello there', + comesFromDashboard: false, + preloadedState: { + persistedDoc: getLensDocumentMock({ savedObjectId: defaultSavedObjectId }), + }, }); - expect(services.attributeService.wrapAttributes).toHaveBeenCalledWith( + expect(services.attributeService.saveToLibrary).toHaveBeenCalledWith( expect.objectContaining({ - savedObjectId: undefined, title: 'hello there', }), - true, - undefined + [{ id: 'mockip', name: 'mockip', type: 'index-pattern' }], + defaultSavedObjectId + ); + expect(props.redirectTo).not.toHaveBeenCalled(); + expect(services.notifications.toasts.addSuccess).toHaveBeenCalledWith( + "Saved 'hello there'" ); - expect(props.redirectToOrigin).toHaveBeenCalledWith({ - input: { savedObjectId: 'aaa' }, - isCopied: false, - }); }); it('saves app filters and does not save pinned filters', async () => { @@ -881,229 +696,227 @@ describe('Lens App', () => { await act(async () => { FilterManager.setFiltersStore([pinned], FilterStateStore.GLOBAL_STATE); }); - const { services } = await save({ - initialSavedObjectId: defaultSavedObjectId, - newCopyOnSave: false, - newTitle: 'hello there2', + + await save({ + savedObjectId: defaultSavedObjectId, + prevSavedObjectId: defaultSavedObjectId, preloadedState: { - persistedDoc: defaultDoc, + isSaveable: true, + persistedDoc: getLensDocumentMock({ savedObjectId: defaultSavedObjectId }), + isLinkedToOriginatingApp: true, filters: [pinned, unpinned], }, }); const { state: expectedFilters } = services.data.query.filterManager.extract([unpinned]); - expect(services.attributeService.wrapAttributes).toHaveBeenCalledWith( + expect(services.attributeService.saveToLibrary).toHaveBeenCalledWith( expect.objectContaining({ - savedObjectId: defaultSavedObjectId, - title: 'hello there2', + title: 'hello there', state: expect.objectContaining({ filters: expectedFilters }), }), - true, - { id: '5678', savedObjectId: defaultSavedObjectId } + [{ id: 'mockip', name: 'mockip', type: 'index-pattern' }], + undefined ); }); it('checks for duplicate title before saving', async () => { - const props = makeDefaultProps(); - props.incomingState = { originatingApp: 'coolContainer' }; - const services = makeDefaultServicesForApp(); - services.attributeService.wrapAttributes = jest - .fn() - .mockReturnValue(Promise.resolve({ savedObjectId: '123' })); - const { instance } = await mountWith({ - props, - services, + await save({ + savedObjectId: defaultSavedObjectId, + prevSavedObjectId: defaultSavedObjectId, preloadedState: { isSaveable: true, - persistedDoc: { savedObjectId: '123' } as unknown as Document, + persistedDoc: { savedObjectId: defaultSavedObjectId } as unknown as LensDocument, isLinkedToOriginatingApp: true, }, }); - await act(async () => { - instance.setProps({ initialInput: { savedObjectId: '123' } }); - getButton(instance).run(instance.getDOMNode()); - }); - instance.update(); - const onTitleDuplicate = jest.fn(); - await act(async () => { - instance.find(SavedObjectSaveModal).prop('onSave')({ - onTitleDuplicate, - isTitleDuplicateConfirmed: false, - newCopyOnSave: false, - newDescription: '', - newTitle: 'test', - }); - }); + expect(checkForDuplicateTitle).toHaveBeenCalledWith( - expect.objectContaining({ id: '123', isTitleDuplicateConfirmed: false }), - onTitleDuplicate, + { + copyOnSave: true, + displayName: 'Lens visualization', + isTitleDuplicateConfirmed: false, + lastSavedTitle: '', + title: 'hello there', + }, + expect.any(Function), expect.anything() ); }); + it('saves new doc and redirects to originating app', async () => { + await save({ + savedObjectId: undefined, + newCopyOnSave: false, + newTitle: 'hello there', + }); + expect(services.attributeService.saveToLibrary).toHaveBeenCalledWith( + expect.objectContaining({ + title: 'hello there', + }), + [{ id: 'mockip', name: 'mockip', type: 'index-pattern' }], + undefined + ); + expect(props.redirectToOrigin).toHaveBeenCalledWith({ + state: expect.objectContaining({ savedObjectId: defaultSavedObjectId }), + isCopied: false, + }); + }); + + it('handles save failure by showing a warning, but still allows another save', async () => { + const mockedConsoleDir = jest.spyOn(console, 'dir').mockImplementation(() => {}); // mocked console.dir to avoid messages in the console when running tests + + services.attributeService.saveToLibrary = jest + .fn() + .mockRejectedValue({ message: 'failed' }); + + props.incomingState = { + originatingApp: 'dashboards', + }; + + await renderApp({ + preloadedState: { + isSaveable: true, + isLinkedToOriginatingApp: true, + }, + }); + await clickSaveButton(); + await userEvent.type(screen.getByTestId('savedObjectTitle'), 'hello there'); + await userEvent.click(screen.getByTestId('confirmSaveSavedObjectButton')); + await waitToLoad(); + + expect(props.redirectTo).not.toHaveBeenCalled(); + expect(services.attributeService.saveToLibrary).toHaveBeenCalled(); + // eslint-disable-next-line no-console + expect(console.dir).toHaveBeenCalledTimes(1); + mockedConsoleDir.mockRestore(); + }); + it('does not show the copy button on first save', async () => { - const props = makeDefaultProps(); - props.incomingState = { originatingApp: 'coolContainer' }; - const { instance } = await mountWith({ - props, + props.incomingState = { + originatingApp: 'dashboards', + }; + + await renderApp({ preloadedState: { isSaveable: true, isLinkedToOriginatingApp: true }, }); - await act(async () => getButton(instance).run(instance.getDOMNode())); - instance.update(); - expect(instance.find(SavedObjectSaveModal).prop('showCopyOnSave')).toEqual(false); + await clickSaveButton(); + await waitForModalVisible(); + expect(screen.queryByTestId('saveAsNewCheckbox')).not.toBeInTheDocument(); }); it('enables Save Query UI when user has app-level permissions', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { saveQuery: true }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { saveQuery: true }, }; - const { instance } = await mountWith({ services }); - await act(async () => { - const topNavMenu = instance.find(services.navigation.ui.AggregateQueryTopNavMenu); - expect(topNavMenu.props().saveQueryMenuVisibility).toBe('allowed_by_app_privilege'); - }); + + await renderApp(); + expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenLastCalledWith( + expect.objectContaining({ saveQueryMenuVisibility: 'allowed_by_app_privilege' }), + {} + ); }); it('checks global save query permission when user does not have app-level permissions', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { saveQuery: false }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { saveQuery: false }, }; - const { instance } = await mountWith({ services }); - await act(async () => { - const topNavMenu = instance.find(services.navigation.ui.AggregateQueryTopNavMenu); - expect(topNavMenu.props().saveQueryMenuVisibility).toBe('globally_managed'); - }); + await renderApp(); + expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenLastCalledWith( + expect.objectContaining({ saveQueryMenuVisibility: 'globally_managed' }), + {} + ); }); }); }); describe('share button', () => { - function getShareButton(inst: ReactWrapper): TopNavMenuData { - return ( - inst.find('[data-test-subj="lnsApp_topNav"]').prop('config') as TopNavMenuData[] - ).find((button) => button.testId === 'lnsApp_shareButton')!; - } + const getShareButton = () => screen.getByTestId('lnsApp_shareButton'); it('should be disabled when no data is available', async () => { - const { instance } = await mountWith({ preloadedState: { isSaveable: true } }); - expect(getShareButton(instance).disableButton).toEqual(true); + await renderApp({ preloadedState: { isSaveable: true } }); + expect(getShareButton()).toBeDisabled(); }); it('should not disable share when not saveable', async () => { - const { instance } = await mountWith({ + await renderApp({ preloadedState: { isSaveable: false, activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, }, }); - expect(getShareButton(instance).disableButton).toEqual(false); + expect(getShareButton()).toBeEnabled(); }); it('should still be enabled even if the user is missing save permissions', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { save: false, saveQuery: false, show: true, createShortUrl: true }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { save: false, saveQuery: false, show: true, createShortUrl: true }, }; - const { instance } = await mountWith({ - services, + await renderApp({ preloadedState: { isSaveable: true, activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, }, }); - expect(getShareButton(instance).disableButton).toEqual(false); + expect(getShareButton()).toBeEnabled(); }); it('should still be enabled even if the user is missing shortUrl permissions', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { save: true, saveQuery: false, show: true, createShortUrl: false }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { save: true, saveQuery: false, show: true, createShortUrl: false }, }; - const { instance } = await mountWith({ - services, + await renderApp({ preloadedState: { isSaveable: true, activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, }, }); - expect(getShareButton(instance).disableButton).toEqual(false); + + expect(getShareButton()).toBeEnabled(); }); it('should be disabled if the user is missing shortUrl permissions and visualization is not saveable', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { save: false, saveQuery: false, show: true, createShortUrl: false }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { save: false, saveQuery: false, show: true, createShortUrl: false }, }; - const { instance } = await mountWith({ - services, + await renderApp({ preloadedState: { isSaveable: false, activeData: { layer1: { type: 'datatable', columns: [], rows: [] } }, }, }); - expect(getShareButton(instance).disableButton).toEqual(true); + expect(getShareButton()).toBeDisabled(); }); }); describe('inspector', () => { - function getButton(inst: ReactWrapper): TopNavMenuData { - return ( - inst.find('[data-test-subj="lnsApp_topNav"]').prop('config') as TopNavMenuData[] - ).find((button) => button.testId === 'lnsApp_inspectButton')!; - } - - async function runInspect(inst: ReactWrapper) { - await getButton(inst).run(inst.getDOMNode()); - await inst.update(); - } - it('inspector button should be available', async () => { - const { instance } = await mountWith({ preloadedState: { isSaveable: true } }); - const button = getButton(instance); - - expect(button.disableButton).toEqual(false); + await renderApp({ + preloadedState: { isSaveable: true }, + }); + expect(screen.getByTestId('lnsApp_inspectButton')).toBeEnabled(); }); - it('should open inspect panel', async () => { - const services = makeDefaultServicesForApp(); - const { instance } = await mountWith({ services, preloadedState: { isSaveable: true } }); - - await runInspect(instance); - + await renderApp({ + preloadedState: { isSaveable: true }, + }); + await userEvent.click(screen.getByTestId('lnsApp_inspectButton')); expect(services.inspector.inspect).toHaveBeenCalledTimes(1); }); }); describe('query bar state management', () => { it('uses the default time and query language settings', async () => { - const { lensStore, services } = await mountWith({}); + const { lensStore } = await renderApp(); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: { query: '', language: 'lucene' }, @@ -1125,18 +938,20 @@ describe('Lens App', () => { }); it('updates the editor frame when the user changes query or time in the search bar', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); (services.data.query.timefilter.timefilter.calculateBounds as jest.Mock).mockReturnValue({ min: moment('2021-01-09T04:00:00.000Z'), max: moment('2021-01-09T08:00:00.000Z'), }); + const onQuerySubmit = (services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock).mock + .calls[0][0].onQuerySubmit; await act(async () => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onQuerySubmit')!({ + onQuerySubmit({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) ); - instance.update(); + expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: { query: 'new', language: 'lucene' }, @@ -1162,7 +977,7 @@ describe('Lens App', () => { }); it('updates the filters when the user changes them', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); const indexPattern = { id: 'index1', isPersisted: () => true } as unknown as DataView; const field = { name: 'myfield' } as unknown as FieldSpec; expect(lensStore.getState()).toEqual({ @@ -1170,10 +985,9 @@ describe('Lens App', () => { filters: [], }), }); - act(() => - services.data.query.filterManager.setFilters([buildExistsFilter(field, indexPattern)]) - ); - instance.update(); + + services.data.query.filterManager.setFilters([buildExistsFilter(field, indexPattern)]); + expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ filters: [buildExistsFilter(field, indexPattern)], @@ -1182,7 +996,7 @@ describe('Lens App', () => { }); it('updates the searchSessionId when the user changes query or time in the search bar', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ @@ -1190,13 +1004,14 @@ describe('Lens App', () => { }), }); + const AggregateQueryTopNavMenu = services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock; + const onQuerySubmit = AggregateQueryTopNavMenu.mock.calls[0][0].onQuerySubmit; act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onQuerySubmit')!({ + onQuerySubmit({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: '', language: 'lucene' }, }) ); - instance.update(); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ @@ -1205,12 +1020,12 @@ describe('Lens App', () => { }); // trigger again, this time changing just the query act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onQuerySubmit')!({ + onQuerySubmit({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) ); - instance.update(); + expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: `sessionId-3`, @@ -1221,7 +1036,7 @@ describe('Lens App', () => { act(() => services.data.query.filterManager.setFilters([buildExistsFilter(field, indexPattern)]) ); - instance.update(); + expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: `sessionId-4`, @@ -1232,15 +1047,11 @@ describe('Lens App', () => { describe('saved query handling', () => { it('does not allow saving when the user is missing the saveQuery permission', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { save: false, saveQuery: false, show: true }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { save: false, saveQuery: false, show: true }, }; - await mountWith({ services }); + await renderApp(); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ saveQueryMenuVisibility: 'globally_managed' }), {} @@ -1248,7 +1059,8 @@ describe('Lens App', () => { }); it('persists the saved query ID when the query is saved', async () => { - const { instance, services } = await mountWith({}); + await renderApp(); + expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ saveQueryMenuVisibility: 'allowed_by_app_privilege', @@ -1259,8 +1071,11 @@ describe('Lens App', () => { }), {} ); + + const onSaved = (services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock).mock + .calls[0][0].onSaved; act(() => { - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onSaved')!({ + onSaved({ id: '1', attributes: { title: '', @@ -1287,9 +1102,12 @@ describe('Lens App', () => { }); it('changes the saved query ID when the query is updated', async () => { - const { instance, services } = await mountWith({}); + await renderApp(); + const { onSaved, onSavedQueryUpdated } = ( + services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock + ).mock.calls[0][0]; act(() => { - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onSaved')!({ + onSaved({ id: '1', attributes: { title: '', @@ -1300,17 +1118,15 @@ describe('Lens App', () => { }); }); act(() => { - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onSavedQueryUpdated')!( - { - id: '2', - attributes: { - title: 'new title', - description: '', - query: { query: '', language: 'lucene' }, - }, - namespaces: ['default'], - } - ); + onSavedQueryUpdated({ + id: '2', + attributes: { + title: 'new title', + description: '', + query: { query: '', language: 'lucene' }, + }, + namespaces: ['default'], + }); }); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ @@ -1329,19 +1145,19 @@ describe('Lens App', () => { }); it('updates the query if saved query is selected', async () => { - const { instance, services } = await mountWith({}); + await renderApp(); + const { onSavedQueryUpdated } = (services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock) + .mock.calls[0][0]; act(() => { - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onSavedQueryUpdated')!( - { - id: '2', - attributes: { - title: 'new title', - description: '', - query: { query: 'abc:def', language: 'lucene' }, - }, - namespaces: ['default'], - } - ); + onSavedQueryUpdated({ + id: '2', + attributes: { + title: 'new title', + description: '', + query: { query: 'abc:def', language: 'lucene' }, + }, + namespaces: ['default'], + }); }); expect(services.navigation.ui.AggregateQueryTopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ @@ -1352,9 +1168,12 @@ describe('Lens App', () => { }); it('clears all existing unpinned filters when the active saved query is cleared', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); + const { onQuerySubmit, onClearSavedQuery } = ( + services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock + ).mock.calls[0][0]; act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onQuerySubmit')!({ + onQuerySubmit({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) @@ -1366,11 +1185,7 @@ describe('Lens App', () => { const pinned = buildExistsFilter(pinnedField, indexPattern); FilterManager.setFiltersStore([pinned], FilterStateStore.GLOBAL_STATE); act(() => services.data.query.filterManager.setFilters([pinned, unpinned])); - instance.update(); - act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onClearSavedQuery')!() - ); - instance.update(); + act(() => onClearSavedQuery()); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ filters: [pinned], @@ -1381,9 +1196,12 @@ describe('Lens App', () => { describe('search session id management', () => { it('updates the searchSessionId when the query is updated', async () => { - const { instance, lensStore, services } = await mountWith({}); + const { lensStore } = await renderApp(); + const { onSaved, onSavedQueryUpdated } = ( + services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock + ).mock.calls[0][0]; act(() => { - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onSaved')!({ + onSaved({ id: '1', attributes: { title: '', @@ -1394,19 +1212,16 @@ describe('Lens App', () => { }); }); act(() => { - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onSavedQueryUpdated')!( - { - id: '2', - attributes: { - title: 'new title', - description: '', - query: { query: '', language: 'lucene' }, - }, - namespaces: ['default'], - } - ); + onSavedQueryUpdated({ + id: '2', + attributes: { + title: 'new title', + description: '', + query: { query: '', language: 'lucene' }, + }, + namespaces: ['default'], + }); }); - instance.update(); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: `sessionId-2`, @@ -1415,9 +1230,12 @@ describe('Lens App', () => { }); it('updates the searchSessionId when the active saved query is cleared', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); + const { onQuerySubmit, onClearSavedQuery } = ( + services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock + ).mock.calls[0][0]; act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onQuerySubmit')!({ + onQuerySubmit({ dateRange: { from: 'now-14d', to: 'now-7d' }, query: { query: 'new', language: 'lucene' }, }) @@ -1429,11 +1247,7 @@ describe('Lens App', () => { const pinned = buildExistsFilter(pinnedField, indexPattern); FilterManager.setFiltersStore([pinned], FilterStateStore.GLOBAL_STATE); act(() => services.data.query.filterManager.setFilters([pinned, unpinned])); - instance.update(); - act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onClearSavedQuery')!() - ); - instance.update(); + act(() => onClearSavedQuery()); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: `sessionId-4`, @@ -1442,14 +1256,14 @@ describe('Lens App', () => { }); it('dispatches update to searchSessionId and dateRange when the user hits refresh', async () => { - const { instance, services, lensStore } = await mountWith({}); + const { lensStore } = await renderApp(); + const { onQuerySubmit } = (services.navigation.ui.AggregateQueryTopNavMenu as jest.Mock).mock + .calls[0][0]; act(() => - instance.find(services.navigation.ui.AggregateQueryTopNavMenu).prop('onQuerySubmit')!({ + onQuerySubmit({ dateRange: { from: 'now-7d', to: 'now' }, }) ); - - instance.update(); expect(lensStore.dispatch).toHaveBeenCalledWith({ type: 'lens/setState', payload: { @@ -1464,15 +1278,12 @@ describe('Lens App', () => { it('updates the state if session id changes from the outside', async () => { const sessionIdS = new Subject<string>(); - const services = makeDefaultServices(sessionIdS, 'sessionId-1'); - const { lensStore } = await mountWith({ props: undefined, services }); + services = makeDefaultServices(sessionIdS, 'sessionId-1'); + const { lensStore } = await renderApp(); - act(() => { - sessionIdS.next('new-session-id'); - }); - await act(async () => { - await new Promise((r) => setTimeout(r, 0)); - }); + act(() => sessionIdS.next('new-session-id')); + + await waitToLoad(); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: `new-session-id`, @@ -1481,7 +1292,7 @@ describe('Lens App', () => { }); it('does not update the searchSessionId when the state changes', async () => { - const { lensStore } = await mountWith({ preloadedState: { isSaveable: true } }); + const { lensStore } = await renderApp({ preloadedState: { isSaveable: true } }); expect(lensStore.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: `sessionId-1`, @@ -1491,40 +1302,37 @@ describe('Lens App', () => { }); describe('showing a confirm message when leaving', () => { - let defaultLeave: jest.Mock; - let confirmLeave: jest.Mock; + const defaultLeave = jest.fn(); + const confirmLeave = jest.fn(); beforeEach(() => { - defaultLeave = jest.fn(); - confirmLeave = jest.fn(); + jest.clearAllMocks(); }); it('should not show a confirm message if there is no expression to save', async () => { - const { props } = await mountWith({}); - const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; + await renderApp(); + const lastCall = (props.onAppLeave as jest.Mock).mock.lastCall![0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); it('does not confirm if the user is missing save permissions', async () => { - const services = makeDefaultServicesForApp(); - services.application = { - ...services.application, - capabilities: { - ...services.application.capabilities, - visualize: { save: false, saveQuery: false, show: true }, - }, + services.application.capabilities = { + ...services.application.capabilities, + visualize: { save: false, saveQuery: false, show: true }, }; - const { props } = await mountWith({ services, preloadedState: { isSaveable: true } }); - const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; + await renderApp({ + preloadedState: { isSaveable: true }, + }); + const lastCall = (props.onAppLeave as jest.Mock).mock.lastCall![0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); it('should confirm when leaving with an unsaved doc', async () => { - const { props } = await mountWith({ + await renderApp({ preloadedState: { visualization: { activeId: 'testVis', @@ -1533,16 +1341,18 @@ describe('Lens App', () => { isSaveable: true, }, }); - const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; + const lastCall = (props.onAppLeave as jest.Mock).mock.calls[ + (props.onAppLeave as jest.Mock).mock.calls.length - 1 + ][0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); expect(defaultLeave).not.toHaveBeenCalled(); }); it('should confirm when leaving with unsaved changes to an existing doc', async () => { - const { props } = await mountWith({ + await renderApp({ preloadedState: { - persistedDoc: defaultDoc, + persistedDoc: getLensDocumentMock(), visualization: { activeId: 'testVis', state: {}, @@ -1550,73 +1360,45 @@ describe('Lens App', () => { isSaveable: true, }, }); - const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; + const lastCall = (props.onAppLeave as jest.Mock).mock.lastCall![0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); expect(defaultLeave).not.toHaveBeenCalled(); }); it('should confirm when leaving from a context initial doc with changes made in lens', async () => { - const initialProps = { - ...makeDefaultProps(), - contextOriginatingApp: 'TSVB', - initialContext: { - layers: [ - { - indexPatternId: 'ff959d40-b880-11e8-a6d9-e546fe2bba5f', - xFieldName: 'order_date', - xMode: 'date_histogram', - chartType: 'area', - axisPosition: 'left', - palette: { - type: 'palette', - name: 'default', - }, - metrics: [ - { - agg: 'count', - isFullReference: false, - fieldName: 'document', - params: {}, - color: '#68BC00', - }, - ], - timeInterval: 'auto', - }, - ], - type: 'lnsXY', - configuration: { - fill: 0.5, - legend: { - isVisible: true, - position: 'right', - shouldTruncate: true, - maxLines: 1, - }, - gridLinesVisibility: { - x: true, - yLeft: true, - yRight: true, + props.contextOriginatingApp = 'TSVB'; + props.initialContext = { + layers: [ + { + indexPatternId: 'indexPatternId', + chartType: 'area', + axisPosition: 'left', + palette: { + type: 'palette', + name: 'default', }, - extents: { - yLeftExtent: { - mode: 'full', - }, - yRightExtent: { - mode: 'full', + metrics: [ + { + agg: 'count', + isFullReference: false, + fieldName: 'document', + params: {}, + color: '#68BC00', }, - }, + ], + timeInterval: 'auto', }, - savedObjectId: '', - vizEditorOriginatingAppUrl: '#/tsvb-link', - isVisualizeAction: true, - }, - }; + ], + type: 'lnsXY', + savedObjectId: '', + vizEditorOriginatingAppUrl: '#/tsvb-link', + isVisualizeAction: true, + } as unknown as VisualizeEditorContext; - const mountedApp = await mountWith({ - props: initialProps as unknown as jest.Mocked<LensAppProps>, + await renderApp({ preloadedState: { - persistedDoc: defaultDoc, + persistedDoc: getLensDocumentMock(), visualization: { activeId: 'testVis', state: {}, @@ -1624,76 +1406,72 @@ describe('Lens App', () => { isSaveable: true, }, }); - const lastCall = - mountedApp.props.onAppLeave.mock.calls[ - mountedApp.props.onAppLeave.mock.calls.length - 1 - ][0]; + const lastCall = (props.onAppLeave as jest.Mock).mock.lastCall![0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).not.toHaveBeenCalled(); expect(confirmLeave).toHaveBeenCalled(); }); it('should not confirm when changes are saved', async () => { + const localDoc = getLensDocumentMock(); const preloadedState = { persistedDoc: { - ...defaultDoc, + ...localDoc, state: { - ...defaultDoc.state, - datasourceStates: { testDatasource: {} }, + ...localDoc.state, + datasourceStates: { + testDatasource: 'datasource', + }, visualization: {}, }, }, isSaveable: true, - ...(defaultDoc.state as Partial<LensAppState>), + ...(localDoc.state as Partial<LensAppState>), visualization: { activeId: 'testVis', state: {}, }, }; - const customProps = makeDefaultProps(); - customProps.datasourceMap.testDatasource.isEqual = () => true; // if this returns false, the documents won't be accounted equal + props.datasourceMap.testDatasource.isEqual = jest.fn().mockReturnValue(true); // if this returns false, the documents won't be accounted equal - const { props } = await mountWith({ preloadedState, props: customProps }); + await renderApp({ preloadedState }); - const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; - lastCall({ default: defaultLeave, confirm: confirmLeave }); + const lastCallArg = props.onAppLeave.mock.lastCall![0]; + lastCallArg?.({ default: defaultLeave, confirm: confirmLeave }); expect(defaultLeave).toHaveBeenCalled(); expect(confirmLeave).not.toHaveBeenCalled(); }); - // not sure how to test it it('should confirm when the latest doc is invalid', async () => { - const { lensStore, props } = await mountWith({}); - act(() => { - lensStore.dispatch( + const { lensStore } = await renderApp(); + await act(async () => { + await lensStore.dispatch( setState({ - persistedDoc: defaultDoc, + persistedDoc: getLensDocumentMock(), isSaveable: true, }) ); }); - const lastCall = props.onAppLeave.mock.calls[props.onAppLeave.mock.calls.length - 1][0]; + const lastCall = (props.onAppLeave as jest.Mock).mock.lastCall![0]; lastCall({ default: defaultLeave, confirm: confirmLeave }); expect(confirmLeave).toHaveBeenCalled(); expect(defaultLeave).not.toHaveBeenCalled(); }); }); + it('should display a conflict callout if saved object conflicts', async () => { const history = createMemoryHistory(); - const { services } = await mountWith({ - props: { - ...makeDefaultProps(), - history: { - ...history, - location: { - ...history.location, - search: '?_g=test', - }, - }, + props.history = { + ...history, + location: { + ...history.location, + search: '?_g=test', }, + }; + await renderApp({ preloadedState: { - persistedDoc: defaultDoc, + persistedDoc: getLensDocumentMock({ savedObjectId: defaultSavedObjectId }), sharingSavedObjectProps: { outcome: 'conflict', aliasTargetId: '2', @@ -1701,7 +1479,7 @@ describe('Lens App', () => { }, }); expect(services.spaces?.ui.components.getLegacyUrlConflict).toHaveBeenCalledWith({ - currentObjectId: '1234', + currentObjectId: defaultSavedObjectId, objectNoun: 'Lens visualization', otherObjectId: '2', otherObjectPath: '#/edit/2?_g=test', diff --git a/x-pack/plugins/lens/public/app_plugin/app.tsx b/x-pack/plugins/lens/public/app_plugin/app.tsx index 60e1b0dfdb66..b8903bde1af0 100644 --- a/x-pack/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/plugins/lens/public/app_plugin/app.tsx @@ -9,16 +9,14 @@ import './app.scss'; import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react'; import { i18n } from '@kbn/i18n'; import type { TimeRange } from '@kbn/es-query'; -import { EuiBreadcrumb, EuiConfirmModal } from '@elastic/eui'; +import { EuiConfirmModal } from '@elastic/eui'; import { useExecutionContext, useKibana } from '@kbn/kibana-react-plugin/public'; import { OnSaveProps } from '@kbn/saved-objects-plugin/public'; import type { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; -import type { LensAppLocatorParams } from '../../common/locator/locator'; import { LensAppProps, LensAppServices } from './types'; import { LensTopNavMenu } from './lens_top_nav'; -import { LensByReferenceInput } from '../embeddable'; -import { AddUserMessages, EditorFrameInstance, UserMessagesGetter } from '../types'; -import { Document } from '../persistence/saved_object_store'; +import { AddUserMessages, EditorFrameInstance, Simplify, UserMessagesGetter } from '../types'; +import { LensDocument } from '../persistence/saved_object_store'; import { setState, @@ -43,15 +41,24 @@ import { import { replaceIndexpattern } from '../state_management/lens_slice'; import { useApplicationUserMessages } from './get_application_user_messages'; import { trackSaveUiCounterEvents } from '../lens_ui_telemetry'; - -export type SaveProps = Omit<OnSaveProps, 'onTitleDuplicate' | 'newDescription'> & { - returnToOrigin: boolean; - dashboardId?: string | null; - onTitleDuplicate?: OnSaveProps['onTitleDuplicate']; - newDescription?: string; - newTags?: string[]; - panelTimeRange?: TimeRange; -}; +import { + getCurrentTitle, + isLegacyEditorEmbeddable, + setBreadcrumbsTitle, + useNavigateBackToApp, + useShortUrlService, +} from './app_helpers'; + +export type SaveProps = Simplify< + Omit<OnSaveProps, 'onTitleDuplicate' | 'newDescription'> & { + returnToOrigin: boolean; + dashboardId?: string | null; + onTitleDuplicate?: OnSaveProps['onTitleDuplicate']; + newDescription?: string; + newTags?: string[]; + panelTimeRange?: TimeRange; + } +>; export function App({ history, @@ -127,18 +134,26 @@ export function App({ selectSavedObjectFormat(state, selectorDependencies) ); - const shortUrls = useMemo(() => share?.url.shortUrls.get(null), [share]); - // Used to show a popover that guides the user towards changing the date range when no data is available. const [indicateNoData, setIndicateNoData] = useState(false); const [isSaveModalVisible, setIsSaveModalVisible] = useState(false); - const [lastKnownDoc, setLastKnownDoc] = useState<Document | undefined>(undefined); - const [initialDocFromContext, setInitialDocFromContext] = useState<Document | undefined>( + const [lastKnownDoc, setLastKnownDoc] = useState<LensDocument | undefined>(undefined); + const [initialDocFromContext, setInitialDocFromContext] = useState<LensDocument | undefined>( undefined ); - const [isGoBackToVizEditorModalVisible, setIsGoBackToVizEditorModalVisible] = useState(false); const [shouldCloseAndSaveTextBasedQuery, setShouldCloseAndSaveTextBasedQuery] = useState(false); - const savedObjectId = (initialInput as LensByReferenceInput)?.savedObjectId; + const savedObjectId = initialInput?.savedObjectId; + + const isFromLegacyEditorEmbeddable = isLegacyEditorEmbeddable(initialContext); + const legacyEditorAppName = + initialContext && 'originatingApp' in initialContext + ? initialContext.originatingApp + : undefined; + const legacyEditorAppUrl = + initialContext && 'vizEditorOriginatingAppUrl' in initialContext + ? initialContext.vizEditorOriginatingAppUrl + : undefined; + const initialContextIsEmbedded = Boolean(legacyEditorAppName); useEffect(() => { if (currentDoc) { @@ -167,18 +182,27 @@ export function App({ [isLinkedToOriginatingApp, savedObjectId] ); + // Wrap the isEqual call to avoid to carry all the static references + // around all the time. + const isLensEqualWrapper = useCallback( + (refDoc: LensDocument | undefined) => { + return isLensEqual( + refDoc, + lastKnownDoc, + data.query.filterManager.inject.bind(data.query.filterManager), + datasourceMap, + visualizationMap, + annotationGroups + ); + }, + [annotationGroups, data.query.filterManager, datasourceMap, lastKnownDoc, visualizationMap] + ); + useEffect(() => { onAppLeave((actions) => { if ( application.capabilities.visualize.save && - !isLensEqual( - persistedDoc, - lastKnownDoc, - data.query.filterManager.inject.bind(data.query.filterManager), - datasourceMap, - visualizationMap, - annotationGroups - ) && + !isLensEqualWrapper(persistedDoc) && (isSaveable || persistedDoc) ) { return actions.confirm( @@ -208,6 +232,7 @@ export function App({ datasourceMap, visualizationMap, annotationGroups, + isLensEqualWrapper, ]); const getLegacyUrlConflictCallout = useCallback(() => { @@ -235,66 +260,17 @@ export function App({ // Sync Kibana breadcrumbs any time the saved document's title changes useEffect(() => { const isByValueMode = getIsByValueMode(); - const comesFromVizEditorDashboard = - initialContext && 'originatingApp' in initialContext && initialContext.originatingApp; - const breadcrumbs: EuiBreadcrumb[] = []; - if ( - (isLinkedToOriginatingApp || comesFromVizEditorDashboard) && - getOriginatingAppName() && - redirectToOrigin - ) { - breadcrumbs.push({ - onClick: () => { - redirectToOrigin(); - }, - text: getOriginatingAppName(), - }); - } - if (!isByValueMode) { - breadcrumbs.push({ - href: application.getUrlForApp('visualize'), - onClick: (e) => { - application.navigateToApp('visualize', { path: '/' }); - e.preventDefault(); - }, - text: i18n.translate('xpack.lens.breadcrumbsTitle', { - defaultMessage: 'Visualize Library', - }), - }); - } - let currentDocTitle = i18n.translate('xpack.lens.breadcrumbsCreate', { - defaultMessage: 'Create', - }); - if (persistedDoc) { - currentDocTitle = isByValueMode - ? i18n.translate('xpack.lens.breadcrumbsByValue', { defaultMessage: 'Edit visualization' }) - : persistedDoc.title; - } - if ( - !persistedDoc?.title && - initialContext && - 'isEmbeddable' in initialContext && - initialContext.isEmbeddable - ) { - currentDocTitle = i18n.translate('xpack.lens.breadcrumbsEditInLensFromDashboard', { - defaultMessage: 'Converting {title} visualization', - values: { - title: initialContext.title ? `"${initialContext.title}"` : initialContext.visTypeTitle, - }, - }); - } - - const currentDocBreadcrumb: EuiBreadcrumb = { text: currentDocTitle }; - breadcrumbs.push(currentDocBreadcrumb); - if (serverless?.setBreadcrumbs) { - // TODO: https://github.com/elastic/kibana/issues/163488 - // for now, serverless breadcrumbs only set the title, - // the rest of the breadcrumbs are handled by the serverless navigation - // the serverless navigation is not yet aware of the byValue/originatingApp context - serverless.setBreadcrumbs(currentDocBreadcrumb); - } else { - chrome.setBreadcrumbs(breadcrumbs); - } + const currentDocTitle = getCurrentTitle(persistedDoc, isByValueMode, initialContext); + setBreadcrumbsTitle( + { application, chrome, serverless }, + { + isByValueMode, + currentDocTitle, + redirectToOrigin, + isFromLegacyEditor: Boolean(isLinkedToOriginatingApp || legacyEditorAppName), + originatingAppName: getOriginatingAppName(), + } + ); }, [ getOriginatingAppName, redirectToOrigin, @@ -303,8 +279,10 @@ export function App({ chrome, isLinkedToOriginatingApp, persistedDoc, - initialContext, + isFromLegacyEditorEmbeddable, + legacyEditorAppName, serverless, + initialContext, ]); const switchDatasource = useCallback(() => { @@ -314,12 +292,13 @@ export function App({ }, []); const runSave = useCallback( - (saveProps: SaveProps, options: { saveToLibrary: boolean }) => { + async (saveProps: SaveProps, options: { saveToLibrary: boolean }) => { dispatch(applyChanges()); const prevVisState = persistedDoc?.visualizationType === visualization.activeId ? persistedDoc?.state.visualization : undefined; + const telemetryEvents = activeVisualization?.getTelemetryEventsOnSave?.( visualization.state, prevVisState @@ -327,36 +306,33 @@ export function App({ if (telemetryEvents && telemetryEvents.length) { trackSaveUiCounterEvents(telemetryEvents); } - return runSaveLensVisualization( - { - lastKnownDoc, - getIsByValueMode, - savedObjectsTagging, - initialInput, - redirectToOrigin, - persistedDoc, - onAppLeave, - redirectTo, - switchDatasource, - originatingApp: incomingState?.originatingApp, - textBasedLanguageSave: shouldCloseAndSaveTextBasedQuery, - ...lensAppServices, - }, - saveProps, - options - ).then( - (newState) => { - if (newState) { - dispatchSetState(newState); - setIsSaveModalVisible(false); - setShouldCloseAndSaveTextBasedQuery(false); - } - }, - () => { - // error is handled inside the modal - // so ignoring it here + try { + const newState = await runSaveLensVisualization( + { + lastKnownDoc, + savedObjectsTagging, + initialInput, + redirectToOrigin, + persistedDoc, + onAppLeave, + redirectTo, + switchDatasource, + originatingApp: incomingState?.originatingApp, + textBasedLanguageSave: shouldCloseAndSaveTextBasedQuery, + ...lensAppServices, + }, + saveProps, + options + ); + if (newState) { + dispatchSetState(newState); + setIsSaveModalVisible(false); + setShouldCloseAndSaveTextBasedQuery(false); } - ); + } catch (e) { + // error is handled inside the modal + // so ignoring it here + } }, [ visualization.activeId, @@ -364,7 +340,6 @@ export function App({ activeVisualization, dispatch, lastKnownDoc, - getIsByValueMode, savedObjectsTagging, initialInput, redirectToOrigin, @@ -386,67 +361,20 @@ export function App({ } }, [lastKnownDoc, initialDocFromContext]); - // if users comes to Lens from the Viz editor, they should have the option to navigate back - const goBackToOriginatingApp = useCallback(() => { - if ( - initialContext && - 'vizEditorOriginatingAppUrl' in initialContext && - initialContext.vizEditorOriginatingAppUrl - ) { - const [initialDocFromContextUnchanged, currentDocHasBeenSavedInLens] = [ - initialDocFromContext, - persistedDoc, - ].map((refDoc) => - isLensEqual( - refDoc, - lastKnownDoc, - data.query.filterManager.inject, - datasourceMap, - visualizationMap, - annotationGroups - ) - ); - if (initialDocFromContextUnchanged || currentDocHasBeenSavedInLens) { - onAppLeave((actions) => { - return actions.default(); - }); - application.navigateToApp('visualize', { path: initialContext.vizEditorOriginatingAppUrl }); - } else { - setIsGoBackToVizEditorModalVisible(true); - } - } - }, [ - annotationGroups, + const { + shouldShowGoBackToVizEditorModal, + goBackToOriginatingApp, + navigateToVizEditor, + closeGoBackToVizEditorModal, + } = useNavigateBackToApp({ application, - data.query.filterManager.inject, - datasourceMap, - initialContext, - initialDocFromContext, - lastKnownDoc, onAppLeave, + legacyEditorAppName, + legacyEditorAppUrl, + initialDocFromContext, persistedDoc, - visualizationMap, - ]); - - const navigateToVizEditor = useCallback(() => { - setIsGoBackToVizEditorModalVisible(false); - if ( - initialContext && - 'vizEditorOriginatingAppUrl' in initialContext && - initialContext.vizEditorOriginatingAppUrl - ) { - onAppLeave((actions) => { - return actions.default(); - }); - application.navigateToApp('visualize', { path: initialContext.vizEditorOriginatingAppUrl }); - } - }, [application, initialContext, onAppLeave]); - - const initialContextIsEmbedded = useMemo(() => { - return Boolean( - initialContext && 'originatingApp' in initialContext && initialContext.originatingApp - ); - }, [initialContext]); + isLensEqual: isLensEqualWrapper, + }); const indexPatternService = useMemo( () => @@ -471,35 +399,12 @@ export function App({ [dataViews, uiActions, http, notifications, uiSettings, initialContext, dispatch] ); - // remember latest URL based on the configuration - // url_panel_content has a similar logic - const shareURLCache = useRef({ params: '', url: '' }); - - const shortUrlService = useCallback( - async (params: LensAppLocatorParams) => { - const cacheKey = JSON.stringify(params); - if (shareURLCache.current.params === cacheKey) { - return shareURLCache.current.url; - } - if (locator && shortUrls) { - // This is a stripped down version of what the share URL plugin is doing - const shortUrl = await shortUrls.createWithLocator({ locator, params }); - const absoluteShortUrl = await shortUrl.locator.getUrl(shortUrl.params, { absolute: true }); - shareURLCache.current = { params: cacheKey, url: absoluteShortUrl }; - return absoluteShortUrl; - } - return ''; - }, - [locator, shortUrls] - ); + const shortUrlService = useShortUrlService(locator, share); const isManaged = useLensSelector(selectIsManaged); const returnToOriginSwitchLabelForContext = - initialContext && - 'isEmbeddable' in initialContext && - initialContext.isEmbeddable && - !persistedDoc + isFromLegacyEditorEmbeddable && !persistedDoc ? i18n.translate('xpack.lens.app.replacePanel', { defaultMessage: 'Replace panel on {originatingApp}', values: { @@ -547,16 +452,7 @@ export function App({ title={persistedDoc?.title} lensInspector={lensInspector} currentDoc={currentDoc} - isCurrentStateDirty={ - !isLensEqual( - persistedDoc, - lastKnownDoc, - data.query.filterManager.inject.bind(data.query.filterManager), - datasourceMap, - visualizationMap, - annotationGroups - ) - } + isCurrentStateDirty={!isLensEqualWrapper(persistedDoc)} goBackToOriginatingApp={goBackToOriginatingApp} contextOriginatingApp={contextOriginatingApp} initialContextIsEmbedded={initialContextIsEmbedded} @@ -612,13 +508,13 @@ export function App({ } /> )} - {isGoBackToVizEditorModalVisible && ( + {shouldShowGoBackToVizEditorModal && ( <EuiConfirmModal maxWidth={600} title={i18n.translate('xpack.lens.app.unsavedWorkTitle', { defaultMessage: 'Unsaved changes', })} - onCancel={() => setIsGoBackToVizEditorModalVisible(false)} + onCancel={closeGoBackToVizEditorModal} onConfirm={navigateToVizEditor} cancelButtonText={i18n.translate('xpack.lens.app.goBackModalCancelBtn', { defaultMessage: 'Cancel', diff --git a/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts b/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts new file mode 100644 index 000000000000..7dc4e8cfda78 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/app_helpers.test.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { renderHook, act } from '@testing-library/react-hooks'; +import faker from 'faker'; +import { UseNavigateBackToAppProps, useNavigateBackToApp } from './app_helpers'; +import { defaultDoc, makeDefaultServices } from '../mocks/services_mock'; +import { cloneDeep } from 'lodash'; +import { LensDocument } from '../persistence'; + +function getLensDocumentMock(someProps?: Partial<LensDocument>) { + return cloneDeep({ ...defaultDoc, ...someProps }); +} + +const getApplicationMock = () => makeDefaultServices().application; + +describe('App helpers', () => { + function getDefaultProps( + someProps?: Partial<UseNavigateBackToAppProps> + ): UseNavigateBackToAppProps { + return { + application: getApplicationMock(), + onAppLeave: jest.fn(), + legacyEditorAppName: faker.lorem.word(), + legacyEditorAppUrl: faker.internet.url(), + isLensEqual: jest.fn(() => true), + initialDocFromContext: undefined, + persistedDoc: getLensDocumentMock(), + ...someProps, + }; + } + describe('useNavigateBackToApp', () => { + it('navigates back to originating app if documents has not changed', () => { + const props = getDefaultProps(); + const { result } = renderHook(() => useNavigateBackToApp(props)); + + act(() => { + result.current.goBackToOriginatingApp(); + }); + + expect(props.application.navigateToApp).toHaveBeenCalledWith(props.legacyEditorAppName, { + path: props.legacyEditorAppUrl, + }); + }); + + it('shows modal if documents are not equal', () => { + const props = getDefaultProps({ isLensEqual: jest.fn().mockReturnValue(false) }); + const { result } = renderHook(() => useNavigateBackToApp(props)); + + act(() => { + result.current.goBackToOriginatingApp(); + }); + + expect(props.application.navigateToApp).not.toHaveBeenCalled(); + expect(result.current.shouldShowGoBackToVizEditorModal).toBe(true); + }); + + it('navigateToVizEditor hides modal and navigates back to Viz editor', () => { + const props = getDefaultProps(); + const { result } = renderHook(() => useNavigateBackToApp(props)); + + act(() => { + result.current.navigateToVizEditor(); + }); + + expect(result.current.shouldShowGoBackToVizEditorModal).toBe(false); + expect(props.application.navigateToApp).toHaveBeenCalledWith(props.legacyEditorAppName, { + path: props.legacyEditorAppUrl, + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/app_plugin/app_helpers.ts b/x-pack/plugins/lens/public/app_plugin/app_helpers.ts new file mode 100644 index 000000000000..4e240ac17159 --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/app_helpers.ts @@ -0,0 +1,207 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; +import { EuiBreadcrumb } from '@elastic/eui'; +import { AppLeaveHandler, ApplicationStart } from '@kbn/core-application-browser'; +import { ChromeStart } from '@kbn/core-chrome-browser'; +import { ServerlessPluginStart } from '@kbn/serverless/public'; +import { useRef, useCallback, useMemo, useState } from 'react'; +import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; +import { LensAppLocator, LensAppLocatorParams } from '../../common/locator/locator'; +import { VisualizeEditorContext } from '../types'; +import { LensDocument } from '../persistence'; +import { RedirectToOriginProps } from './types'; + +const VISUALIZE_APP_ID = 'visualize'; + +export function isLegacyEditorEmbeddable( + initialContext: VisualizeEditorContext | VisualizeFieldContext | undefined +): initialContext is VisualizeEditorContext { + return Boolean(initialContext && 'isEmbeddable' in initialContext && initialContext.isEmbeddable); +} + +export function getCurrentTitle( + persistedDoc: LensDocument | undefined, + isByValueMode: boolean, + initialContext: VisualizeEditorContext | VisualizeFieldContext | undefined +) { + if (persistedDoc) { + if (isByValueMode) { + return i18n.translate('xpack.lens.breadcrumbsByValue', { + defaultMessage: 'Edit visualization', + }); + } + if (persistedDoc.title) { + return persistedDoc.title; + } + } + if (!persistedDoc?.title && isLegacyEditorEmbeddable(initialContext)) { + return i18n.translate('xpack.lens.breadcrumbsEditInLensFromDashboard', { + defaultMessage: 'Converting {title} visualization', + values: { + title: initialContext.title ? `"${initialContext.title}"` : initialContext.visTypeTitle, + }, + }); + } + return i18n.translate('xpack.lens.breadcrumbsCreate', { + defaultMessage: 'Create', + }); +} + +export function setBreadcrumbsTitle( + { + application, + serverless, + chrome, + }: { + application: ApplicationStart; + serverless: ServerlessPluginStart | undefined; + chrome: ChromeStart; + }, + { + isByValueMode, + originatingAppName, + redirectToOrigin, + isFromLegacyEditor, + currentDocTitle, + }: { + isByValueMode: boolean; + originatingAppName: string | undefined; + redirectToOrigin: ((props?: RedirectToOriginProps | undefined) => void) | undefined; + isFromLegacyEditor: boolean; + currentDocTitle: string; + } +) { + const breadcrumbs: EuiBreadcrumb[] = []; + if (isFromLegacyEditor && originatingAppName && redirectToOrigin) { + breadcrumbs.push({ + onClick: () => { + redirectToOrigin(); + }, + text: originatingAppName, + }); + } + if (!isByValueMode) { + breadcrumbs.push({ + href: application.getUrlForApp(VISUALIZE_APP_ID), + onClick: (e) => { + application.navigateToApp(VISUALIZE_APP_ID, { path: '/' }); + e.preventDefault(); + }, + text: i18n.translate('xpack.lens.breadcrumbsTitle', { + defaultMessage: 'Visualize Library', + }), + }); + } + + const currentDocBreadcrumb: EuiBreadcrumb = { text: currentDocTitle }; + breadcrumbs.push(currentDocBreadcrumb); + if (serverless?.setBreadcrumbs) { + // TODO: https://github.com/elastic/kibana/issues/163488 + // for now, serverless breadcrumbs only set the title, + // the rest of the breadcrumbs are handled by the serverless navigation + // the serverless navigation is not yet aware of the byValue/originatingApp context + serverless.setBreadcrumbs(currentDocBreadcrumb); + } else { + chrome.setBreadcrumbs(breadcrumbs); + } +} + +export function useShortUrlService( + locator: LensAppLocator | undefined, + share: SharePublicStart | undefined +) { + const shortUrls = useMemo(() => share?.url.shortUrls.get(null), [share]); + // remember latest URL based on the configuration + // url_panel_content has a similar logic + const shareURLCache = useRef({ params: '', url: '' }); + + return useCallback( + async (params: LensAppLocatorParams) => { + const cacheKey = JSON.stringify(params); + if (shareURLCache.current.params === cacheKey) { + return shareURLCache.current.url; + } + if (locator && shortUrls) { + // This is a stripped down version of what the share URL plugin is doing + const shortUrl = await shortUrls.createWithLocator({ locator, params }); + const absoluteShortUrl = await shortUrl.locator.getUrl(shortUrl.params, { absolute: true }); + shareURLCache.current = { params: cacheKey, url: absoluteShortUrl }; + return absoluteShortUrl; + } + return ''; + }, + [locator, shortUrls] + ); +} + +export interface UseNavigateBackToAppProps { + application: ApplicationStart; + onAppLeave: (handler: AppLeaveHandler) => void; + legacyEditorAppName: string | undefined; + legacyEditorAppUrl: string | undefined; + initialDocFromContext: LensDocument | undefined; + persistedDoc: LensDocument | undefined; + isLensEqual: (refDoc: LensDocument | undefined) => boolean; +} + +export function useNavigateBackToApp({ + application, + onAppLeave, + legacyEditorAppName, + legacyEditorAppUrl, + initialDocFromContext, + persistedDoc, + isLensEqual, +}: UseNavigateBackToAppProps) { + const [shouldShowGoBackToVizEditorModal, setIsGoBackToVizEditorModalVisible] = useState(false); + /** Shared logic to navigate back to the originating viz editor app */ + const navigateBackToVizEditor = useCallback(() => { + if (legacyEditorAppUrl) { + onAppLeave((actions) => { + return actions.default(); + }); + application.navigateToApp(legacyEditorAppName || VISUALIZE_APP_ID, { + path: legacyEditorAppUrl, + }); + } + }, [application, legacyEditorAppName, legacyEditorAppUrl, onAppLeave]); + + // if users comes to Lens from the Viz editor, they should have the option to navigate back + // used for TopNavMenu + const goBackToOriginatingApp = useCallback(() => { + if (legacyEditorAppUrl) { + if ([initialDocFromContext, persistedDoc].some(isLensEqual)) { + navigateBackToVizEditor(); + } else { + setIsGoBackToVizEditorModalVisible(true); + } + } + }, [ + legacyEditorAppUrl, + initialDocFromContext, + persistedDoc, + isLensEqual, + navigateBackToVizEditor, + setIsGoBackToVizEditorModalVisible, + ]); + + // Used for Saving Modal + const navigateToVizEditor = useCallback(() => { + setIsGoBackToVizEditorModalVisible(false); + navigateBackToVizEditor(); + }, [navigateBackToVizEditor, setIsGoBackToVizEditorModalVisible]); + + return { + shouldShowGoBackToVizEditorModal, + goBackToOriginatingApp, + navigateToVizEditor, + closeGoBackToVizEditorModal: () => setIsGoBackToVizEditorModalVisible(false), + }; +} diff --git a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx index 1afa1974de35..a470cf41cf83 100644 --- a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.test.tsx @@ -15,9 +15,12 @@ import { UserMessageGetterProps, filterAndSortUserMessages, getApplicationUserMessages, + handleMessageOverwriteFromConsumer, } from './get_application_user_messages'; import { cleanup, render, screen } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n-react'; +import { FIELD_NOT_FOUND, FIELD_WRONG_TYPE } from '../user_messages_ids'; +import { LensPublicCallbacks } from '../react_embeddable/types'; import { getLongMessage } from '../user_messages_utils'; jest.mock('@kbn/shared-ux-link-redirect-app', () => { @@ -388,4 +391,100 @@ describe('filtering user messages', () => { ] `); }); + + describe('override messages with custom callback', () => { + it('should override embeddableBadge message', async () => { + const getBadgeMessage = jest.fn( + (): ReturnType<NonNullable<LensPublicCallbacks['onBeforeBadgesRender']>> => [ + { + uniqueId: FIELD_NOT_FOUND, + severity: 'warning', + fixableInEditor: true, + displayLocations: [ + { id: 'embeddableBadge' }, + { id: 'dimensionButton', dimensionId: '1' }, + ], + longMessage: 'custom', + shortMessage: '', + hidePopoverIcon: true, + }, + ] + ); + + expect( + handleMessageOverwriteFromConsumer( + [ + { + uniqueId: FIELD_NOT_FOUND, + severity: 'error', + fixableInEditor: true, + displayLocations: [ + { id: 'embeddableBadge' }, + { id: 'dimensionButton', dimensionId: '1' }, + ], + longMessage: 'original', + shortMessage: '', + }, + { + uniqueId: FIELD_WRONG_TYPE, + severity: 'error', + fixableInEditor: true, + displayLocations: [{ id: 'visualization' }], + longMessage: 'original', + shortMessage: '', + }, + ], + getBadgeMessage + ) + ).toEqual( + expect.arrayContaining([ + { + uniqueId: FIELD_WRONG_TYPE, + severity: 'error', + fixableInEditor: true, + displayLocations: [{ id: 'visualization' }], + longMessage: 'original', + shortMessage: '', + }, + { + uniqueId: FIELD_NOT_FOUND, + severity: 'warning', + fixableInEditor: true, + displayLocations: [ + { id: 'embeddableBadge' }, + { id: 'dimensionButton', dimensionId: '1' }, + ], + longMessage: 'custom', + shortMessage: '', + hidePopoverIcon: true, + }, + ]) + ); + }); + + it('should not override embeddableBadge message if callback is not provided', async () => { + const messages: UserMessage[] = [ + { + uniqueId: FIELD_NOT_FOUND, + severity: 'error', + fixableInEditor: true, + displayLocations: [ + { id: 'embeddableBadge' }, + { id: 'dimensionButton', dimensionId: '1' }, + ], + longMessage: 'original', + shortMessage: '', + }, + { + uniqueId: FIELD_WRONG_TYPE, + severity: 'error', + fixableInEditor: true, + displayLocations: [{ id: 'visualization' }], + longMessage: 'original', + shortMessage: '', + }, + ]; + expect(handleMessageOverwriteFromConsumer(messages)).toEqual(messages); + }); + }); }); diff --git a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx index d7d04a837e08..b2755a411e71 100644 --- a/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx +++ b/x-pack/plugins/lens/public/app_plugin/get_application_user_messages.tsx @@ -11,6 +11,7 @@ import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { FormattedMessage } from '@kbn/i18n-react'; import type { CoreStart } from '@kbn/core/public'; import { Dispatch } from '@reduxjs/toolkit'; +import { partition } from 'lodash'; import { updateDatasourceState, type DataViewsState, @@ -35,6 +36,8 @@ import { EDITOR_UNKNOWN_DATASOURCE_TYPE, EDITOR_UNKNOWN_VIS_TYPE, } from '../user_messages_ids'; +import { nonNullable } from '../utils'; +import type { LensPublicCallbacks } from '../react_embeddable/types'; export interface UserMessageGetterProps { visualizationType: string | null | undefined; @@ -203,21 +206,38 @@ function getMissingIndexPatternsErrors( ]; } +export const handleMessageOverwriteFromConsumer = ( + messages: UserMessage[], + onBeforeBadgesRender?: LensPublicCallbacks['onBeforeBadgesRender'] +) => { + if (onBeforeBadgesRender) { + // we need something else to better identify those errors + const [messagesToHandle, originalMessages] = partition(messages, (message) => + message.displayLocations.some((location) => location.id === 'embeddableBadge') + ); + + if (messagesToHandle.length > 0) { + const customBadgeMessages = onBeforeBadgesRender(messagesToHandle); + return originalMessages.concat(customBadgeMessages); + } + } + + return messages; +}; + export const filterAndSortUserMessages = ( userMessages: UserMessage[], locationId?: UserMessagesDisplayLocationId | UserMessagesDisplayLocationId[], { dimensionId, severity }: UserMessageFilters = {} ) => { - const locationIds = Array.isArray(locationId) - ? locationId - : typeof locationId === 'string' - ? [locationId] - : []; + const locationIds = new Set( + (Array.isArray(locationId) ? locationId : [locationId]).filter(nonNullable) + ); const filteredMessages = userMessages.filter((message) => { - if (locationIds.length) { + if (locationIds.size) { const hasMatch = message.displayLocations.some((location) => { - if (!locationIds.includes(location.id)) { + if (!locationIds.has(location.id)) { return false; } @@ -229,11 +249,7 @@ export const filterAndSortUserMessages = ( } } - if (severity && message.severity !== severity) { - return false; - } - - return true; + return !severity || message.severity === severity; }); return filteredMessages.sort(bySeverity); @@ -329,7 +345,7 @@ export const useApplicationUserMessages = ({ const getUserMessages: UserMessagesGetter = (locationId, filterArgs) => filterAndSortUserMessages( - [...userMessages, ...Object.values(additionalUserMessages)], + userMessages.concat(Object.values(additionalUserMessages)), locationId, filterArgs ?? {} ); diff --git a/x-pack/plugins/lens/public/app_plugin/lens_document_equality.test.ts b/x-pack/plugins/lens/public/app_plugin/lens_document_equality.test.ts index babde51e39f2..8371a77793ea 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_document_equality.test.ts +++ b/x-pack/plugins/lens/public/app_plugin/lens_document_equality.test.ts @@ -7,7 +7,7 @@ import { Filter, FilterStateStore } from '@kbn/es-query'; import { isLensEqual } from './lens_document_equality'; -import { Document } from '../persistence/saved_object_store'; +import { LensDocument } from '../persistence/saved_object_store'; import { AnnotationGroups, Datasource, @@ -18,7 +18,7 @@ import { const visualizationType = 'lnsSomeVis'; -const defaultDoc: Document = { +const defaultDoc: LensDocument = { title: 'some-title', visualizationType, state: { @@ -105,7 +105,7 @@ describe('lens document equality', () => { expect( isLensEqual( undefined, - {} as Document, + {} as LensDocument, mockInjectFilterReferences, {}, mockVisualizationMap, @@ -114,7 +114,7 @@ describe('lens document equality', () => { ).toBeFalsy(); expect( isLensEqual( - {} as Document, + {} as LensDocument, undefined, mockInjectFilterReferences, {}, diff --git a/x-pack/plugins/lens/public/app_plugin/lens_document_equality.ts b/x-pack/plugins/lens/public/app_plugin/lens_document_equality.ts index 60316802ca5e..4fc97882fd92 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_document_equality.ts +++ b/x-pack/plugins/lens/public/app_plugin/lens_document_equality.ts @@ -7,7 +7,7 @@ import { isEqual, intersection, union } from 'lodash'; import { FilterManager } from '@kbn/data-plugin/public'; -import { Document } from '../persistence/saved_object_store'; +import { LensDocument } from '../persistence/saved_object_store'; import { AnnotationGroups, DatasourceMap, VisualizationMap } from '../types'; import { removePinnedFilters } from './save_modal_container'; @@ -15,8 +15,8 @@ const removeNonSerializable = (obj: Parameters<JSON['stringify']>[0]) => JSON.parse(JSON.stringify(obj)); export const isLensEqual = ( - doc1In: Document | undefined, - doc2In: Document | undefined, + doc1In: LensDocument | undefined, + doc2In: LensDocument | undefined, injectFilterReferences: FilterManager['inject'], datasourceMap: DatasourceMap, visualizationMap: VisualizationMap, @@ -54,6 +54,7 @@ export const isLensEqual = ( } })() : isEqual(doc1.state.visualization, doc2.state.visualization); + if (!visualizationStateIsEqual) { return false; } @@ -68,16 +69,14 @@ export const isLensEqual = ( if (datasourcesEqual) { // equal so far, so actually check - datasourcesEqual = availableDatasourceTypes1 - .map((type) => - datasourceMap[type].isEqual( - doc1.state.datasourceStates[type], - [...doc1.references, ...(doc1.state.internalReferences || [])], - doc2.state.datasourceStates[type], - [...doc2.references, ...(doc2.state.internalReferences || [])] - ) + datasourcesEqual = availableDatasourceTypes1.every((type) => + datasourceMap[type].isEqual( + doc1.state.datasourceStates[type], + doc1.references.concat(doc1.state.internalReferences || []), + doc2.state.datasourceStates[type], + doc2.references.concat(doc2.state.internalReferences || []) ) - .every((res) => res); + ); } if (!datasourcesEqual) { @@ -96,7 +95,7 @@ export const isLensEqual = ( function injectDocFilterReferences( injectFilterReferences: FilterManager['inject'], - doc?: Document + doc?: LensDocument ) { if (!doc) return undefined; return { diff --git a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx index 399c849b6ebc..cf76df44eefc 100644 --- a/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx +++ b/x-pack/plugins/lens/public/app_plugin/lens_top_nav.tsx @@ -37,7 +37,6 @@ import { } from '../utils'; import { combineQueryAndFilters, getLayerMetaInfo } from './show_underlying_data'; import { changeIndexPattern } from '../state_management/lens_slice'; -import { LensByReferenceInput } from '../embeddable'; import { DEFAULT_LENS_LAYOUT_DIMENSIONS, getShareURL } from './share_action'; import { getDatasourceLayers } from '../state_management/utils'; @@ -291,7 +290,6 @@ export const LensTopNavMenu = ({ navigation, uiSettings, application, - attributeService, share, dataViewFieldEditor, dataViewEditor, @@ -529,11 +527,9 @@ export const LensTopNavMenu = ({ const topNavConfig = useMemo(() => { const showReplaceInDashboard = - initialContext?.originatingApp === 'dashboards' && - !(initialInput as LensByReferenceInput)?.savedObjectId; + initialContext?.originatingApp === 'dashboards' && !initialInput?.savedObjectId; const showReplaceInCanvas = - initialContext?.originatingApp === 'canvas' && - !(initialInput as LensByReferenceInput)?.savedObjectId; + initialContext?.originatingApp === 'canvas' && !initialInput?.savedObjectId; const contextFromEmbeddable = initialContext && 'isEmbeddable' in initialContext && initialContext.isEmbeddable; @@ -690,8 +686,7 @@ export const LensTopNavMenu = ({ panelTimeRange: contextFromEmbeddable ? initialContext.panelTimeRange : undefined, }, { - saveToLibrary: - (initialInput && attributeService.inputIsRefType(initialInput)) ?? false, + saveToLibrary: Boolean(initialInput?.savedObjectId), } ); } @@ -801,7 +796,6 @@ export const LensTopNavMenu = ({ defaultLensTitle, onAppLeave, runSave, - attributeService, setIsSaveModalVisible, goBackToOriginatingApp, redirectToOrigin, diff --git a/x-pack/plugins/lens/public/app_plugin/mounter.tsx b/x-pack/plugins/lens/public/app_plugin/mounter.tsx index 7f91943eade3..c431f48f0c40 100644 --- a/x-pack/plugins/lens/public/app_plugin/mounter.tsx +++ b/x-pack/plugins/lens/public/app_plugin/mounter.tsx @@ -33,12 +33,7 @@ import { EditorFrameStart, LensTopNavMenuEntryGenerator, VisualizeEditorContext import { addHelpMenuToAppChrome } from '../help_menu_util'; import { LensPluginStartDependencies } from '../plugin'; import { LENS_EMBEDDABLE_TYPE, LENS_EDIT_BY_VALUE, APP_ID } from '../../common/constants'; -import { - LensEmbeddableInput, - LensByReferenceInput, - LensByValueInput, -} from '../embeddable/embeddable'; -import { LensAttributeService } from '../lens_attribute_service'; +import { LensAttributesService } from '../lens_attribute_service'; import { LensAppServices, RedirectToOriginProps, HistoryLocationState } from './types'; import { makeConfigureStore, @@ -55,6 +50,7 @@ import { MainHistoryLocationState, } from '../../common/locator/locator'; import { SavedObjectIndexStore } from '../persistence'; +import { LensSerializedState } from '../react_embeddable/types'; function getInitialContext(history: AppMountParameters['history']) { const historyLocationState = history.location.state as @@ -83,7 +79,7 @@ function getInitialContext(history: AppMountParameters['history']) { export async function getLensServices( coreStart: CoreStart, startDependencies: LensPluginStartDependencies, - attributeService: LensAttributeService, + attributeService: LensAttributesService, initialContext?: VisualizeFieldContext | VisualizeEditorContext, locator?: LensAppLocator ): Promise<LensAppServices> { @@ -146,7 +142,7 @@ export async function mountApp( params: AppMountParameters, mountProps: { createEditorFrame: EditorFrameStart['createInstance']; - attributeService: LensAttributeService; + attributeService: LensAttributesService; topNavMenuEntryGenerators: LensTopNavMenuEntryGenerator[]; locator?: LensAppLocator; } @@ -188,12 +184,12 @@ export async function mountApp( i18n.translate('xpack.lens.pageTitle', { defaultMessage: 'Lens' }) ); - const getInitialInput = (id?: string, editByValue?: boolean): LensEmbeddableInput | undefined => { + const getInitialInput = (id?: string, editByValue?: boolean): LensSerializedState | undefined => { if (editByValue) { - return embeddableEditorIncomingState?.valueInput as LensByValueInput; + return embeddableEditorIncomingState?.valueInput as LensSerializedState; } if (id) { - return { savedObjectId: id } as LensByReferenceInput; + return { savedObjectId: id } as LensSerializedState; } }; @@ -220,14 +216,14 @@ export async function mountApp( if (initialContext && 'embeddableId' in initialContext) { embeddableId = initialContext.embeddableId; } - if (stateTransfer && props?.input) { - const { input, isCopied } = props; + if (stateTransfer && props?.state) { + const { state, isCopied } = props; stateTransfer.navigateToWithEmbeddablePackage(mergedOriginatingApp, { path: embeddableEditorIncomingState?.originatingPath, state: { embeddableId: isCopied ? undefined : embeddableId, type: LENS_EMBEDDABLE_TYPE, - input, + input: { ...state, savedObject: state.savedObjectId }, searchSessionId: data.search.session.getSessionId(), }, }); @@ -426,7 +422,7 @@ export async function mountApp( return () => { data.search.session.clear(); unmountComponentAtNode(params.element); - lensServices.inspector.close(); + lensServices.inspector.closeInspector(); unlistenParentHistory(); lensStore.dispatch(navigateAway()); stateTransfer.clearEditorState?.(APP_ID); diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx b/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx new file mode 100644 index 000000000000..987b320b3abf --- /dev/null +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container.test.tsx @@ -0,0 +1,407 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SaveProps } from './app'; +import { type SaveVisualizationProps, runSaveLensVisualization } from './save_modal_container'; +import { defaultDoc, makeDefaultServices } from '../mocks'; +import faker from 'faker'; +import { makeAttributeService } from '../mocks/services_mock'; + +jest.mock('../persistence/saved_objects_utils/check_for_duplicate_title', () => ({ + checkForDuplicateTitle: jest.fn(async () => false), +})); + +describe('runSaveLensVisualization', () => { + // Need to call reset here as makeDefaultServices() reuses some mocks from core + const resetMocks = () => + beforeEach(() => { + jest.resetAllMocks(); + }); + + function getDefaultArgs( + servicesOverrides: Partial<SaveVisualizationProps> = {}, + { saveToLibrary, ...propsOverrides }: Partial<SaveProps & { saveToLibrary: boolean }> = {} + ) { + const redirectToOrigin = jest.fn(); + const redirectTo = jest.fn(); + const onAppLeave = jest.fn(); + const switchDatasource = jest.fn(); + const props: SaveVisualizationProps = { + ...makeDefaultServices(), + // start with both the initial input and lastKnownDoc synced + lastKnownDoc: defaultDoc, + initialInput: { attributes: defaultDoc, savedObjectId: defaultDoc.savedObjectId }, + redirectToOrigin, + redirectTo, + onAppLeave, + switchDatasource, + ...servicesOverrides, + }; + const saveProps: SaveProps = { + newTitle: faker.lorem.word(), + newDescription: faker.lorem.sentence(), + newTags: [faker.lorem.word(), faker.lorem.word()], + isTitleDuplicateConfirmed: false, + returnToOrigin: false, + dashboardId: undefined, + newCopyOnSave: false, + ...propsOverrides, + }; + const options = { + saveToLibrary: Boolean(saveToLibrary), + }; + + return { + props, + saveProps, + options, + // convenience shortcuts + /** + * This function will be called when a fresh chart is saved + * and in the modal the user chooses to add the chart into a specific dashboard. Make sure to pass the "dashboardId" prop as well to simulate this scenario. + * This is used to test indirectly the redirectToDashboard call + */ + redirectToDashboardFn: props.stateTransfer.navigateToWithEmbeddablePackage, + /** + * This function will be called before reloading the editor after saving a a new document/new copy of the document + */ + cleanupEditor: props.stateTransfer.clearEditorState, + saveToLibraryFn: props.attributeService.saveToLibrary, + toasts: props.notifications.toasts, + }; + } + + describe('from dashboard', () => { + describe('as by value', () => { + const defaultByValueDoc = { ...defaultDoc, savedObjectId: undefined }; + + describe('Save and return', () => { + resetMocks(); + + // Test the "Save and return" button + it('should get back to dashboard', async () => { + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn } = + getDefaultArgs( + { + lastKnownDoc: defaultByValueDoc, + initialInput: { attributes: defaultByValueDoc }, + }, + { returnToOrigin: true } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(props.onAppLeave).toHaveBeenCalled(); + expect(props.redirectToOrigin).toHaveBeenCalled(); + + // callback not called + expect(redirectToDashboardFn).not.toHaveBeenCalled(); + expect(saveToLibraryFn).not.toHaveBeenCalled(); + expect(props.notifications.toasts.addSuccess).not.toHaveBeenCalled(); + }); + + it('should get back to dashboard preserving the original panel settings', async () => { + const { props, saveProps, options } = getDefaultArgs( + { + lastKnownDoc: defaultByValueDoc, + initialInput: { + attributes: defaultByValueDoc, + title: 'blah', + timeRange: { from: 'now-7d', to: 'now' }, + }, + }, + { returnToOrigin: true } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(props.onAppLeave).toHaveBeenCalled(); + expect(props.redirectToOrigin).toHaveBeenCalledWith( + expect.objectContaining({ + state: expect.objectContaining({ + title: 'blah', + timeRange: { from: 'now-7d', to: 'now' }, + }), + }) + ); + }); + }); + + describe('Save to library', () => { + resetMocks(); + + // Test the "Save to library" flow + it('should save to library without redirect', async () => { + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn } = + getDefaultArgs( + { + lastKnownDoc: defaultByValueDoc, + initialInput: { attributes: defaultByValueDoc }, + }, + { + saveToLibrary: true, + // do not get back at dashboard once saved + returnToOrigin: false, + } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(saveToLibraryFn).toHaveBeenCalled(); + expect(props.notifications.toasts.addSuccess).toHaveBeenCalled(); + + // not called + expect(props.onAppLeave).not.toHaveBeenCalled(); + expect(props.redirectToOrigin).not.toHaveBeenCalled(); + expect(redirectToDashboardFn).not.toHaveBeenCalled(); + }); + + it('should save to library and redirect', async () => { + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn } = + getDefaultArgs( + { + lastKnownDoc: defaultByValueDoc, + initialInput: { attributes: defaultByValueDoc }, + }, + { + saveToLibrary: true, + // return to dashboard once saved + returnToOrigin: true, + } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(props.onAppLeave).toHaveBeenCalled(); + expect(props.redirectToOrigin).toHaveBeenCalled(); + expect(saveToLibraryFn).toHaveBeenCalled(); + + // not called + expect(redirectToDashboardFn).not.toHaveBeenCalled(); + expect(props.notifications.toasts.addSuccess).not.toHaveBeenCalled(); + }); + }); + }); + + describe('as by reference', () => { + resetMocks(); + // There are 4 possibilities here: + // save the current document overwriting the existing one + it('should overwrite and show a success toast', async () => { + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn, toasts } = + getDefaultArgs( + { + // defaultDoc is by reference + }, + { newCopyOnSave: false, saveToLibrary: true } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(saveToLibraryFn).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + defaultDoc.savedObjectId + ); + expect(toasts.addSuccess).toHaveBeenCalled(); + + // not called + expect(props.onAppLeave).not.toHaveBeenCalled(); + expect(props.redirectToOrigin).not.toHaveBeenCalled(); + expect(redirectToDashboardFn).not.toHaveBeenCalled(); + }); + + // save the current document as a new by-ref copy in the library + it('should save as a new copy and show a success toast', async () => { + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn, toasts } = + getDefaultArgs( + { + // defaultDoc is by reference + }, + { newCopyOnSave: true, saveToLibrary: true } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(saveToLibraryFn).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + undefined + ); + expect(toasts.addSuccess).toHaveBeenCalled(); + + // not called + expect(props.onAppLeave).not.toHaveBeenCalled(); + expect(props.redirectToOrigin).not.toHaveBeenCalled(); + expect(redirectToDashboardFn).not.toHaveBeenCalled(); + }); + // save the current document as a new by-value copy and add it to a dashboard + it('should save as a new by-value copy and redirect to the dashboard', async () => { + const dashboardId = faker.random.uuid(); + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn, toasts } = + getDefaultArgs( + { + // defaultDoc is by reference + }, + { newCopyOnSave: true, saveToLibrary: false, dashboardId } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(props.onAppLeave).toHaveBeenCalled(); + + // not called + expect(props.redirectToOrigin).not.toHaveBeenCalled(); + expect(redirectToDashboardFn).toHaveBeenCalledWith( + 'dashboards', + // make sure the new savedObject id is removed from the new input + expect.objectContaining({ + state: expect.objectContaining({ + input: expect.objectContaining({ savedObjectId: undefined }), + }), + }) + ); + expect(saveToLibraryFn).not.toHaveBeenCalled(); + expect(toasts.addSuccess).not.toHaveBeenCalled(); + }); + + // save the current document as a new by-ref copy and add it to a dashboard + it('should save as a new by-ref copy and redirect to the dashboard', async () => { + const dashboardId = faker.random.uuid(); + const { props, saveProps, options, redirectToDashboardFn, saveToLibraryFn, toasts } = + getDefaultArgs( + { + // defaultDoc is by reference + }, + { newCopyOnSave: true, saveToLibrary: true, dashboardId } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(props.onAppLeave).toHaveBeenCalled(); + expect(redirectToDashboardFn).toHaveBeenCalledWith( + 'dashboards', + // make sure the new savedObject id is passed with the new input + expect.objectContaining({ + state: expect.objectContaining({ + input: expect.objectContaining({ savedObjectId: '1234' }), + }), + }) + ); + expect(saveToLibraryFn).toHaveBeenCalled(); + + // not called + expect(props.redirectToOrigin).not.toHaveBeenCalled(); + expect(toasts.addSuccess).not.toHaveBeenCalled(); + }); + }); + }); + + describe('fresh editor start', () => { + resetMocks(); + + it('should reload the editor if it has been saved as new copy', async () => { + const { props, saveProps, options, saveToLibraryFn, cleanupEditor, toasts } = getDefaultArgs( + {}, + { + saveToLibrary: true, + newCopyOnSave: true, + } + ); + const result = await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(saveToLibraryFn).toHaveBeenCalled(); + expect(toasts.addSuccess).toHaveBeenCalled(); + expect(cleanupEditor).toHaveBeenCalled(); + expect(props.redirectTo).toHaveBeenCalledWith(defaultDoc.savedObjectId); + expect(result?.isLinkedToOriginatingApp).toBeFalsy(); + + // not called + expect(props.onAppLeave).not.toHaveBeenCalled(); + }); + + it('should show a notification toast and reload as first save of the document', async () => { + const { props, saveProps, options, saveToLibraryFn, toasts } = getDefaultArgs( + { + lastKnownDoc: { ...defaultDoc, savedObjectId: undefined }, + persistedDoc: undefined, + initialInput: undefined, + }, + { saveToLibrary: true } + ); + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(saveToLibraryFn).toHaveBeenCalled(); + expect(toasts.addSuccess).toHaveBeenCalled(); + expect(props.redirectTo).toHaveBeenCalled(); + + // not called + expect(props.application.navigateToApp).not.toHaveBeenCalledWith('lens', { path: '/' }); + expect(props.redirectToOrigin).not.toHaveBeenCalled(); + }); + + it('should throw if something goes wrong when saving', async () => { + const attributeServiceMock = { + ...makeAttributeService(defaultDoc), + saveToLibrary: jest.fn().mockImplementation(() => Promise.reject(Error('failed to save'))), + }; + const { props, saveProps, options, toasts } = getDefaultArgs( + { + lastKnownDoc: { ...defaultDoc, savedObjectId: undefined }, + attributeService: attributeServiceMock, + }, + { saveToLibrary: true } + ); + try { + await runSaveLensVisualization(props, saveProps, options); + } catch (error) { + expect(toasts.addDanger).toHaveBeenCalled(); + expect(toasts.addSuccess).not.toHaveBeenCalled(); + expect(error.message).toEqual('failed to save'); + } + }); + }); + + // While this is technically a virtual option as for now, it's still worth testing to not break it in the future + describe('Textbased version', () => { + resetMocks(); + + it('should have a dedicated flow for textbased saving by-ref', async () => { + // simulate a new save + const attributeServiceMock = makeAttributeService({ + ...defaultDoc, + savedObjectId: faker.random.uuid(), + }); + + const { props, saveProps, options, saveToLibraryFn, cleanupEditor } = getDefaultArgs( + { + textBasedLanguageSave: true, + attributeService: attributeServiceMock, + // give a document without a savedObjectId + lastKnownDoc: { ...defaultDoc, savedObjectId: undefined }, + persistedDoc: undefined, + // simulate a fresh start in the editor + initialInput: undefined, + }, + { + saveToLibrary: true, + } + ); + + await runSaveLensVisualization(props, saveProps, options); + + // callback called + expect(saveToLibraryFn).toHaveBeenCalled(); + expect(cleanupEditor).toHaveBeenCalled(); + expect(props.switchDatasource).toHaveBeenCalled(); + expect(props.redirectTo).not.toHaveBeenCalled(); + expect(props.application.navigateToApp).toHaveBeenCalledWith('lens', { path: '/' }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx b/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx index 354bf0888259..f1ccacc37db5 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container.tsx @@ -11,25 +11,29 @@ import { isFilterPinned } from '@kbn/es-query'; import { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; import type { SavedObjectReference } from '@kbn/core/public'; import { EuiLoadingSpinner } from '@elastic/eui'; +import { omit } from 'lodash'; import { SaveModal } from './save_modal'; import type { LensAppProps, LensAppServices } from './types'; import type { SaveProps } from './app'; -import { Document, checkForDuplicateTitle, SavedObjectIndexStore } from '../persistence'; -import type { LensByReferenceInput, LensEmbeddableInput } from '../embeddable'; +import { checkForDuplicateTitle, SavedObjectIndexStore, LensDocument } from '../persistence'; import { APP_ID, getFullPath } from '../../common/constants'; import type { LensAppState } from '../state_management'; -import { getPersisted } from '../state_management/init_middleware/load_initial'; -import { VisualizeEditorContext } from '../types'; +import { getFromPreloaded } from '../state_management/init_middleware/load_initial'; +import { Simplify, VisualizeEditorContext } from '../types'; import { redirectToDashboard } from './save_modal_container_helpers'; +import { LensSerializedState } from '../react_embeddable/types'; +import { isLegacyEditorEmbeddable } from './app_helpers'; -type ExtraProps = Pick<LensAppProps, 'initialInput'> & - Partial<Pick<LensAppProps, 'redirectToOrigin' | 'redirectTo' | 'onAppLeave'>>; +type ExtraProps = Simplify< + Pick<LensAppProps, 'initialInput'> & + Partial<Pick<LensAppProps, 'redirectToOrigin' | 'redirectTo' | 'onAppLeave'>> +>; export type SaveModalContainerProps = { originatingApp?: string; getOriginatingPath?: (dashboardId: string) => string; - persistedDoc?: Document; - lastKnownDoc?: Document; + persistedDoc?: LensDocument; + lastKnownDoc?: LensDocument; returnToOriginSwitchLabel?: string; onClose: () => void; onSave?: (saveProps: SaveProps) => void; @@ -78,19 +82,14 @@ export function SaveModalContainer({ let description; let savedObjectId; const [initializing, setInitializing] = useState(true); - const [lastKnownDoc, setLastKnownDoc] = useState<Document | undefined>(initLastKnownDoc); + const [lastKnownDoc, setLastKnownDoc] = useState<LensDocument | undefined>(initLastKnownDoc); if (lastKnownDoc) { title = lastKnownDoc.title; description = lastKnownDoc.description; savedObjectId = lastKnownDoc.savedObjectId; } - if ( - !lastKnownDoc?.title && - initialContext && - 'isEmbeddable' in initialContext && - initialContext.isEmbeddable - ) { + if (!lastKnownDoc?.title && isLegacyEditorEmbeddable(initialContext)) { title = i18n.translate('xpack.lens.app.convertedLabel', { defaultMessage: '{title} (converted)', values: { @@ -109,7 +108,7 @@ export function SaveModalContainer({ let isMounted = true; if (initialInput) { - getPersisted({ + getFromPreloaded({ initialInput, lensServices, }) @@ -133,12 +132,13 @@ export function SaveModalContainer({ ? savedObjectsTagging.ui.getTagIdsFromReferences(persistedDoc.references) : []; - const runLensSave = (saveProps: SaveProps, options: { saveToLibrary: boolean }) => { + const runLensSave = async (saveProps: SaveProps, options: { saveToLibrary: boolean }) => { if (runSave) { // inside lens, we use the function that's passed to it - runSave(saveProps, options); - } else if (attributeService && lastKnownDoc) { - runSaveLensVisualization( + return runSave(saveProps, options); + } + if (attributeService && lastKnownDoc) { + await runSaveLensVisualization( { ...lensServices, lastKnownDoc, @@ -147,16 +147,14 @@ export function SaveModalContainer({ redirectToOrigin, originatingApp, getOriginatingPath, - getIsByValueMode: () => false, onAppLeave: () => {}, ...lensServices, }, saveProps, options - ).then(() => { - onSave?.(saveProps); - onClose(); - }); + ); + onSave?.(saveProps); + onClose(); } }; @@ -188,11 +186,24 @@ export function SaveModalContainer({ ); } +function fromDocumentToSerializedState( + doc: LensDocument, + panelSettings: Partial<LensSerializedState>, + originalInput?: LensAppProps['initialInput'] +): LensSerializedState { + return { + ...originalInput, + attributes: omit(doc, 'savedObjectId'), + savedObjectId: doc.savedObjectId, + ...panelSettings, + }; +} + const getDocToSave = ( - lastKnownDoc: Document, + lastKnownDoc: LensDocument, saveProps: SaveProps, references: SavedObjectReference[] -) => { +): LensDocument => { const docToSave = { ...removePinnedFilters(lastKnownDoc)!, references, @@ -209,11 +220,10 @@ const getDocToSave = ( return docToSave; }; -export const runSaveLensVisualization = async ( - props: { - lastKnownDoc?: Document; - getIsByValueMode: () => boolean; - persistedDoc?: Document; +export type SaveVisualizationProps = Simplify< + { + lastKnownDoc?: LensDocument; + persistedDoc?: LensDocument; originatingApp?: string; getOriginatingPath?: (dashboardId: string) => string; textBasedLanguageSave?: boolean; @@ -232,7 +242,11 @@ export const runSaveLensVisualization = async ( | 'stateTransfer' | 'attributeService' | 'savedObjectsTagging' - >, + > +>; + +export const runSaveLensVisualization = async ( + props: SaveVisualizationProps, saveProps: SaveProps, options: { saveToLibrary: boolean } ): Promise<Partial<LensAppState> | undefined> => { @@ -245,7 +259,6 @@ export const runSaveLensVisualization = async ( stateTransfer, attributeService, savedObjectsTagging, - getIsByValueMode, redirectToOrigin, onAppLeave, redirectTo, @@ -262,7 +275,7 @@ export const runSaveLensVisualization = async ( return; } - let references = lastKnownDoc.references; + let references = lastKnownDoc.references || initialInput?.attributes?.references; if (savedObjectsTagging) { const tagsIds = @@ -277,68 +290,90 @@ export const runSaveLensVisualization = async ( const docToSave = getDocToSave(lastKnownDoc, saveProps, references); - // Required to serialize filters in by value mode until - // https://github.com/elastic/kibana/issues/77588 is fixed - if (getIsByValueMode()) { - docToSave.state.filters.forEach((filter) => { - if (typeof filter.meta.value === 'function') { - delete filter.meta.value; - } - }); - } - const originalInput = saveProps.newCopyOnSave ? undefined : initialInput; - const originalSavedObjectId = (originalInput as LensByReferenceInput)?.savedObjectId; + const originalSavedObjectId = originalInput?.savedObjectId; if (options.saveToLibrary) { - try { - await checkForDuplicateTitle( - { - id: originalSavedObjectId, - title: docToSave.title, - displayName: i18n.translate('xpack.lens.app.saveModalType', { - defaultMessage: 'Lens visualization', - }), - lastSavedTitle: lastKnownDoc.title, - copyOnSave: saveProps.newCopyOnSave, - isTitleDuplicateConfirmed: saveProps.isTitleDuplicateConfirmed, - }, - saveProps.onTitleDuplicate, - { - client: savedObjectStore, - ...startServices, - } - ); - } catch (e) { - // ignore duplicate title failure, user notified in save modal - throw e; - } + // this is a lower level call that the Lens attribute service one + // @TODO: check if it's worth to replace it witht he attribute service one + await checkForDuplicateTitle( + { + id: originalSavedObjectId, + title: docToSave.title, + displayName: i18n.translate('xpack.lens.app.saveModalType', { + defaultMessage: 'Lens visualization', + }), + lastSavedTitle: lastKnownDoc.title, + copyOnSave: saveProps.newCopyOnSave, + isTitleDuplicateConfirmed: saveProps.isTitleDuplicateConfirmed, + }, + saveProps.onTitleDuplicate, + { + client: savedObjectStore, + ...startServices, + } + ); + // ignore duplicate title failure, user notified in save modal } + try { - let newInput = (await attributeService.wrapAttributes( + // wrap the doc into a serializable state + const newDoc = fromDocumentToSerializedState( docToSave, - options.saveToLibrary, + { + timeRange: saveProps.panelTimeRange ?? originalInput?.timeRange, + savedObjectId: options.saveToLibrary ? originalSavedObjectId : undefined, + }, originalInput - )) as LensEmbeddableInput; - if (saveProps.panelTimeRange) { - newInput = { - ...newInput, - timeRange: saveProps.panelTimeRange, - }; + ); + + let savedObjectId: string | undefined; + try { + savedObjectId = + newDoc.attributes && options.saveToLibrary + ? await attributeService.saveToLibrary( + newDoc.attributes, + newDoc.attributes.references || [], + originalSavedObjectId + ) + : undefined; + } catch (error) { + notifications.toasts.addDanger({ + title: i18n.translate('xpack.lens.app.saveVisualization.errorNotificationText', { + defaultMessage: `An error occurred while saving. Error: {errorMessage}`, + values: { + errorMessage: error.message, + }, + }), + }); + // trigger a reject to jump to the final catch clause + throw error; } - if (saveProps.returnToOrigin && redirectToOrigin) { + + const shouldNavigateBackToOrigin = saveProps.returnToOrigin && redirectToOrigin; + const hasRedirect = shouldNavigateBackToOrigin || saveProps.dashboardId; + + // if a redirect was set, prevent the validation on app leave + if (hasRedirect) { // disabling the validation on app leave because the document has been saved. onAppLeave?.((actions) => { return actions.default(); }); - redirectToOrigin({ input: newInput, isCopied: saveProps.newCopyOnSave }); - return; - } else if (saveProps.dashboardId) { - // disabling the validation on app leave because the document has been saved. - onAppLeave?.((actions) => { - return actions.default(); + } + + if (shouldNavigateBackToOrigin) { + redirectToOrigin({ + state: { ...newDoc, savedObjectId }, + isCopied: saveProps.newCopyOnSave, }); + return; + } + // should we make it more robust here and better check the context of the saving + // or keep the responsability of the consumer of the function to provide the right set + // of args here in case the user is within a by value chart AND want's to save it in the library + // without redirect? + if (saveProps.dashboardId) { redirectToDashboard({ - embeddableInput: newInput, + embeddableInput: { ...newDoc, savedObjectId }, dashboardId: saveProps.dashboardId, stateTransfer, originatingApp: props.originatingApp, @@ -356,15 +391,8 @@ export const runSaveLensVisualization = async ( }) ); - if ( - attributeService.inputIsRefType(newInput) && - newInput.savedObjectId !== originalSavedObjectId - ) { - chrome.recentlyAccessed.add( - getFullPath(newInput.savedObjectId), - docToSave.title, - newInput.savedObjectId - ); + if (savedObjectId && savedObjectId !== originalSavedObjectId) { + chrome.recentlyAccessed.add(getFullPath(savedObjectId), docToSave.title, savedObjectId); // remove editor state so the connection is still broken after reload stateTransfer.clearEditorState?.(APP_ID); @@ -372,18 +400,13 @@ export const runSaveLensVisualization = async ( switchDatasource?.(); application.navigateToApp('lens', { path: '/' }); } else { - redirectTo?.(newInput.savedObjectId); + redirectTo?.(savedObjectId); } return { isLinkedToOriginatingApp: false }; } - const newDoc = { - ...docToSave, - ...newInput, - }; - return { - persistedDoc: newDoc, + persistedDoc: newDoc.attributes, isLinkedToOriginatingApp: false, }; } catch (e) { @@ -393,7 +416,7 @@ export const runSaveLensVisualization = async ( } }; -export function removePinnedFilters(doc?: Document) { +export function removePinnedFilters(doc?: LensDocument) { if (!doc) return undefined; return { ...doc, diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts index 1f4e255c5441..9415ab2e323c 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.test.ts @@ -5,14 +5,14 @@ * 2.0. */ import { makeDefaultServices } from '../mocks'; -import type { LensEmbeddableInput } from '../embeddable'; import type { LensAppServices } from './types'; import { redirectToDashboard } from './save_modal_container_helpers'; +import { LensSerializedState } from '..'; describe('redirectToDashboard', () => { const embeddableInput = { test: 'test', - } as unknown as LensEmbeddableInput; + } as unknown as LensSerializedState; const mockServices = makeDefaultServices(); it('should call the navigateToWithEmbeddablePackage with the correct args if originatingApp is given', () => { diff --git a/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts index 98b2d0bdc2ab..44b879c7f27c 100644 --- a/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts +++ b/x-pack/plugins/lens/public/app_plugin/save_modal_container_helpers.ts @@ -6,8 +6,8 @@ */ import type { LensAppServices } from './types'; -import type { LensEmbeddableInput } from '../embeddable'; import { LENS_EMBEDDABLE_TYPE } from '../../common/constants'; +import { LensSerializedState } from '../react_embeddable/types'; export const redirectToDashboard = ({ embeddableInput, @@ -16,7 +16,7 @@ export const redirectToDashboard = ({ getOriginatingPath, stateTransfer, }: { - embeddableInput: LensEmbeddableInput; + embeddableInput: LensSerializedState; dashboardId: string; originatingApp?: string; getOriginatingPath?: (dashboardId: string) => string | undefined; diff --git a/x-pack/plugins/lens/public/app_plugin/share_action.ts b/x-pack/plugins/lens/public/app_plugin/share_action.ts index c9ec3a11ef5e..dbb5d9d61eda 100644 --- a/x-pack/plugins/lens/public/app_plugin/share_action.ts +++ b/x-pack/plugins/lens/public/app_plugin/share_action.ts @@ -11,7 +11,7 @@ import { DataViewSpec } from '@kbn/data-views-plugin/common'; import type { LensAppLocatorParams } from '../../common/locator/locator'; import type { LensAppState } from '../state_management'; import type { LensAppServices } from './types'; -import type { Document } from '../persistence/saved_object_store'; +import type { LensDocument } from '../persistence/saved_object_store'; import type { DatasourceMap, VisualizationMap } from '../types'; import { extractReferencesFromState, getResolvedDateRange } from '../utils'; import { getEditPath } from '../../common/constants'; @@ -23,7 +23,7 @@ interface ShareableConfiguration > { datasourceMap: DatasourceMap; visualizationMap: VisualizationMap; - currentDoc: Document | undefined; + currentDoc: LensDocument | undefined; adHocDataViews?: DataViewSpec[]; } @@ -37,7 +37,7 @@ export const DEFAULT_LENS_LAYOUT_DIMENSIONS = { function getShareURLForSavedObject( { application, data }: Pick<LensAppServices, 'application' | 'data'>, - currentDoc: Document | undefined + currentDoc: LensDocument | undefined ) { return new URL( `${application.getUrlForApp('lens', { absolute: true })}${ @@ -89,7 +89,7 @@ export function getLocatorParams( const serializableDatasourceStates = datasourceStates as LensAppState['datasourceStates'] & SerializableRecord; - const snapshotParams = { + const snapshotParams: LensAppLocatorParams = { filters, query, resolvedDateRange: getResolvedDateRange(data.query.timefilter.timefilter), diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx index 205aa74aaee2..dedd34c24cb5 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration.tsx @@ -16,6 +16,7 @@ import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; import { isEqual } from 'lodash'; import { RootDragDropProvider } from '@kbn/dom-drag-drop'; +import { TypedLensSerializedState } from '../../../react_embeddable/types'; import type { LensPluginStartDependencies } from '../../../plugin'; import { makeConfigureStore, @@ -28,8 +29,7 @@ import { generateId } from '../../../id_generator'; import type { DatasourceMap, VisualizationMap } from '../../../types'; import { LensEditConfigurationFlyout } from './lens_configuration_flyout'; import type { EditConfigPanelProps } from './types'; -import { SavedObjectIndexStore, type Document } from '../../../persistence'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import { SavedObjectIndexStore, type LensDocument } from '../../../persistence'; import { DOC_TYPE } from '../../../../common/constants'; export type EditLensConfigurationProps = Omit< @@ -87,6 +87,41 @@ export const updatingMiddleware = } }; +const MaybeWrapper = ({ + wrapInFlyout, + closeFlyout, + children, +}: { + wrapInFlyout?: boolean; + children: JSX.Element; + closeFlyout?: () => void; +}) => { + if (!wrapInFlyout) { + return children; + } + return ( + <EuiFlyout + data-test-subj="lnsEditOnFlyFlyout" + type="push" + ownFocus + paddingSize="m" + onClose={() => { + closeFlyout?.(); + }} + aria-labelledby={i18n.translate('xpack.lens.config.editLabel', { + defaultMessage: 'Edit configuration', + })} + size="s" + hideCloseButton + css={css` + clip-path: polygon(-100% 0, 100% 0, 100% 100%, -100% 100%); + `} + > + {children} + </EuiFlyout> + ); +}; + export async function getEditLensConfiguration( coreStart: CoreStart, startDependencies: LensPluginStartDependencies, @@ -109,30 +144,29 @@ export async function getEditLensConfiguration( datasourceId, panelId, savedObjectId, - output$, + dataLoading$, lensAdapters, updateByRefInput, navigateToLensEditor, displayFlyoutHeader, canEditTextBasedQuery, isNewPanel, - deletePanel, hidesSuggestions, - onApplyCb, - onCancelCb, + onApply, + onCancel, hideTimeFilterInfo, }: EditLensConfigurationProps) => { if (!lensServices || !datasourceMap || !visualizationMap) { return <LoadingSpinnerWithOverlay />; } const [currentAttributes, setCurrentAttributes] = - useState<TypedLensByValueInput['attributes']>(attributes); + useState<TypedLensSerializedState['attributes']>(attributes); /** * During inline editing of a by reference panel, the panel is converted to a by value one. * When the user applies the changes we save them to the Lens SO */ const saveByRef = useCallback( - async (attrs: Document) => { + async (attrs: LensDocument) => { const savedObjectStore = new SavedObjectIndexStore(lensServices.contentManagement); await savedObjectStore.save({ ...attrs, @@ -167,34 +201,6 @@ export async function getEditLensConfiguration( }) ); - const getWrapper = (children: JSX.Element) => { - if (wrapInFlyout) { - return ( - <EuiFlyout - data-test-subj="lnsEditOnFlyFlyout" - type="push" - ownFocus - paddingSize="m" - onClose={() => { - closeFlyout?.(); - }} - aria-labelledby={i18n.translate('xpack.lens.config.editLabel', { - defaultMessage: 'Edit configuration', - })} - size="s" - hideCloseButton - css={css` - clip-path: polygon(-100% 0, 100% 0, 100% 100%, -100% 100%); - `} - > - {children} - </EuiFlyout> - ); - } else { - return children; - } - }; - const configPanelProps = { attributes: currentAttributes, updatePanelState, @@ -204,7 +210,7 @@ export async function getEditLensConfiguration( coreStart, startDependencies, visualizationMap, - output$, + dataLoading$, lensAdapters, datasourceMap, saveByRef, @@ -216,22 +222,23 @@ export async function getEditLensConfiguration( hidesSuggestions, setCurrentAttributes, isNewPanel, - deletePanel, - onApplyCb, - onCancelCb, + onApply, + onCancel, hideTimeFilterInfo, }; - return getWrapper( - <Provider store={lensStore}> - <KibanaRenderContextProvider {...coreStart}> - <KibanaContextProvider services={lensServices}> - <RootDragDropProvider> - <LensEditConfigurationFlyout {...configPanelProps} /> - </RootDragDropProvider> - </KibanaContextProvider> - </KibanaRenderContextProvider> - </Provider> + return ( + <MaybeWrapper wrapInFlyout={wrapInFlyout} closeFlyout={closeFlyout}> + <Provider store={lensStore}> + <KibanaRenderContextProvider {...coreStart}> + <KibanaContextProvider services={lensServices}> + <RootDragDropProvider> + <LensEditConfigurationFlyout {...configPanelProps} /> + </RootDragDropProvider> + </KibanaContextProvider> + </KibanaRenderContextProvider> + </Provider> + </MaybeWrapper> ); }; } diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts index 1274008d0de8..c0280af59504 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/helpers.ts @@ -18,7 +18,7 @@ import type { DataView } from '@kbn/data-views-plugin/common'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { getTime } from '@kbn/data-plugin/common'; import { type DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import { TypedLensSerializedState } from '../../../react_embeddable/types'; import type { LensPluginStartDependencies } from '../../../plugin'; import type { DatasourceMap, VisualizationMap } from '../../../types'; import { suggestionsApi } from '../../../lens_suggestions_api'; @@ -123,7 +123,7 @@ export const getSuggestions = async ( query, suggestion: firstSuggestion, dataView, - }) as TypedLensByValueInput['attributes']; + }) as TypedLensSerializedState['attributes']; return attrs; } catch (e) { setErrors([e]); diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx index 85c7036a3e9d..474d5cc69c18 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.test.tsx @@ -13,9 +13,9 @@ import { coreMock } from '@kbn/core/public/mocks'; import { mockVisualizationMap, mockDatasourceMap, mockDataPlugin } from '../../../mocks'; import type { LensPluginStartDependencies } from '../../../plugin'; import { createMockStartDependencies } from '../../../editor_frame_service/mocks'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; import { LensEditConfigurationFlyout } from './lens_configuration_flyout'; import type { EditConfigPanelProps } from './types'; +import { TypedLensSerializedState } from '../../../react_embeddable/types'; jest.mock('@kbn/esql-utils', () => { return { @@ -93,7 +93,7 @@ const lensAttributes = { esql: 'from index1 | limit 10', }, references: [], -} as unknown as TypedLensByValueInput['attributes']; +} as unknown as TypedLensSerializedState['attributes']; const mockStartDependencies = createMockStartDependencies() as unknown as LensPluginStartDependencies; @@ -139,6 +139,8 @@ describe('LensEditConfigurationFlyout', () => { visualizationMap={visualizationMap} closeFlyout={jest.fn()} datasourceId={'testDatasource' as EditConfigPanelProps['datasourceId']} + onApply={jest.fn()} + onCancel={jest.fn()} {...propsOverrides} />, {}, @@ -234,7 +236,7 @@ describe('LensEditConfigurationFlyout', () => { await renderConfigFlyout( { closeFlyout: jest.fn(), - onApplyCb: onApplyCbSpy, + onApply: onApplyCbSpy, }, { esql: 'from index1 | limit 10' } ); diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx index fd3bcdc8bed8..8c8693cd7c76 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/lens_configuration_flyout.tsx @@ -30,6 +30,7 @@ import { import type { AggregateQuery, Query } from '@kbn/es-query'; import { ESQLLangEditor } from '@kbn/esql/public'; import { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; +import type { TypedLensSerializedState } from '../../../react_embeddable/types'; import { buildExpression } from '../../../editor_frame_service/editor_frame/expression_helpers'; import { MAX_NUM_OF_COLUMNS } from '../../../datasources/text_based/utils'; import { @@ -38,7 +39,6 @@ import { onActiveDataChange, useLensDispatch, } from '../../../state_management'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; import { EXPRESSION_BUILD_ERROR_ID, extractReferencesFromState, @@ -67,20 +67,19 @@ export function LensEditConfigurationFlyout({ saveByRef, savedObjectId, updateByRefInput, - output$, + dataLoading$, lensAdapters, navigateToLensEditor, displayFlyoutHeader, canEditTextBasedQuery, isNewPanel, - deletePanel, hidesSuggestions, - onApplyCb, - onCancelCb, + onApply: onApplyCallback, + onCancel: onCancelCallback, hideTimeFilterInfo, }: EditConfigPanelProps) { const euiTheme = useEuiTheme(); - const previousAttributes = useRef<TypedLensByValueInput['attributes']>(attributes); + const previousAttributes = useRef<TypedLensSerializedState['attributes']>(attributes); const previousAdapters = useRef<Partial<DefaultInspectorAdapters> | undefined>(lensAdapters); const prevQuery = useRef<AggregateQuery | Query>(attributes.state.query); const [query, setQuery] = useState<AggregateQuery | Query>(attributes.state.query); @@ -117,7 +116,11 @@ export function LensEditConfigurationFlyout({ const dispatch = useLensDispatch(); useEffect(() => { - const s = output$?.subscribe(() => { + const s = dataLoading$?.subscribe((isDataLoading) => { + // go thru only when the loading is complete + if (isDataLoading) { + return; + } const activeData: Record<string, Datatable> = {}; const adaptersTables = previousAdapters.current?.tables?.tables; const [table] = Object.values(adaptersTables || {}); @@ -134,7 +137,7 @@ export function LensEditConfigurationFlyout({ } }); return () => s?.unsubscribe(); - }, [dispatch, output$, layers]); + }, [dispatch, dataLoading$, layers]); useEffect(() => { const abortController = new AbortController(); @@ -217,16 +220,10 @@ export function LensEditConfigurationFlyout({ updateByRefInput?.(savedObjectId); } } - // for a newly created chart, I want cancelling to also remove the panel - if (isNewPanel && deletePanel) { - deletePanel(); - } - onCancelCb?.(); + onCancelCallback?.(); closeFlyout?.(); }, [ attributesChanged, - isNewPanel, - deletePanel, closeFlyout, visualization.activeId, savedObjectId, @@ -235,7 +232,7 @@ export function LensEditConfigurationFlyout({ updatePanelState, updateSuggestion, updateByRefInput, - onCancelCb, + onCancelCallback, ]); const textBasedMode = useMemo( @@ -244,6 +241,9 @@ export function LensEditConfigurationFlyout({ ); const onApply = useCallback(() => { + if (visualization.activeId == null) { + return; + } const dsStates = Object.fromEntries( Object.entries(datasourceStates).map(([id, ds]) => { const dsState = ds.state; @@ -265,7 +265,7 @@ export function LensEditConfigurationFlyout({ activeVisualization, }) : []; - const attrs = { + const attrs: TypedLensSerializedState['attributes'] = { ...attributes, state: { ...attributes.state, @@ -293,18 +293,18 @@ export function LensEditConfigurationFlyout({ trackSaveUiCounterEvents(telemetryEvents); } - onApplyCb?.(attrs as TypedLensByValueInput['attributes']); + onApplyCallback?.(attrs); closeFlyout?.(); }, [ + visualization.activeId, + savedObjectId, + closeFlyout, + onApplyCallback, datasourceStates, textBasedMode, visualization.state, - visualization.activeId, activeVisualization, attributes, - savedObjectId, - onApplyCb, - closeFlyout, datasourceMap, saveByRef, updateByRefInput, diff --git a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts index d2aceb323773..d31a518cf80e 100644 --- a/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/shared/edit_on_the_fly/types.ts @@ -4,9 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Observable } from 'rxjs'; import type { CoreStart } from '@kbn/core/public'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import type { PublishingSubject } from '@kbn/presentation-publishing'; +import type { TypedLensSerializedState } from '../../../react_embeddable/types'; import type { LensPluginStartDependencies } from '../../../plugin'; import type { DatasourceMap, @@ -14,9 +14,8 @@ import type { FramePublicAPI, UserMessagesGetter, } from '../../../types'; -import type { LensEmbeddableOutput } from '../../../embeddable'; import type { LensInspector } from '../../../lens_inspector_service'; -import type { Document } from '../../../persistence'; +import type { LensDocument } from '../../../persistence'; export interface FlyoutWrapperProps { children: JSX.Element; @@ -37,22 +36,22 @@ export interface EditConfigPanelProps { visualizationMap: VisualizationMap; datasourceMap: DatasourceMap; /** The attributes of the Lens embeddable */ - attributes: TypedLensByValueInput['attributes']; + attributes: TypedLensSerializedState['attributes']; /** Callback for updating the visualization and datasources state.*/ updatePanelState: ( datasourceState: unknown, visualizationState: unknown, - visualizationType?: string + visualizationId?: string ) => void; - updateSuggestion?: (attrs: TypedLensByValueInput['attributes']) => void; + updateSuggestion?: (attrs: TypedLensSerializedState['attributes']) => void; /** Set the attributes state */ - setCurrentAttributes?: (attrs: TypedLensByValueInput['attributes']) => void; + setCurrentAttributes?: (attrs: TypedLensSerializedState['attributes']) => void; /** Lens visualizations can be either created from ESQL (textBased) or from dataviews (formBased) */ datasourceId: 'formBased' | 'textBased'; /** Embeddable output observable, useful for dashboard flyout */ - output$?: Observable<LensEmbeddableOutput>; + dataLoading$?: PublishingSubject<boolean | undefined>; /** Contains the active data, necessary for some panel configuration such as coloring */ - lensAdapters?: LensInspector['adapters']; + lensAdapters?: ReturnType<LensInspector['getInspectorAdapters']>; /** Optional callback called when updating the by reference embeddable */ updateByRefInput?: (soId: string) => void; /** Callback for closing the edit flyout */ @@ -69,7 +68,7 @@ export interface EditConfigPanelProps { */ savedObjectId?: string; /** Callback for saving the embeddable as a SO */ - saveByRef?: (attrs: Document) => void; + saveByRef?: (attrs: LensDocument) => void; /** Optional callback for navigation from the header of the flyout */ navigateToLensEditor?: () => void; /** If set to true it displays a header on the flyout */ @@ -78,21 +77,19 @@ export interface EditConfigPanelProps { canEditTextBasedQuery?: boolean; /** The flyout is used for adding a new panel by scratch */ isNewPanel?: boolean; - /** Handler for deleting the embeddable, used in case a user cancels a newly created chart */ - deletePanel?: () => void; /** If set to true the layout changes to accordion and the text based query (i.e. ES|QL) can be edited */ hidesSuggestions?: boolean; - /** Optional callback for apply flyout button */ - onApplyCb?: (input: TypedLensByValueInput['attributes']) => void; - /** Optional callback for cancel flyout button */ - onCancelCb?: () => void; + /** Apply button handler */ + onApply?: (attrs: TypedLensSerializedState['attributes']) => void; + /** Cancel button handler */ + onCancel?: () => void; // in cases where the embeddable is not filtered by time // (e.g. through unified search) set this property to true hideTimeFilterInfo?: boolean; } export interface LayerConfigurationProps { - attributes: TypedLensByValueInput['attributes']; + attributes: TypedLensSerializedState['attributes']; coreStart: CoreStart; startDependencies: LensPluginStartDependencies; visualizationMap: VisualizationMap; diff --git a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts index fa9268c0374e..f35443a51014 100644 --- a/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts +++ b/x-pack/plugins/lens/public/app_plugin/show_underlying_data.ts @@ -16,6 +16,7 @@ import { EsQueryConfig, isOfQueryType, AggregateQuery, + isOfAggregateQueryType, } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import { RecursiveReadonly } from '@kbn/utility-types'; @@ -219,8 +220,9 @@ export function combineQueryAndFilters( }; const allQueries = Array.isArray(query) ? query : query && isOfQueryType(query) ? [query] : []; - const nonEmptyQueries = allQueries.filter((q) => - Boolean(typeof q.query === 'string' ? q.query.trim() : q.query) + const nonEmptyQueries = allQueries.filter( + (q) => + !isOfAggregateQueryType(q) && Boolean(typeof q.query === 'string' ? q.query.trim() : q.query) ); [queries.lucene, queries.kuery] = partition(nonEmptyQueries, (q) => q.language === 'lucene'); diff --git a/x-pack/plugins/lens/public/app_plugin/types.ts b/x-pack/plugins/lens/public/app_plugin/types.ts index 317efd5be507..4791dc89d446 100644 --- a/x-pack/plugins/lens/public/app_plugin/types.ts +++ b/x-pack/plugins/lens/public/app_plugin/types.ts @@ -55,15 +55,15 @@ import type { UserMessagesGetter, StartServices, } from '../types'; -import type { LensAttributeService } from '../lens_attribute_service'; -import type { LensEmbeddableInput } from '../embeddable/embeddable'; +import type { LensAttributesService } from '../lens_attribute_service'; import type { LensInspector } from '../lens_inspector_service'; import type { IndexPatternServiceAPI } from '../data_views_service/service'; -import type { Document, SavedObjectIndexStore } from '../persistence/saved_object_store'; +import type { LensDocument, SavedObjectIndexStore } from '../persistence/saved_object_store'; import type { LensAppLocator, LensAppLocatorParams } from '../../common/locator/locator'; +import { LensSerializedState } from '../react_embeddable/types'; export interface RedirectToOriginProps { - input?: LensEmbeddableInput; + state?: LensSerializedState; isCopied?: boolean; } @@ -76,7 +76,7 @@ export interface LensAppProps { redirectToOrigin?: (props?: RedirectToOriginProps) => void; // The initial input passed in by the container when editing. Can be either by reference or by value. - initialInput?: LensEmbeddableInput; + initialInput?: LensSerializedState; // State passed in by the container which is used to determine the id of the Originating App. incomingState?: EmbeddableEditorState; @@ -110,7 +110,7 @@ export interface LensTopNavMenuProps { redirectToOrigin?: (props?: RedirectToOriginProps) => void; // The initial input passed in by the container when editing. Can be either by reference or by value. - initialInput?: LensEmbeddableInput; + initialInput?: LensSerializedState; getIsByValueMode: () => boolean; indicateNoData: boolean; setIsSaveModalVisible: React.Dispatch<React.SetStateAction<boolean>>; @@ -124,7 +124,7 @@ export interface LensTopNavMenuProps { initialContextIsEmbedded?: boolean; topNavMenuEntryGenerators: LensTopNavMenuEntryGenerator[]; initialContext?: VisualizeFieldContext | VisualizeEditorContext; - currentDoc: Document | undefined; + currentDoc: LensDocument | undefined; indexPatternService: IndexPatternServiceAPI; getUserMessages: UserMessagesGetter; shortUrlService: (params: LensAppLocatorParams) => Promise<string>; @@ -156,7 +156,7 @@ export interface LensAppServices extends StartServices { usageCollection?: UsageCollectionStart; stateTransfer: EmbeddableStateTransfer; navigation: NavigationPublicPluginStart; - attributeService: LensAttributeService; + attributeService: LensAttributesService; contentManagement: ContentManagementPublicStart; savedObjectsTagging?: SavedObjectTaggingPluginStart; getOriginatingAppName: () => string | undefined; diff --git a/x-pack/plugins/lens/public/async_services.ts b/x-pack/plugins/lens/public/async_services.ts index 28becae5e607..e5523b38b525 100644 --- a/x-pack/plugins/lens/public/async_services.ts +++ b/x-pack/plugins/lens/public/async_services.ts @@ -43,13 +43,11 @@ export * from './lens_ui_telemetry'; export * from './lens_ui_errors'; export * from './editor_frame_service/editor_frame'; export * from './editor_frame_service'; -export * from './embeddable'; export * from './app_plugin/mounter'; export * from './lens_attribute_service'; export * from './app_plugin/save_modal_container'; export * from './chart_info_api'; export * from './trigger_actions/open_in_discover_helpers'; -export * from './trigger_actions/open_lens_config/edit_action_helpers'; export * from './trigger_actions/open_lens_config/create_action_helpers'; export * from './trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers'; diff --git a/x-pack/plugins/lens/public/chart_info_api.test.ts b/x-pack/plugins/lens/public/chart_info_api.test.ts index c302d4e934eb..f647e2289c5b 100644 --- a/x-pack/plugins/lens/public/chart_info_api.test.ts +++ b/x-pack/plugins/lens/public/chart_info_api.test.ts @@ -6,9 +6,9 @@ */ import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks'; -import type { EditorFrameService } from './editor_frame_service'; import { createChartInfoApi } from './chart_info_api'; -import type { LensSavedObjectAttributes } from '.'; +import { LensDocument } from './persistence'; +import { DatasourceMap, VisualizationMap } from './types'; const mockGetVisualizationInfo = jest.fn().mockReturnValue({ layers: [ @@ -37,18 +37,19 @@ const mockGetDatasourceInfo = jest.fn().mockResolvedValue([ describe('createChartInfoApi', () => { const dataViews = dataViewPluginMocks.createStartContract(); test('get correct chart info', async () => { - const chartInfoApi = await createChartInfoApi(dataViews, { - loadVisualizations: () => ({ + const chartInfoApi = await createChartInfoApi( + dataViews, + { lnsXY: { getVisualizationInfo: mockGetVisualizationInfo, }, - }), - loadDatasources: () => ({ + } as unknown as VisualizationMap, + { from_based: { getDatasourceInfo: mockGetDatasourceInfo, }, - }), - } as unknown as EditorFrameService); + } as unknown as DatasourceMap + ); const vis = { title: 'xy', visualizationType: 'lnsXY', @@ -69,7 +70,7 @@ describe('createChartInfoApi', () => { query: '', }, references: [], - } as LensSavedObjectAttributes; + } as LensDocument; const chartInfo = await chartInfoApi.getChartInfo(vis); diff --git a/x-pack/plugins/lens/public/chart_info_api.ts b/x-pack/plugins/lens/public/chart_info_api.ts index d2661226cdf1..ace9ab445dba 100644 --- a/x-pack/plugins/lens/public/chart_info_api.ts +++ b/x-pack/plugins/lens/public/chart_info_api.ts @@ -5,23 +5,22 @@ * 2.0. */ -import type { Filter, Query } from '@kbn/es-query'; +import type { AggregateQuery, Filter, Query } from '@kbn/es-query'; import type { IconType } from '@elastic/eui/src/components/icon/icon'; import type { DataView, DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { getActiveDatasourceIdFromDoc } from './utils'; -import type { EditorFrameService as EditorFrameServiceType } from './editor_frame_service'; -import type { OperationDescriptor } from './types'; -import type { LensSavedObjectAttributes } from '.'; +import type { DatasourceMap, OperationDescriptor, VisualizationMap } from './types'; +import { LensDocument } from './persistence'; export type ChartInfoApi = Promise<{ - getChartInfo: (vis: LensSavedObjectAttributes) => Promise<ChartInfo | undefined>; + getChartInfo: (vis: LensDocument) => Promise<ChartInfo | undefined>; }>; export interface ChartInfo { layers: ChartLayerDescriptor[]; visualizationType: string; filters: Filter[]; - query: Query; + query: Query | AggregateQuery; } export interface ChartLayerDescriptor { @@ -42,17 +41,14 @@ export interface ChartLayerDescriptor { export const createChartInfoApi = async ( dataViews: DataViewsPublicPluginStart, - editorFrameService?: EditorFrameServiceType + visualizationMap: VisualizationMap, + datasourceMap: DatasourceMap ): ChartInfoApi => { - const [visualizationMap, datasourceMap] = await Promise.all([ - editorFrameService!.loadVisualizations(), - editorFrameService!.loadDatasources(), - ]); return { - async getChartInfo(vis: LensSavedObjectAttributes): Promise<ChartInfo | undefined> { + async getChartInfo(vis: LensDocument): Promise<ChartInfo | undefined> { const lensVis = vis; const activeDatasourceId = getActiveDatasourceIdFromDoc(lensVis); - if (!activeDatasourceId || !lensVis?.visualizationType) { + if (!activeDatasourceId || lensVis?.visualizationType == null) { return undefined; } diff --git a/x-pack/plugins/lens/public/datasources/form_based/datapanel.tsx b/x-pack/plugins/lens/public/datasources/form_based/datapanel.tsx index e356a59956f0..ff51014f548d 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/datapanel.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/datapanel.tsx @@ -12,6 +12,7 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import type { CoreStart } from '@kbn/core/public'; +import { Query } from '@kbn/es-query'; import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import { type DataView, DataViewField, FieldSpec } from '@kbn/data-plugin/common'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; @@ -42,7 +43,7 @@ import { IndexPatternServiceAPI } from '../../data_views_service/service'; import { FieldItem } from '../common/field_item'; export type FormBasedDataPanelProps = Omit< - DatasourceDataPanelProps<FormBasedPrivateState>, + DatasourceDataPanelProps<FormBasedPrivateState, Query>, 'core' | 'onChangeIndexPattern' > & { data: DataPublicPluginStart; @@ -185,7 +186,7 @@ export const InnerFormBasedDataPanel = function InnerFormBasedDataPanel({ showNoDataPopover, activeIndexPatterns, }: Omit< - DatasourceDataPanelProps, + DatasourceDataPanelProps<unknown, Query>, 'state' | 'setState' | 'core' | 'onChangeIndexPattern' | 'usedIndexPatterns' > & { data: DataPublicPluginStart; diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts index b399f8eaa7b5..cd26abe0fdd8 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.test.ts @@ -51,6 +51,7 @@ import { Datatable, DatatableColumn } from '@kbn/expressions-plugin/common'; import { filterAndSortUserMessages } from '../../app_plugin/get_application_user_messages'; import { createMockFramePublicAPI } from '../../mocks'; import { createMockDataViewsState } from '../../data_views_service/mocks'; +import { Query } from '@kbn/es-query'; jest.mock('./loader'); jest.mock('../../id_generator'); @@ -193,7 +194,7 @@ const dateRange = { describe('IndexPattern Data Source', () => { let baseState: FormBasedPrivateState; - let FormBasedDatasource: Datasource<FormBasedPrivateState, FormBasedPersistedState>; + let FormBasedDatasource: Datasource<FormBasedPrivateState, FormBasedPersistedState, Query>; beforeEach(() => { const data = dataPluginMock.createStartContract(); diff --git a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx index da893707ab2b..ebe98c56adeb 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/form_based.tsx @@ -8,7 +8,7 @@ import React from 'react'; import type { CoreStart, SavedObjectReference } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { TimeRange } from '@kbn/es-query'; +import { Query, TimeRange } from '@kbn/es-query'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { flatten, isEqual } from 'lodash'; @@ -28,7 +28,6 @@ import memoizeOne from 'memoize-one'; import type { DatasourceDimensionEditorProps, DatasourceDimensionTriggerProps, - DatasourceDataPanelProps, DatasourceLayerPanelProps, PublicAPIProps, OperationDescriptor, @@ -40,6 +39,7 @@ import type { UserMessage, StateSetter, IndexPatternMap, + DatasourceDataPanelProps, } from '../../types'; import { changeIndexPattern, @@ -217,7 +217,7 @@ export function getFormBasedDatasource({ const ALIAS_IDS = ['indexpattern']; // Not stateful. State is persisted to the frame - const formBasedDatasource: Datasource<FormBasedPrivateState, FormBasedPersistedState> = { + const formBasedDatasource: Datasource<FormBasedPrivateState, FormBasedPersistedState, Query> = { id: DATASOURCE_ID, alias: ALIAS_IDS, @@ -464,7 +464,7 @@ export function getFormBasedDatasource({ LayerSettingsComponent(props) { return <LayerSettingsPanel {...props} />; }, - DataPanelComponent(props: DatasourceDataPanelProps<FormBasedPrivateState>) { + DataPanelComponent(props: DatasourceDataPanelProps<FormBasedPrivateState, Query>) { const { onChangeIndexPattern, ...otherProps } = props; const layerFields = formBasedDatasource?.getSelectedFields?.(props.state); return ( @@ -869,13 +869,11 @@ export function getFormBasedDatasource({ getDatasourceInfo: async (state, references, dataViewsService) => { const layers = references ? injectReferences(state, references).layers : state.layers; - const indexPatterns: DataView[] = []; - for (const { indexPatternId } of Object.values(layers)) { - const dataView = await dataViewsService?.get(indexPatternId); - if (dataView) { - indexPatterns.push(dataView); - } - } + const indexPatterns: DataView[] = await Promise.all( + Object.values(layers) + .map(({ indexPatternId }) => dataViewsService?.get(indexPatternId)) + .filter(nonNullable) + ); return Object.entries(layers).reduce<DataSourceInfo[]>((acc, [key, layer]) => { const dataView = indexPatterns?.find( (indexPattern) => indexPattern.id === layer.indexPatternId diff --git a/x-pack/plugins/lens/public/datasources/form_based/mocks.ts b/x-pack/plugins/lens/public/datasources/form_based/mocks.ts index fcefa97ecd4b..f98107eebbcc 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/mocks.ts +++ b/x-pack/plugins/lens/public/datasources/form_based/mocks.ts @@ -8,101 +8,83 @@ import { getFieldByNameFactory } from './pure_helpers'; import type { IndexPattern, IndexPatternField } from '../../types'; +export function createMockedField( + someProps: Partial<IndexPatternField> & Pick<IndexPatternField, 'name' | 'type'> +) { + return { + displayName: someProps.name, + aggregatable: true, + searchable: true, + ...someProps, + }; +} + export const createMockedIndexPattern = ( someProps?: Partial<IndexPattern>, customFields: IndexPatternField[] = [] ): IndexPattern => { const fields = [ - { + createMockedField({ name: 'timestamp', displayName: 'timestampLabel', type: 'date', - aggregatable: true, - searchable: true, - }, - { + }), + createMockedField({ name: 'start_date', - displayName: 'start_date', type: 'date', - aggregatable: true, - searchable: true, - }, - { + }), + createMockedField({ name: 'bytes', - displayName: 'bytes', type: 'number', - aggregatable: true, - searchable: true, - }, - { + }), + createMockedField({ name: 'memory', - displayName: 'memory', type: 'number', - aggregatable: true, - searchable: true, esTypes: ['float'], - }, - { + }), + createMockedField({ name: 'source', - displayName: 'source', type: 'string', - aggregatable: true, - searchable: true, esTypes: ['keyword'], - }, - { + }), + createMockedField({ name: 'unsupported', - displayName: 'unsupported', type: 'geo', - aggregatable: true, - searchable: true, - }, - { + }), + createMockedField({ name: 'dest', - displayName: 'dest', type: 'string', - aggregatable: true, - searchable: true, esTypes: ['keyword'], - }, - { + }), + createMockedField({ name: 'geo.src', - displayName: 'geo.src', type: 'string', - aggregatable: true, - searchable: true, esTypes: ['keyword'], - }, - { + }), + createMockedField({ name: 'scripted', displayName: 'Scripted', type: 'string', - searchable: true, - aggregatable: true, scripted: true, lang: 'painless' as const, script: '1234', - }, - { + }), + createMockedField({ name: 'runtime-keyword', displayName: 'Runtime keyword field', type: 'string', - searchable: true, - aggregatable: true, runtime: true, lang: 'painless' as const, script: 'emit("123")', - }, - { + }), + createMockedField({ name: 'runtime-number', displayName: 'Runtime number field', type: 'number', - searchable: true, - aggregatable: true, runtime: true, lang: 'painless' as const, script: 'emit(123)', - }, + }), ...(customFields || []), ]; return { @@ -120,31 +102,23 @@ export const createMockedIndexPattern = ( export const createMockedRestrictedIndexPattern = () => { const fields = [ - { + createMockedField({ name: 'timestamp', displayName: 'timestampLabel', type: 'date', - aggregatable: true, - searchable: true, - }, - { + }), + createMockedField({ name: 'bytes', - displayName: 'bytes', type: 'number', - aggregatable: true, - searchable: true, - }, - { + }), + createMockedField({ name: 'source', - displayName: 'source', type: 'string', - aggregatable: true, - searchable: true, scripted: true, esTypes: ['keyword'], lang: 'painless' as const, script: '1234', - }, + }), ]; return { id: '2', diff --git a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx index 411583d88ef1..6a9471e174e8 100644 --- a/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx +++ b/x-pack/plugins/lens/public/datasources/text_based/text_based_languages.tsx @@ -362,7 +362,7 @@ export function getTextBasedDatasource({ getUsedDataViews: (state) => { return Object.values(state.layers) .map(({ index }) => index) - .filter((index) => index !== undefined) as string[]; + .filter(nonNullable); }, getPersistableState({ layers }: TextBasedPrivateState) { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/easteregg/index.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/easteregg/index.tsx index 7bfd7c666079..3372625ff283 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/easteregg/index.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/easteregg/index.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import type { Query } from '@kbn/es-query'; +import { AggregateQuery, isOfAggregateQueryType, Query } from '@kbn/es-query'; import { EuiErrorBoundary } from '@elastic/eui'; const Bee = React.lazy(() => import('./bee')); @@ -34,11 +34,14 @@ function Bees({ query }: { query?: Query }) { ); } -export function Easteregg(props: { query?: Query }) { +export function Easteregg(props: { query?: Query | AggregateQuery }) { + if (isOfAggregateQueryType(props.query)) { + return null; + } return ( // Do not break Lens for an easteregg <EuiErrorBoundary style={{ display: 'none' }}> - <Bees {...props} /> + <Bees query={props.query} /> </EuiErrorBoundary> ); } diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts index 466773ec1c6b..efe3ccc84f56 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/state_helpers.ts @@ -33,7 +33,7 @@ import type { SuggestionRequest, } from '../../types'; import { buildExpression } from './expression_helpers'; -import { Document } from '../../persistence/saved_object_store'; +import { LensDocument } from '../../persistence/saved_object_store'; import { getActiveDatasourceIdFromDoc, sortDataViewRefs } from '../../utils'; import type { DatasourceState, DatasourceStates, VisualizationState } from '../../state_management'; import { readFromStorage } from '../../settings_storage'; @@ -353,12 +353,13 @@ export interface DocumentToExpressionReturnType { indexPatterns: IndexPatternMap; indexPatternRefs: IndexPatternRef[]; activeVisualizationState: unknown; + activeDatasourceState: unknown; } export async function persistedStateToExpression( datasourceMap: DatasourceMap, visualizations: VisualizationMap, - doc: Document, + doc: LensDocument, services: { uiSettings: IUiSettingsClient; storage: IStorageWrapper; @@ -381,7 +382,13 @@ export async function persistedStateToExpression( description, } = doc; if (!visualizationType) { - return { ast: null, indexPatterns: {}, indexPatternRefs: [], activeVisualizationState: null }; + return { + ast: null, + indexPatterns: {}, + indexPatternRefs: [], + activeVisualizationState: null, + activeDatasourceState: null, + }; } const annotationGroups = await initializeEventAnnotationGroups( @@ -435,6 +442,7 @@ export async function persistedStateToExpression( indexPatterns, indexPatternRefs, activeVisualizationState, + activeDatasourceState: null, }; } @@ -454,6 +462,7 @@ export async function persistedStateToExpression( nowInstant: services.nowProvider.get(), }), activeVisualizationState, + activeDatasourceState: datasourceStates[datasourceId]?.state, indexPatterns, indexPatternRefs, }; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx index b32d7456bd2b..5775748da8ce 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel.tsx @@ -248,7 +248,7 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ const removeExpressionBuildErrorsRef = useRef<() => void>(); const onData$ = useCallback( - (_data: unknown, adapters?: Partial<DefaultInspectorAdapters>) => { + (_data: unknown, adapters?: DefaultInspectorAdapters) => { if (renderDeps.current) { dataReceivedTime.current = performance.now(); @@ -283,10 +283,11 @@ export const InnerWorkspacePanel = React.memo(function InnerWorkspacePanel({ dispatchLens( onActiveDataChange({ activeData: Object.entries(adapters.tables?.tables).reduce<Record<string, Datatable>>( - (acc, [key, value], _index, tables) => ({ - ...acc, - [tables.length === 1 ? defaultLayerId : key]: value, - }), + (acc, [key, value], _index, tables) => { + const id = tables.length === 1 ? defaultLayerId : key; + acc[id] = value as Datatable; + return acc; + }, {} ), }) @@ -726,7 +727,7 @@ export const VisualizationWrapper = ({ ExpressionRendererComponent: ReactExpressionRendererType; core: CoreStart; onRender$: () => void; - onData$: (data: unknown, adapters?: Partial<DefaultInspectorAdapters>) => void; + onData$: (data: unknown, adapters?: DefaultInspectorAdapters) => void; onComponentRendered: () => void; displayOptions: VisualizationDisplayOptions | undefined; }) => { @@ -788,7 +789,7 @@ export const VisualizationWrapper = ({ // @ts-expect-error upgrade typescript v4.9.5 onData$={onData$} onRender$={onRenderHandler} - inspectorAdapters={lensInspector.adapters} + inspectorAdapters={lensInspector.getInspectorAdapters()} executionContext={executionContext} renderMode="edit" renderError={(errorMessage?: string | null, error?: ExpressionRenderError | null) => { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx index 54532360169f..a4077b691982 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper.tsx @@ -260,6 +260,7 @@ export function WorkspacePanelWrapper({ flexGrow: 0, height: '100%', width: '100%', + overflow: 'auto', ...visDimensionsCSS, }} > diff --git a/x-pack/plugins/lens/public/editor_frame_service/service.tsx b/x-pack/plugins/lens/public/editor_frame_service/service.tsx index 71cf62d02d38..a677e0c6105b 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/service.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/service.tsx @@ -24,7 +24,7 @@ import { DataViewsPublicPluginStart, } from '@kbn/data-views-plugin/public'; import { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; -import { Document } from '../persistence/saved_object_store'; +import { LensDocument } from '../persistence/saved_object_store'; import { Datasource, Visualization, @@ -93,7 +93,7 @@ export class EditorFrameService { * This is an asynchronous process. * @param doc parsed Lens saved object */ - public documentToExpression = async (doc: Document, services: EditorFramePlugins) => { + public documentToExpression = async (doc: LensDocument, services: EditorFramePlugins) => { const [resolvedDatasources, resolvedVisualizations] = await Promise.all([ this.loadDatasources(), this.loadVisualizations(), diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx deleted file mode 100644 index 3dda0daf2576..000000000000 --- a/x-pack/plugins/lens/public/embeddable/embeddable.test.tsx +++ /dev/null @@ -1,1373 +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 { - Embeddable, - LensByValueInput, - LensUnwrapMetaInfo, - LensEmbeddableInput, - LensByReferenceInput, - LensSavedObjectAttributes, - LensUnwrapResult, - LensEmbeddableDeps, -} from './embeddable'; -import { ReactExpressionRendererProps } from '@kbn/expressions-plugin/public'; -import { spacesPluginMock } from '@kbn/spaces-plugin/public/mocks'; -import { Filter, Query, TimeRange } from '@kbn/es-query'; -import { FilterManager } from '@kbn/data-plugin/public'; -import type { DataViewsContract } from '@kbn/data-views-plugin/public'; -import { Document } from '../persistence'; -import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; -import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public/embeddable'; -import { coreMock, httpServiceMock } from '@kbn/core/public/mocks'; -import { IBasePath, IUiSettingsClient } from '@kbn/core/public'; -import { AttributeService, ViewMode } from '@kbn/embeddable-plugin/public'; -import { LensAttributeService } from '../lens_attribute_service'; -import { OnSaveProps } from '@kbn/saved-objects-plugin/public/save_modal'; -import { act } from 'react-dom/test-utils'; -import { inspectorPluginMock } from '@kbn/inspector-plugin/public/mocks'; -import { Visualization } from '../types'; -import { createMockDatasource, createMockVisualization } from '../mocks'; -import { FIELD_NOT_FOUND, FIELD_WRONG_TYPE } from '../user_messages_ids'; - -jest.mock('@kbn/inspector-plugin/public', () => ({ - isAvailable: false, - open: false, -})); - -const defaultVisualizationId = 'lnsSomeVisType'; -const defaultDatasourceId = 'someDatasource'; - -const savedVis: Document = { - state: { - visualization: { activeId: defaultVisualizationId }, - datasourceStates: { [defaultDatasourceId]: {} }, - query: { query: '', language: 'lucene' }, - filters: [], - }, - references: [], - title: 'My title', - visualizationType: defaultVisualizationId, -}; - -const defaultVisualizationMap = { - [defaultVisualizationId]: createMockVisualization(), -}; - -const defaultDatasourceMap = { - [defaultDatasourceId]: createMockDatasource(defaultDatasourceId), -}; - -const defaultSaveMethod = ( - _testAttributes: LensSavedObjectAttributes, - _savedObjectId?: string -): Promise<{ id: string }> => { - return new Promise(() => { - return { id: '123' }; - }); -}; -const defaultUnwrapMethod = ( - _savedObjectId: string -): Promise<{ attributes: LensSavedObjectAttributes }> => { - return new Promise(() => { - return { attributes: { ...savedVis } }; - }); -}; -const defaultCheckForDuplicateTitle = (_props: OnSaveProps): Promise<true> => { - return new Promise(() => { - return true; - }); -}; -const options = { - saveMethod: defaultSaveMethod, - unwrapMethod: defaultUnwrapMethod, - checkForDuplicateTitle: defaultCheckForDuplicateTitle, -}; - -const mockInjectFilterReferences: FilterManager['inject'] = (filters, _references) => { - return filters.map((filter) => ({ - ...filter, - meta: { - ...filter.meta, - index: 'injected!', - }, - })); -}; - -const attributeServiceMockFromSavedVis = (document: Document): LensAttributeService => { - const core = coreMock.createStart(); - const service = new AttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput, - LensUnwrapMetaInfo - >('lens', core.notifications.toasts, options); - service.unwrapAttributes = jest.fn((_input: LensByValueInput | LensByReferenceInput) => { - return Promise.resolve({ - attributes: { - ...document, - }, - metaInfo: { - sharingSavedObjectProps: { - outcome: 'exactMatch', - }, - }, - } as LensUnwrapResult); - }); - service.wrapAttributes = jest.fn(); - return service; -}; - -const dataMock = dataPluginMock.createStartContract(); - -describe('embeddable', () => { - const coreStart = coreMock.createStart(); - - let mountpoint: HTMLDivElement; - let expressionRenderer: jest.Mock<null, [ReactExpressionRendererProps]>; - let getTrigger: jest.Mock; - let trigger: { exec: jest.Mock }; - let basePath: IBasePath; - let attributeService: AttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput, - LensUnwrapMetaInfo - >; - - beforeEach(() => { - mountpoint = document.createElement('div'); - expressionRenderer = jest.fn((_props) => null); - trigger = { exec: jest.fn() }; - getTrigger = jest.fn(() => trigger); - attributeService = attributeServiceMockFromSavedVis(savedVis); - const http = httpServiceMock.createSetupContract({ basePath: '/test' }); - basePath = http.basePath; - }); - - afterEach(() => { - mountpoint.remove(); - }); - - function getEmbeddableProps(props: Partial<LensEmbeddableDeps> = {}): LensEmbeddableDeps { - return { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService, - data: dataMock, - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - inspector: inspectorPluginMock.createStartContract(), - expressionRenderer, - coreStart, - basePath, - dataViews: { - get: (id: string) => Promise.resolve({ id, isTimeBased: () => false }), - } as unknown as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - getTrigger, - visualizationMap: defaultVisualizationMap, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - ...props, - }; - } - - it('should render expression once with expression renderer', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), { - timeRange: { - from: 'now-15m', - to: 'now', - }, - } as LensEmbeddableInput); - embeddable.render(mountpoint); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - expect(expressionRenderer.mock.calls[0][0]!.expression).toEqual(`my -| expression`); - }); - - it('should not throw if render is called after destroy', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), { - timeRange: { - from: 'now-15m', - to: 'now', - }, - } as LensEmbeddableInput); - let renderCalled = false; - let renderThrew = false; - // destroying completes output synchronously which might make a synchronous render call - this shouldn't throw - embeddable.getOutput$().subscribe(undefined, undefined, () => { - try { - embeddable.render(mountpoint); - } catch (e) { - renderThrew = true; - } finally { - renderCalled = true; - } - }); - embeddable.destroy(); - expect(renderCalled).toBe(true); - expect(renderThrew).toBe(false); - }); - - it('should render once even if reload is called before embeddable is fully initialized', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), { - timeRange: { - from: 'now-15m', - to: 'now', - }, - } as LensEmbeddableInput); - embeddable.reload(); - expect(expressionRenderer).toHaveBeenCalledTimes(0); - embeddable.render(mountpoint); - expect(expressionRenderer).toHaveBeenCalledTimes(0); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - }); - - it('should not render the visualization if any error arises', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), {} as LensEmbeddableInput); - - jest.spyOn(embeddable, 'getUserMessages').mockReturnValue([ - { - uniqueId: 'error', - severity: 'error', - fixableInEditor: true, - displayLocations: [{ id: 'visualization' }], - longMessage: 'lol', - shortMessage: 'lol', - }, - ]); - - await embeddable.initializeSavedVis({} as LensEmbeddableInput); - embeddable.render(mountpoint); - - expect(expressionRenderer).toHaveBeenCalledTimes(0); - }); - - it('should override embeddableBadge message', async () => { - const getBadgeMessage = jest.fn( - (): ReturnType<NonNullable<LensEmbeddableInput['onBeforeBadgesRender']>> => [ - { - uniqueId: FIELD_NOT_FOUND, - severity: 'warning', - fixableInEditor: true, - displayLocations: [ - { id: 'embeddableBadge' }, - { id: 'dimensionButton', dimensionId: '1' }, - ], - longMessage: 'custom', - shortMessage: '', - hidePopoverIcon: true, - }, - ] - ); - - const embeddable = new Embeddable( - getEmbeddableProps({ - datasourceMap: { - ...defaultDatasourceMap, - [defaultDatasourceId]: { - ...defaultDatasourceMap[defaultDatasourceId], - getUserMessages: jest.fn(() => [ - { - uniqueId: FIELD_NOT_FOUND, - severity: 'error', - fixableInEditor: true, - displayLocations: [ - { id: 'embeddableBadge' }, - { id: 'dimensionButton', dimensionId: '1' }, - ], - longMessage: 'original', - shortMessage: '', - }, - { - uniqueId: FIELD_WRONG_TYPE, - severity: 'error', - fixableInEditor: true, - displayLocations: [{ id: 'visualization' }], - longMessage: 'original', - shortMessage: '', - }, - ]), - }, - }, - }), - { - onBeforeBadgesRender: getBadgeMessage as LensEmbeddableInput['onBeforeBadgesRender'], - } as LensEmbeddableInput - ); - - const getUserMessagesSpy = jest.spyOn(embeddable, 'getUserMessages'); - await embeddable.initializeSavedVis({} as LensEmbeddableInput); - - embeddable.render(mountpoint); - - expect(getUserMessagesSpy.mock.results.flatMap((r) => r.value)).toEqual( - expect.arrayContaining([ - { - uniqueId: FIELD_WRONG_TYPE, - severity: 'error', - fixableInEditor: true, - displayLocations: [{ id: 'visualization' }], - longMessage: 'original', - shortMessage: '', - }, - { - uniqueId: FIELD_NOT_FOUND, - severity: 'warning', - fixableInEditor: true, - displayLocations: [ - { id: 'embeddableBadge' }, - { id: 'dimensionButton', dimensionId: '1' }, - ], - longMessage: 'custom', - shortMessage: '', - hidePopoverIcon: true, - }, - ]) - ); - }); - - it('should not render the vis if loaded saved object conflicts', async () => { - attributeService.unwrapAttributes = jest.fn( - (_input: LensByValueInput | LensByReferenceInput) => { - return Promise.resolve({ - attributes: { - ...savedVis, - }, - metaInfo: { - sharingSavedObjectProps: { - outcome: 'conflict', - sourceId: '1', - aliasTargetId: '2', - }, - }, - } as LensUnwrapResult); - } - ); - const spacesPluginStart = spacesPluginMock.createStartContract(); - spacesPluginStart.ui.components.getEmbeddableLegacyUrlConflict = jest.fn(() => ( - <>getEmbeddableLegacyUrlConflict</> - )); - const embeddable = new Embeddable( - getEmbeddableProps({ - spaces: spacesPluginStart, - attributeService, - }), - {} as LensEmbeddableInput - ); - await embeddable.initializeSavedVis({} as LensEmbeddableInput); - embeddable.render(mountpoint); - expect(expressionRenderer).toHaveBeenCalledTimes(0); - expect(spacesPluginStart.ui.components.getEmbeddableLegacyUrlConflict).toHaveBeenCalled(); - }); - - it('should not render if timeRange prop is not passed when a referenced data view is time based', async () => { - const embeddable = new Embeddable( - getEmbeddableProps({ - attributeService: attributeServiceMockFromSavedVis({ - ...savedVis, - references: [ - { type: 'index-pattern', id: '123', name: 'abc' }, - { type: 'index-pattern', id: '123', name: 'def' }, - { type: 'index-pattern', id: '456', name: 'ghi' }, - ], - }), - dataViews: { - get: (id: string) => Promise.resolve({ id, isTimeBased: () => true }), - } as unknown as DataViewsContract, - }), - {} as LensEmbeddableInput - ); - await embeddable.initializeSavedVis({} as LensEmbeddableInput); - embeddable.render(mountpoint); - expect(expressionRenderer).toHaveBeenCalledTimes(0); - }); - - it('should initialize output with deduped list of index patterns', async () => { - const embeddable = new Embeddable( - getEmbeddableProps({ - attributeService: attributeServiceMockFromSavedVis({ - ...savedVis, - references: [ - { type: 'index-pattern', id: '123', name: 'abc' }, - { type: 'index-pattern', id: '123', name: 'def' }, - { type: 'index-pattern', id: '456', name: 'ghi' }, - ], - }), - }), - {} as LensEmbeddableInput - ); - - await embeddable.initializeSavedVis({} as LensEmbeddableInput); - const outputIndexPatterns = embeddable.getOutput().indexPatterns!; - expect(outputIndexPatterns.length).toEqual(2); - expect(outputIndexPatterns[0].id).toEqual('123'); - expect(outputIndexPatterns[1].id).toEqual('456'); - }); - - it('should re-render once on filter change', async () => { - const embeddable = new Embeddable( - { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService, - data: dataMock, - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - expressionRenderer, - coreStart, - basePath, - inspector: inspectorPluginMock.createStartContract(), - dataViews: {} as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - getTrigger, - visualizationMap: defaultVisualizationMap, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - }, - { id: '123' } as LensEmbeddableInput - ); - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ - filters: [{ meta: { alias: 'test', negate: false, disabled: false } }], - }); - - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(2); - }); - - it('should re-render once on search session change', async () => { - const embeddable = new Embeddable( - { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService, - data: dataMock, - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - expressionRenderer, - coreStart, - basePath, - inspector: inspectorPluginMock.createStartContract(), - dataViews: {} as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - getTrigger, - visualizationMap: defaultVisualizationMap, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - }, - { id: '123', searchSessionId: 'firstSession' } as LensEmbeddableInput - ); - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ - searchSessionId: 'nextSession', - }); - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(2); - }); - - it('should re-render when dashboard view/edit mode changes if dynamic actions are set', async () => { - const sampleInput = { - id: '123', - enhancements: { - dynamicActions: {}, - }, - } as unknown as LensEmbeddableInput; - const embeddable = new Embeddable(getEmbeddableProps(), { id: '123' } as LensEmbeddableInput); - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ - viewMode: ViewMode.VIEW, - }); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ - ...sampleInput, - viewMode: ViewMode.VIEW, - }); - - expect(expressionRenderer).toHaveBeenCalledTimes(2); - }); - - it('should re-render when dynamic actions input changes', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), { id: '123' } as LensEmbeddableInput); - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ - enhancements: { - dynamicActions: {}, - }, - }); - - expect(expressionRenderer).toHaveBeenCalledTimes(2); - }); - - it('should pass context to embeddable', async () => { - const timeRange: TimeRange = { from: 'now-15d', to: 'now' }; - const query: Query = { language: 'kquery', query: '' }; - const filters: Filter[] = [{ meta: { alias: 'test', negate: false, disabled: false } }]; - - const input = { - savedObjectId: '123', - timeRange, - query, - filters, - searchSessionId: 'searchSessionId', - } as LensEmbeddableInput; - - const embeddable = new Embeddable(getEmbeddableProps(), input); - await embeddable.initializeSavedVis(input); - embeddable.render(mountpoint); - - expect(expressionRenderer.mock.calls[0][0].searchContext).toEqual( - expect.objectContaining({ - timeRange, - query: [query, savedVis.state.query], - filters, - }) - ); - - expect(expressionRenderer.mock.calls[0][0].searchSessionId).toBe(input.searchSessionId); - }); - - it('should pass render mode to expression', async () => { - const timeRange: TimeRange = { from: 'now-15d', to: 'now' }; - const query: Query = { language: 'kquery', query: '' }; - const filters: Filter[] = [{ meta: { alias: 'test', negate: false, disabled: false } }]; - - const input = { - savedObjectId: '123', - timeRange, - query, - filters, - renderMode: 'view', - disableTriggers: true, - } as LensEmbeddableInput; - - const embeddable = new Embeddable(getEmbeddableProps(), input); - await embeddable.initializeSavedVis(input); - embeddable.render(mountpoint); - - expect(expressionRenderer.mock.calls[0][0]).toEqual( - expect.objectContaining({ - interactive: false, - renderMode: 'view', - }) - ); - }); - - it('should merge external context with query and filters of the saved object', async () => { - const timeRange: TimeRange = { from: 'now-15d', to: 'now' }; - const query: Query = { language: 'kquery', query: 'external query' }; - const filters: Filter[] = [ - { meta: { alias: 'external filter', negate: false, disabled: false } }, - ]; - - const newSavedVis = { - ...savedVis, - state: { - ...savedVis.state, - query: { language: 'kquery', query: 'saved filter' }, - filters: [{ meta: { alias: 'test', negate: false, disabled: false, index: 'filter-0' } }], - }, - references: [{ type: 'index-pattern', name: 'filter-0', id: 'my-index-pattern-id' }], - }; - - const input = { savedObjectId: '123', timeRange, query, filters } as LensEmbeddableInput; - - const embeddable = new Embeddable( - getEmbeddableProps({ attributeService: attributeServiceMockFromSavedVis(newSavedVis) }), - input - ); - await embeddable.initializeSavedVis(input); - embeddable.render(mountpoint); - - const expectedFilters = [ - ...input.filters!, - ...mockInjectFilterReferences(newSavedVis.state.filters, []), - ]; - expect(expressionRenderer.mock.calls[0][0].searchContext?.timeRange).toEqual(timeRange); - expect(expressionRenderer.mock.calls[0][0].searchContext?.filters).toEqual(expectedFilters); - expect(expressionRenderer.mock.calls[0][0].searchContext?.query).toEqual([ - query, - { language: 'kquery', query: 'saved filter' }, - ]); - }); - - it('should execute trigger on event from expression renderer', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), { id: '123' } as LensEmbeddableInput); - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - const onEvent = expressionRenderer.mock.calls[0][0].onEvent!; - - const eventData = { myData: true, table: { rows: [], columns: [] }, column: 0 }; - onEvent({ name: 'brush', data: eventData }); - - expect(getTrigger).toHaveBeenCalledWith(VIS_EVENT_TO_TRIGGER.brush); - expect(trigger.exec).toHaveBeenCalledWith( - expect.objectContaining({ - data: { ...eventData, timeFieldName: undefined }, - embeddable: expect.anything(), - }) - ); - }); - - it('should execute trigger on row click event from expression renderer', async () => { - const embeddable = new Embeddable(getEmbeddableProps(), { id: '123' } as LensEmbeddableInput); - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - const onEvent = expressionRenderer.mock.calls[0][0].onEvent!; - - onEvent({ name: 'tableRowContextMenuClick', data: {} }); - - expect(getTrigger).toHaveBeenCalledWith(VIS_EVENT_TO_TRIGGER.tableRowContextMenuClick); - }); - - it('should not re-render if only change is in disabled filter', async () => { - const timeRange: TimeRange = { from: 'now-15d', to: 'now' }; - const query: Query = { language: 'kquery', query: '' }; - const filters: Filter[] = [{ meta: { alias: 'test', negate: false, disabled: true } }]; - - const embeddable = new Embeddable(getEmbeddableProps(), { - id: '123', - timeRange, - query, - filters, - } as LensEmbeddableInput); - await embeddable.initializeSavedVis({ - id: '123', - timeRange, - query, - filters, - } as LensEmbeddableInput); - embeddable.render(mountpoint); - - act(() => { - embeddable.updateInput({ - timeRange, - query, - filters: [{ meta: { alias: 'test', negate: true, disabled: true } }], - }); - }); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - }); - - it('should call onload after rerender and onData$ call ', async () => { - const onDataTimeout = 10; - const onLoad = jest.fn(); - const adapters = { tables: {} }; - - expressionRenderer = jest.fn(({ onData$ }) => { - setTimeout(() => { - onData$?.({}, adapters); - }, onDataTimeout); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onLoad, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - expect(onLoad).toHaveBeenCalledWith(true); - expect(onLoad).toHaveBeenCalledTimes(1); - - await new Promise((resolve) => setTimeout(resolve, onDataTimeout * 1.5)); - - // loading should become false - expect(onLoad).toHaveBeenCalledTimes(2); - expect(onLoad).toHaveBeenNthCalledWith(2, false, adapters, embeddable.getOutput$()); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - - embeddable.updateInput({ - searchSessionId: 'newSession', - }); - - await new Promise((resolve) => setTimeout(resolve, 0)); - - // loading should become again true - expect(onLoad).toHaveBeenCalledTimes(3); - expect(onLoad).toHaveBeenNthCalledWith(3, true); - expect(expressionRenderer).toHaveBeenCalledTimes(2); - - await new Promise((resolve) => setTimeout(resolve, onDataTimeout * 1.5)); - - // loading should again become false - expect(onLoad).toHaveBeenCalledTimes(4); - expect(onLoad).toHaveBeenNthCalledWith(4, false, adapters, embeddable.getOutput$()); - }); - - it('should call onFilter event on filter call ', async () => { - const onFilter = jest.fn(); - - expressionRenderer = jest.fn(({ onEvent }) => { - setTimeout(() => { - onEvent?.({ - name: 'filter', - data: { pings: false, table: { rows: [], columns: [] }, column: 0 }, - }); - }, 10); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onFilter, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 20)); - - expect(onFilter).toHaveBeenCalledWith(expect.objectContaining({ pings: false })); - expect(onFilter).toHaveBeenCalledTimes(1); - }); - - it('should prevent the onFilter trigger when calling preventDefault', async () => { - const onFilter = jest.fn(({ preventDefault }) => preventDefault()); - - expressionRenderer = jest.fn(({ onEvent }) => { - setTimeout(() => { - onEvent?.({ - name: 'filter', - data: { pings: false, table: { rows: [], columns: [] }, column: 0 }, - }); - }, 10); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onFilter, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 20)); - - expect(getTrigger).not.toHaveBeenCalled(); - }); - - it('should call onBrush event on brushing', async () => { - const onBrushEnd = jest.fn(); - - expressionRenderer = jest.fn(({ onEvent }) => { - setTimeout(() => { - onEvent?.({ - name: 'brush', - data: { range: [0, 1], table: { rows: [], columns: [] }, column: 0 }, - }); - }, 10); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onBrushEnd, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 20)); - - expect(onBrushEnd).toHaveBeenCalledWith(expect.objectContaining({ range: [0, 1] })); - expect(onBrushEnd).toHaveBeenCalledTimes(1); - }); - - it('should prevent the onBrush trigger when calling preventDefault', async () => { - const onBrushEnd = jest.fn(({ preventDefault }) => preventDefault()); - - expressionRenderer = jest.fn(({ onEvent }) => { - setTimeout(() => { - onEvent?.({ - name: 'brush', - data: { range: [0, 1], table: { rows: [], columns: [] }, column: 0 }, - }); - }, 10); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onBrushEnd, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 20)); - - expect(getTrigger).not.toHaveBeenCalled(); - }); - - it('should call onTableRowClick event ', async () => { - const onTableRowClick = jest.fn(); - - expressionRenderer = jest.fn(({ onEvent }) => { - setTimeout(() => { - onEvent?.({ name: 'tableRowContextMenuClick', data: { name: 'test' } }); - }, 10); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onTableRowClick, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 20)); - - expect(onTableRowClick).toHaveBeenCalledWith(expect.objectContaining({ name: 'test' })); - expect(onTableRowClick).toHaveBeenCalledTimes(1); - }); - - it('should prevent onTableRowClick trigger when calling preventDefault ', async () => { - const onTableRowClick = jest.fn(({ preventDefault }) => preventDefault()); - - expressionRenderer = jest.fn(({ onEvent }) => { - setTimeout(() => { - onEvent?.({ name: 'tableRowContextMenuClick', data: { name: 'test' } }); - }, 10); - - return null; - }); - - const embeddable = new Embeddable(getEmbeddableProps({ expressionRenderer }), { - id: '123', - onTableRowClick, - } as unknown as LensEmbeddableInput); - - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 20)); - - expect(getTrigger).not.toHaveBeenCalled(); - }); - - it('handles edit actions ', async () => { - const editedVisualizationState = { value: 'edited' }; - const onEditActionMock = jest.fn().mockReturnValue(editedVisualizationState); - const documentToExpressionMock = jest.fn().mockImplementation(async (document) => { - const isStateEdited = document.state.visualization.value === 'edited'; - return { - ast: { - type: 'expression', - chain: [ - { - type: 'function', - function: isStateEdited ? 'edited' : 'not_edited', - arguments: {}, - }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - }; - }); - - const visDocument: Document = { - state: { - visualization: {}, - datasourceStates: { [defaultDatasourceId]: {} }, - query: { query: '', language: 'lucene' }, - filters: [], - }, - references: [], - title: 'My title', - visualizationType: 'lensDatatable', - }; - - const embeddable = new Embeddable( - getEmbeddableProps({ - attributeService: attributeServiceMockFromSavedVis(visDocument), - visualizationMap: { - [visDocument.visualizationType as string]: { - onEditAction: onEditActionMock, - initialize: () => {}, - } as unknown as Visualization, - }, - documentToExpression: documentToExpressionMock, - }), - { id: '123' } as unknown as LensEmbeddableInput - ); - - // SETUP FRESH STATE - await embeddable.initializeSavedVis({ id: '123' } as LensEmbeddableInput); - embeddable.render(mountpoint); - - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - expect(expressionRenderer.mock.calls[0][0]!.expression).toBe(`not_edited`); - - // TEST EDIT EVENT - await embeddable.handleEvent({ name: 'edit' }); - - expect(onEditActionMock).toHaveBeenCalledTimes(1); - expect(documentToExpressionMock).toHaveBeenCalled(); - - const docToExpCalls = documentToExpressionMock.mock.calls; - const editedVisDocument = docToExpCalls[docToExpCalls.length - 1][0]; - expect(editedVisDocument.state.visualization).toEqual(editedVisualizationState); - - expect(expressionRenderer).toHaveBeenCalledTimes(2); - expect(expressionRenderer.mock.calls[1][0]!.expression).toBe(`edited`); - }); - - it('should override noPadding in the display options if noPadding is set in the embeddable input', async () => { - expressionRenderer = jest.fn((_) => null); - - const createEmbeddable = (displayOptions?: { noPadding: boolean }, noPadding?: boolean) => { - return new Embeddable( - { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService: attributeServiceMockFromSavedVis(savedVis), - data: dataMock, - expressionRenderer, - coreStart, - basePath, - dataViews: {} as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - inspector: inspectorPluginMock.createStartContract(), - getTrigger, - visualizationMap: { - [savedVis.visualizationType as string]: { - getDisplayOptions: displayOptions ? () => displayOptions : undefined, - initialize: () => {}, - } as unknown as Visualization, - }, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - }, - { - timeRange: { - from: 'now-15m', - to: 'now', - }, - noPadding, - } as LensEmbeddableInput - ); - }; - - // no display options and no override - let embeddable = createEmbeddable(); - embeddable.render(mountpoint); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - expect(expressionRenderer.mock.calls[0][0]!.padding).toBe('s'); - - // display options and no override - embeddable = createEmbeddable({ noPadding: true }); - embeddable.render(mountpoint); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(2); - expect(expressionRenderer.mock.calls[1][0]!.padding).toBe(undefined); - - // no display options and override - embeddable = createEmbeddable(undefined, true); - embeddable.render(mountpoint); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(3); - expect(expressionRenderer.mock.calls[1][0]!.padding).toBe(undefined); - - // display options and override - embeddable = createEmbeddable({ noPadding: false }, true); - embeddable.render(mountpoint); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(4); - expect(expressionRenderer.mock.calls[1][0]!.padding).toBe(undefined); - }); - - it('should reload only once when the attributes or savedObjectId and the search context change at the same time', async () => { - const createEmbeddable = async () => { - const currentExpressionRenderer = jest.fn((_props) => null); - const timeRange: TimeRange = { from: 'now-15d', to: 'now' }; - const query: Query = { language: 'kquery', query: '' }; - const filters: Filter[] = [{ meta: { alias: 'test', negate: false, disabled: true } }]; - const embeddable = new Embeddable( - { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService, - data: dataMock, - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - expressionRenderer: currentExpressionRenderer, - coreStart, - basePath, - inspector: inspectorPluginMock.createStartContract(), - dataViews: {} as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - getTrigger, - visualizationMap: defaultVisualizationMap, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - }, - { id: '123', timeRange, query, filters } as LensEmbeddableInput - ); - const reload = jest.spyOn(embeddable, 'reload'); - const initializeSavedVis = jest.spyOn(embeddable, 'initializeSavedVis'); - - await embeddable.initializeSavedVis({ - id: '123', - timeRange, - query, - filters, - } as LensEmbeddableInput); - - embeddable.render(mountpoint); - - return { - embeddable, - reload, - initializeSavedVis, - expressionRenderer: currentExpressionRenderer, - }; - }; - - let test = await createEmbeddable(); - - expect(test.reload).toHaveBeenCalledTimes(1); - expect(test.initializeSavedVis).toHaveBeenCalledTimes(1); - expect(test.expressionRenderer).toHaveBeenCalledTimes(1); - - // Test with savedObjectId and searchSessionId change - act(() => { - test.embeddable.updateInput({ savedObjectId: '123', searchSessionId: '456' }); - }); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(test.reload).toHaveBeenCalledTimes(2); - expect(test.initializeSavedVis).toHaveBeenCalledTimes(2); - expect(test.expressionRenderer).toHaveBeenCalledTimes(2); - - test = await createEmbeddable(); - - expect(test.reload).toHaveBeenCalledTimes(1); - expect(test.initializeSavedVis).toHaveBeenCalledTimes(1); - expect(test.expressionRenderer).toHaveBeenCalledTimes(1); - - // Test with attributes and timeRange change - act(() => { - test.embeddable.updateInput({ - attributes: { foo: 'bar' } as unknown as LensSavedObjectAttributes, - timeRange: { from: 'now-30d', to: 'now' }, - }); - }); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(test.reload).toHaveBeenCalledTimes(2); - expect(test.initializeSavedVis).toHaveBeenCalledTimes(2); - expect(test.expressionRenderer).toHaveBeenCalledTimes(2); - }); - - it('should get full attributes', async () => { - const createEmbeddable = async () => { - const currentExpressionRenderer = jest.fn((_props) => null); - const timeRange: TimeRange = { from: 'now-15d', to: 'now' }; - const query: Query = { language: 'kquery', query: '' }; - const filters: Filter[] = [{ meta: { alias: 'test', negate: false, disabled: true } }]; - const embeddable = new Embeddable( - { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService, - data: dataMock, - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - expressionRenderer: currentExpressionRenderer, - coreStart, - basePath, - inspector: inspectorPluginMock.createStartContract(), - dataViews: {} as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - getTrigger, - visualizationMap: defaultVisualizationMap, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - }, - { id: '123', timeRange, query, filters } as LensEmbeddableInput - ); - const reload = jest.spyOn(embeddable, 'reload'); - const initializeSavedVis = jest.spyOn(embeddable, 'initializeSavedVis'); - - await embeddable.initializeSavedVis({ - id: '123', - timeRange, - query, - filters, - } as LensEmbeddableInput); - - embeddable.render(mountpoint); - - return { - embeddable, - reload, - initializeSavedVis, - expressionRenderer: currentExpressionRenderer, - }; - }; - - const test = await createEmbeddable(); - - expect(test.embeddable.getFullAttributes()).toEqual(savedVis); - }); - - it('should pass over the overrides as variables', async () => { - const embeddable = new Embeddable( - { - timefilter: dataPluginMock.createSetupContract().query.timefilter.timefilter, - attributeService, - data: dataMock, - expressionRenderer, - coreStart, - basePath, - dataViews: {} as DataViewsContract, - capabilities: { - canSaveDashboards: true, - canSaveVisualizations: true, - canOpenVisualizations: true, - discover: {}, - navLinks: {}, - }, - inspector: inspectorPluginMock.createStartContract(), - getTrigger, - visualizationMap: defaultVisualizationMap, - datasourceMap: defaultDatasourceMap, - injectFilterReferences: jest.fn(mockInjectFilterReferences), - documentToExpression: () => - Promise.resolve({ - ast: { - type: 'expression', - chain: [ - { type: 'function', function: 'my', arguments: {} }, - { type: 'function', function: 'expression', arguments: {} }, - ], - }, - indexPatterns: {}, - indexPatternRefs: [], - activeVisualizationState: null, - }), - uiSettings: { get: () => undefined } as unknown as IUiSettingsClient, - }, - { - timeRange: { - from: 'now-15m', - to: 'now', - }, - overrides: { - settings: { - onBrushEnd: 'ignore', - }, - }, - } as LensEmbeddableInput - ); - embeddable.render(mountpoint); - - // wait one tick to give embeddable time to initialize - await new Promise((resolve) => setTimeout(resolve, 0)); - - expect(expressionRenderer).toHaveBeenCalledTimes(1); - expect(expressionRenderer.mock.calls[0][0]!.variables).toEqual( - expect.objectContaining({ - overrides: { - settings: { - onBrushEnd: 'ignore', - }, - }, - }) - ); - }); - - it('should not be editable for no visualize library privileges', async () => { - const embeddable = new Embeddable( - getEmbeddableProps({ - capabilities: { - canSaveDashboards: false, - canSaveVisualizations: true, - canOpenVisualizations: false, - discover: {}, - navLinks: {}, - }, - }), - { - timeRange: { - from: 'now-15m', - to: 'now', - }, - } as LensEmbeddableInput - ); - expect(embeddable.getOutput().editable).toBeUndefined(); - }); -}); diff --git a/x-pack/plugins/lens/public/embeddable/embeddable.tsx b/x-pack/plugins/lens/public/embeddable/embeddable.tsx deleted file mode 100644 index ce86b896d5fa..000000000000 --- a/x-pack/plugins/lens/public/embeddable/embeddable.tsx +++ /dev/null @@ -1,1719 +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 { partition, uniqBy } from 'lodash'; -import React from 'react'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { css } from '@emotion/react'; -import { i18n } from '@kbn/i18n'; -import { render, unmountComponentAtNode } from 'react-dom'; -import { ENABLE_ESQL } from '@kbn/esql-utils'; -import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; -import { - DataViewBase, - EsQueryConfig, - Filter, - Query, - AggregateQuery, - TimeRange, - isOfQueryType, - getAggregateQueryMode, - ExecutionContextSearch, - getLanguageDisplayName, - isOfAggregateQueryType, -} from '@kbn/es-query'; -import type { PaletteOutput } from '@kbn/coloring'; -import { - DataPublicPluginStart, - TimefilterContract, - FilterManager, - getEsQueryConfig, - mapAndFlattenFilters, -} from '@kbn/data-plugin/public'; -import type { Start as InspectorStart } from '@kbn/inspector-plugin/public'; - -import { merge, Subscription, switchMap } from 'rxjs'; -import { toExpression } from '@kbn/interpreter'; -import { - Datatable, - DefaultInspectorAdapters, - ErrorLike, - RenderMode, -} from '@kbn/expressions-plugin/common'; -import { map, distinctUntilChanged, skip, debounceTime } from 'rxjs'; -import fastIsEqual from 'fast-deep-equal'; -import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; -import { - ExpressionRendererEvent, - ReactExpressionRendererType, -} from '@kbn/expressions-plugin/public'; -import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; - -import { - EmbeddableStateTransfer, - Embeddable as AbstractEmbeddable, - EmbeddableInput, - EmbeddableOutput, - IContainer, - SavedObjectEmbeddableInput, - ReferenceOrValueEmbeddable, - SelfStyledEmbeddable, - FilterableEmbeddable, - cellValueTrigger, - CELL_VALUE_TRIGGER, - type CellValueContext, - shouldFetch$, -} from '@kbn/embeddable-plugin/public'; -import type { Action, UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import type { DataViewsContract, DataView } from '@kbn/data-views-plugin/public'; -import type { - Capabilities, - CoreStart, - IBasePath, - IUiSettingsClient, - KibanaExecutionContext, -} from '@kbn/core/public'; -import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import { - BrushTriggerEvent, - ClickTriggerEvent, - MultiClickTriggerEvent, -} from '@kbn/charts-plugin/public'; -import { DataViewSpec } from '@kbn/data-views-plugin/common'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { useEuiFontSize, useEuiTheme, EuiEmptyPrompt } from '@elastic/eui'; -import { canTrackContentfulRender } from '@kbn/presentation-containers'; -import { getSuccessfulRequestTimings } from '../report_performance_metric_util'; -import { getExecutionContextEvents, trackUiCounterEvents } from '../lens_ui_telemetry'; -import { Document } from '../persistence'; -import { ExpressionWrapper, ExpressionWrapperProps } from './expression_wrapper'; -import { - isLensBrushEvent, - isLensFilterEvent, - isLensMultiFilterEvent, - isLensEditEvent, - isLensTableRowContextMenuClickEvent, - LensTableRowContextMenuEvent, - VisualizationMap, - Visualization, - DatasourceMap, - Datasource, - IndexPatternMap, - GetCompatibleCellValueActions, - UserMessage, - IndexPatternRef, - FramePublicAPI, - AddUserMessages, - UserMessagesGetter, - UserMessagesDisplayLocationId, -} from '../types'; - -import type { - AllowedChartOverrides, - AllowedPartitionOverrides, - AllowedSettingsOverrides, - AllowedGaugeOverrides, - AllowedXYOverrides, -} from '../../common/types'; -import { getEditPath, DOC_TYPE, APP_ID } from '../../common/constants'; -import { LensAttributeService } from '../lens_attribute_service'; -import type { TableInspectorAdapter } from '../editor_frame_service/types'; -import { getLensInspectorService, LensInspector } from '../lens_inspector_service'; -import { SharingSavedObjectProps, VisualizationDisplayOptions } from '../types'; -import { - getActiveDatasourceIdFromDoc, - getActiveVisualizationIdFromDoc, - getIndexPatternsObjects, - getSearchWarningMessages, - inferTimeField, - extractReferencesFromState, -} from '../utils'; -import { getLayerMetaInfo, combineQueryAndFilters } from '../app_plugin/show_underlying_data'; -import { - filterAndSortUserMessages, - getApplicationUserMessages, -} from '../app_plugin/get_application_user_messages'; -import { MessageList } from '../editor_frame_service/editor_frame/workspace_panel/message_list'; -import type { DocumentToExpressionReturnType } from '../editor_frame_service/editor_frame'; -import type { TypedLensByValueInput } from './embeddable_component'; -import type { LensPluginStartDependencies } from '../plugin'; -import { EmbeddableFeatureBadge } from './embeddable_info_badges'; -import { getDatasourceLayers } from '../state_management/utils'; -import type { EditLensConfigurationProps } from '../app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration'; -import { TextBasedPersistedState } from '../datasources/text_based/types'; -import { getLongMessage } from '../user_messages_utils'; - -export type LensSavedObjectAttributes = Omit<Document, 'savedObjectId' | 'type'>; - -export interface LensUnwrapMetaInfo { - sharingSavedObjectProps?: SharingSavedObjectProps; - managed?: boolean; -} - -export interface LensUnwrapResult { - attributes: LensSavedObjectAttributes; - metaInfo?: LensUnwrapMetaInfo; -} - -interface PreventableEvent { - preventDefault(): void; -} - -export type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {}; - -export interface LensBaseEmbeddableInput extends EmbeddableInput { - filters?: Filter[]; - query?: Query; - timeRange?: TimeRange; - timeslice?: [number, number]; - palette?: PaletteOutput; - renderMode?: RenderMode; - style?: React.CSSProperties; - className?: string; - noPadding?: boolean; - onBrushEnd?: (data: Simplify<BrushTriggerEvent['data'] & PreventableEvent>) => void; - onLoad?: ( - isLoading: boolean, - adapters?: Partial<DefaultInspectorAdapters>, - output$?: Observable<LensEmbeddableOutput> - ) => void; - onFilter?: ( - data: Simplify<(ClickTriggerEvent['data'] | MultiClickTriggerEvent['data']) & PreventableEvent> - ) => void; - onTableRowClick?: ( - data: Simplify<LensTableRowContextMenuEvent['data'] & PreventableEvent> - ) => void; - abortController?: AbortController; - onBeforeBadgesRender?: (userMessages: UserMessage[]) => UserMessage[]; -} - -export type LensByValueInput = { - attributes: LensSavedObjectAttributes; - /** - * Overrides can tweak the style of the final embeddable and are executed at the end of the Lens rendering pipeline. - * Each visualization type offers various type of overrides, per component (i.e. 'setting', 'axisX', 'partition', etc...) - * - * While it is not possible to pass function/callback/handlers to the renderer, it is possible to overwrite - * the current behaviour by passing the "ignore" string to the override prop (i.e. onBrushEnd: "ignore" to stop brushing) - */ - overrides?: - | AllowedChartOverrides - | AllowedSettingsOverrides - | AllowedXYOverrides - | AllowedPartitionOverrides - | AllowedGaugeOverrides; -} & LensBaseEmbeddableInput; - -export type LensByReferenceInput = SavedObjectEmbeddableInput & LensBaseEmbeddableInput; -export type LensEmbeddableInput = LensByValueInput | LensByReferenceInput; - -export interface LensEmbeddableOutput extends EmbeddableOutput { - indexPatterns?: DataView[]; -} - -export interface LensEmbeddableDeps { - attributeService: LensAttributeService; - data: DataPublicPluginStart; - documentToExpression: (doc: Document) => Promise<DocumentToExpressionReturnType>; - injectFilterReferences: FilterManager['inject']; - visualizationMap: VisualizationMap; - datasourceMap: DatasourceMap; - dataViews: DataViewsContract; - expressionRenderer: ReactExpressionRendererType; - timefilter: TimefilterContract; - basePath: IBasePath; - inspector: InspectorStart; - getTrigger?: UiActionsStart['getTrigger'] | undefined; - getTriggerCompatibleActions?: UiActionsStart['getTriggerCompatibleActions']; - capabilities: { - canSaveVisualizations: boolean; - canOpenVisualizations: boolean; - canSaveDashboards: boolean; - navLinks: Capabilities['navLinks']; - discover: Capabilities['discover']; - }; - coreStart: CoreStart; - usageCollection?: UsageCollectionSetup; - spaces?: SpacesPluginStart; - uiSettings: IUiSettingsClient; -} - -export interface ViewUnderlyingDataArgs { - dataViewSpec: DataViewSpec; - timeRange: TimeRange; - filters: Filter[]; - query: Query | AggregateQuery | undefined; - columns: string[]; -} - -function VisualizationErrorPanel({ errors, canEdit }: { errors: UserMessage[]; canEdit: boolean }) { - const firstError = errors.at(0); - const canFixInLens = canEdit && errors.some(({ fixableInEditor }) => fixableInEditor); - return ( - <div className="lnsEmbeddedError"> - <EuiEmptyPrompt - iconType="warning" - iconColor="danger" - data-test-subj="embeddable-lens-failure" - body={ - <> - {firstError ? ( - <> - <p>{getLongMessage(firstError)}</p> - {errors.length > 1 && !canFixInLens ? ( - <p> - <FormattedMessage - id="xpack.lens.embeddable.moreErrors" - defaultMessage="Edit in Lens editor to see more errors" - /> - </p> - ) : null} - {canFixInLens ? ( - <p> - <FormattedMessage - id="xpack.lens.embeddable.fixErrors" - defaultMessage="Edit in Lens editor to fix the error" - /> - </p> - ) : null} - </> - ) : ( - <p> - <FormattedMessage - id="xpack.lens.embeddable.failure" - defaultMessage="Visualization couldn't be displayed" - /> - </p> - )} - </> - } - /> - </div> - ); -} - -const getExpressionFromDocument = async ( - document: Document, - documentToExpression: LensEmbeddableDeps['documentToExpression'] -) => { - const { ast, indexPatterns, indexPatternRefs, activeVisualizationState } = - await documentToExpression(document); - return { - ast: ast ? toExpression(ast) : null, - indexPatterns, - indexPatternRefs, - activeVisualizationState, - }; -}; - -function getViewUnderlyingDataArgs({ - activeDatasource, - activeDatasourceState, - activeVisualization, - activeVisualizationState, - activeData, - dataViews, - capabilities, - query, - filters, - timeRange, - esQueryConfig, - indexPatternsCache, -}: { - activeDatasource: Datasource; - activeDatasourceState: unknown; - activeVisualization: Visualization; - activeVisualizationState: unknown; - activeData: TableInspectorAdapter | undefined; - dataViews: DataViewBase[] | undefined; - capabilities: LensEmbeddableDeps['capabilities']; - query: ExecutionContextSearch['query']; - filters: Filter[]; - timeRange: TimeRange; - esQueryConfig: EsQueryConfig; - indexPatternsCache: IndexPatternMap; -}) { - const { error, meta } = getLayerMetaInfo( - activeDatasource, - activeDatasourceState, - activeVisualization, - activeVisualizationState, - activeData, - indexPatternsCache, - timeRange, - capabilities - ); - - if (error || !meta) { - return; - } - const luceneOrKuery: Query[] = []; - const aggregateQuery: AggregateQuery[] = []; - - if (Array.isArray(query)) { - query.forEach((q) => { - if (isOfQueryType(q)) { - luceneOrKuery.push(q); - } else { - aggregateQuery.push(q); - } - }); - } - - const { filters: newFilters, query: newQuery } = combineQueryAndFilters( - luceneOrKuery.length > 0 ? luceneOrKuery : (query as Query), - filters, - meta, - dataViews, - esQueryConfig - ); - - const dataViewSpec = indexPatternsCache[meta.id]!.spec; - - return { - dataViewSpec, - timeRange, - filters: newFilters, - query: aggregateQuery.length > 0 ? aggregateQuery[0] : newQuery, - columns: meta.columns, - }; -} - -const EmbeddableMessagesPopover = ({ messages }: { messages: UserMessage[] }) => { - const { euiTheme } = useEuiTheme(); - const xsFontSize = useEuiFontSize('xs').fontSize; - - if (!messages.length) { - return null; - } - - return ( - <MessageList - messages={messages} - customButtonStyles={css` - block-size: ${euiTheme.size.l}; - font-size: ${xsFontSize}; - padding: 0 ${euiTheme.size.xs}; - & > * { - gap: ${euiTheme.size.xs}; - } - `} - /> - ); -}; - -const blockingMessageDisplayLocations: UserMessagesDisplayLocationId[] = [ - 'visualization', - 'visualizationOnEmbeddable', -]; - -const MessagesBadge = ({ onMount }: { onMount: (el: HTMLDivElement) => void }) => ( - <div - css={css({ - position: 'absolute', - zIndex: 2, - left: 0, - bottom: 0, - })} - ref={(el) => { - if (el) { - onMount(el); - } - }} - /> -); - -export class Embeddable - extends AbstractEmbeddable<LensEmbeddableInput, LensEmbeddableOutput> - implements - ReferenceOrValueEmbeddable<LensByValueInput, LensByReferenceInput>, - SelfStyledEmbeddable, - FilterableEmbeddable -{ - type = DOC_TYPE; - - deferEmbeddableLoad = true; - - private expressionRenderer: ReactExpressionRendererType; - private savedVis: Document | undefined; - private expression: string | undefined | null; - private domNode: HTMLElement | Element | undefined; - private isInitialized = false; - private inputReloadSubscriptions: Subscription[]; - private isDestroyed?: boolean; - private lensInspector: LensInspector; - - private logError(type: 'runtime' | 'validation') { - trackUiCounterEvents( - type === 'runtime' ? 'embeddable_runtime_error' : 'embeddable_validation_error', - this.getExecutionContext() - ); - } - - private activeData?: TableInspectorAdapter; - - private internalDataViews: DataView[] = []; - - private viewUnderlyingDataArgs?: ViewUnderlyingDataArgs; - - private activeVisualizationState?: unknown; - - constructor( - private deps: LensEmbeddableDeps, - initialInput: LensEmbeddableInput, - parent?: IContainer - ) { - super( - initialInput, - { - editApp: 'lens', - }, - parent - ); - - this.lensInspector = getLensInspectorService(deps.inspector); - this.expressionRenderer = deps.expressionRenderer; - this.initializeSavedVis(initialInput) - .then(() => { - this.reload(); - }) - .catch((e) => this.onFatalError(e)); - - const input$ = this.getInput$(); - - this.inputReloadSubscriptions = []; - - // Lens embeddable does not re-render when embeddable input changes in - // general, to improve performance. This line makes sure the Lens embeddable - // re-renders when anything in ".dynamicActions" (e.g. drilldowns) changes. - this.inputReloadSubscriptions.push( - input$ - .pipe( - map((input) => input.enhancements?.dynamicActions), - distinctUntilChanged((a, b) => fastIsEqual(a, b)), - skip(1) - ) - .subscribe((_input) => { - this.reload(); - }) - ); - - // Lens embeddable does not re-render when embeddable input changes in - // general, to improve performance. This line makes sure the Lens embeddable - // re-renders when dashboard view mode switches between "view/edit". This is - // needed to see the changes to ".dynamicActions" (e.g. drilldowns) when - // dashboard's mode is toggled. - this.inputReloadSubscriptions.push( - input$ - .pipe( - map((input) => input.viewMode), - distinctUntilChanged(), - skip(1) - ) - .subscribe((_input) => { - // only reload if drilldowns are set - if (this.getInput().enhancements?.dynamicActions) { - this.reload(); - } - }) - ); - - // Use a trigger to distinguish between observables in the subscription - const withTrigger = (trigger: 'attributesOrSavedObjectId' | 'searchContext') => - map((input: LensEmbeddableInput) => ({ trigger, input })); - - // Re-initialize the visualization if either the attributes or the saved object id changes - const attributesOrSavedObjectId$ = input$.pipe( - distinctUntilChanged((a, b) => - fastIsEqual( - [ - 'attributes' in a && a.attributes, - 'savedObjectId' in a && a.savedObjectId, - 'overrides' in a && a.overrides, - 'disableTriggers' in a && a.disableTriggers, - ], - [ - 'attributes' in b && b.attributes, - 'savedObjectId' in b && b.savedObjectId, - 'overrides' in b && b.overrides, - 'disableTriggers' in b && b.disableTriggers, - ] - ) - ), - skip(1), - withTrigger('attributesOrSavedObjectId') - ); - - // Update search context and reload on changes related to search - const searchContext$ = shouldFetch$<LensEmbeddableInput>(input$, () => this.getInput()).pipe( - withTrigger('searchContext') - ); - - // Merge and debounce the observables to avoid multiple reloads - this.inputReloadSubscriptions.push( - merge(searchContext$, attributesOrSavedObjectId$) - .pipe( - debounceTime(0), - switchMap(async ({ trigger, input }) => { - if (trigger === 'attributesOrSavedObjectId') { - await this.initializeSavedVis(input); - } - - // reset removable messages - // Dashboard search/context changes are detected here - this.additionalUserMessages = {}; - - this.reload(); - }) - ) - .subscribe() - ); - } - - private get activeDatasourceId() { - return getActiveDatasourceIdFromDoc(this.savedVis); - } - - private get activeDatasource() { - if (!this.activeDatasourceId) return; - return this.deps.datasourceMap[this.activeDatasourceId]; - } - - private get activeVisualizationId() { - return getActiveVisualizationIdFromDoc(this.savedVis); - } - - private get activeVisualization() { - if (!this.activeVisualizationId) return; - return this.deps.visualizationMap[this.activeVisualizationId]; - } - - private indexPatterns: IndexPatternMap = {}; - - private indexPatternRefs: IndexPatternRef[] = []; - - // TODO - consider getting this from the persistedStateToExpression function - // where it is already computed - private get activeDatasourceState(): undefined | unknown { - if (!this.activeDatasourceId || !this.activeDatasource) return; - - const docDatasourceState = this.savedVis?.state.datasourceStates[this.activeDatasourceId]; - - return this.activeDatasource.initialize( - docDatasourceState, - [...(this.savedVis?.references || []), ...(this.savedVis?.state.internalReferences || [])], - undefined, - undefined, - this.indexPatterns - ); - } - - private fullAttributes: LensSavedObjectAttributes | undefined; - - private handleExternalUserMessage = (messages: UserMessage[]) => { - if (this.input.onBeforeBadgesRender) { - // we need something else to better identify those errors - const [messagesToHandle, originalMessages] = partition(messages, (message) => - message.displayLocations.some((location) => location.id === 'embeddableBadge') - ); - - if (messagesToHandle.length > 0) { - const customBadgeMessages = this.input.onBeforeBadgesRender(messagesToHandle); - return [...originalMessages, ...customBadgeMessages]; - } - } - - return messages; - }; - - public getUserMessages: UserMessagesGetter = (locationId, filters) => { - const userMessages: UserMessage[] = []; - userMessages.push( - ...getApplicationUserMessages({ - visualizationType: this.savedVis?.visualizationType, - visualizationState: { - state: this.activeVisualizationState, - activeId: this.activeVisualizationId, - }, - visualization: - this.activeVisualizationId && this.deps.visualizationMap[this.activeVisualizationId] - ? this.deps.visualizationMap[this.activeVisualizationId] - : undefined, - activeDatasource: this.activeDatasource, - activeDatasourceState: { - isLoading: !this.activeDatasourceState, - state: this.activeDatasourceState, - }, - dataViews: { - indexPatterns: this.indexPatterns, - indexPatternRefs: this.indexPatternRefs, // TODO - are these actually used? - }, - core: this.deps.coreStart, - }) - ); - - if (!this.savedVis) { - return this.handleExternalUserMessage(userMessages); - } - - const mergedSearchContext = this.getMergedSearchContext(); - - const framePublicAPI: FramePublicAPI = { - dataViews: { - indexPatterns: this.indexPatterns, - indexPatternRefs: this.indexPatternRefs, - }, - datasourceLayers: getDatasourceLayers( - { - [this.activeDatasourceId!]: { - isLoading: !this.activeDatasourceState, - state: this.activeDatasourceState, - }, - }, - this.deps.datasourceMap, - this.indexPatterns - ), - query: this.savedVis.state.query, - filters: mergedSearchContext.filters ?? [], - dateRange: { - fromDate: mergedSearchContext.timeRange?.from ?? '', - toDate: mergedSearchContext.timeRange?.to ?? '', - }, - absDateRange: { - fromDate: mergedSearchContext.timeRange?.from ?? '', - toDate: mergedSearchContext.timeRange?.to ?? '', - }, - activeData: this.activeData, - }; - - userMessages.push( - ...(this.activeDatasource?.getUserMessages(this.activeDatasourceState, { - setState: () => {}, - frame: framePublicAPI, - visualizationInfo: this.activeVisualization?.getVisualizationInfo?.( - this.activeVisualizationState, - framePublicAPI - ), - }) ?? []), - ...(this.activeVisualization?.getUserMessages?.(this.activeVisualizationState, { - frame: framePublicAPI, - }) ?? []) - ); - - return this.handleExternalUserMessage( - filterAndSortUserMessages( - [...userMessages, ...Object.values(this.additionalUserMessages)], - locationId, - filters ?? {} - ) - ); - }; - - private additionalUserMessages: Record<string, UserMessage> = {}; - - // used to add warnings and errors from elsewhere in the embeddable - private addUserMessages: AddUserMessages = (messages) => { - const newMessageMap = { - ...this.additionalUserMessages, - }; - - const addedMessageIds: string[] = []; - messages.forEach((message) => { - if (!newMessageMap[message.uniqueId]) { - addedMessageIds.push(message.uniqueId); - newMessageMap[message.uniqueId] = message; - } - }); - - if (addedMessageIds.length) { - this.additionalUserMessages = newMessageMap; - this.renderUserMessages(); - } - - return () => { - messages.forEach(({ uniqueId }) => { - delete this.additionalUserMessages[uniqueId]; - }); - }; - }; - - public reportsEmbeddableLoad() { - return true; - } - - public supportedTriggers() { - if (!this.savedVis || !this.savedVis.visualizationType) { - return []; - } - - return this.deps.visualizationMap[this.savedVis.visualizationType]?.triggers || []; - } - - public getInspectorAdapters() { - return this.lensInspector.adapters; - } - - public getFullAttributes() { - return this.fullAttributes; - } - - public isTextBasedLanguage() { - if (!this.savedVis) { - return; - } - const query = this.savedVis.state.query; - return !isOfQueryType(query); - } - - public getTextBasedLanguage(): string | undefined { - if (!this.isTextBasedLanguage() || !this.savedVis?.state.query) { - return; - } - const query = this.savedVis?.state.query as unknown as AggregateQuery; - const language = getAggregateQueryMode(query); - return getLanguageDisplayName(language).toUpperCase(); - } - - /** - * Gets the Lens embeddable's datasource and visualization states - * updates the embeddable input - */ - async updateVisualization( - datasourceState: unknown, - visualizationState: unknown, - visualizationType?: string - ) { - const viz = this.savedVis; - const activeDatasourceId = (this.activeDatasourceId ?? - 'formBased') as EditLensConfigurationProps['datasourceId']; - if (viz?.state) { - const datasourceStates = { - ...viz.state.datasourceStates, - [activeDatasourceId]: datasourceState, - }; - const references = - activeDatasourceId === 'formBased' - ? extractReferencesFromState({ - activeDatasources: Object.keys(datasourceStates).reduce( - (acc, datasourceId) => ({ - ...acc, - [datasourceId]: this.deps.datasourceMap[datasourceId], - }), - {} - ), - datasourceStates: Object.fromEntries( - Object.entries(datasourceStates).map(([id, state]) => [ - id, - { isLoading: false, state }, - ]) - ), - visualizationState, - activeVisualization: this.activeVisualizationId - ? this.deps.visualizationMap[visualizationType ?? this.activeVisualizationId] - : undefined, - }) - : []; - const attrs = { - ...viz, - state: { - ...viz.state, - visualization: visualizationState, - datasourceStates, - }, - references, - visualizationType: visualizationType ?? viz.visualizationType, - }; - - /** - * SavedObjectId is undefined for by value panels and defined for the by reference ones. - * Here we are converting the by reference panels to by value when user is inline editing - */ - this.updateInput({ attributes: attrs, savedObjectId: undefined }); - /** - * Should load again the user messages, - * otherwise the embeddable state is stuck in an error state - */ - this.renderUserMessages(); - } - } - - async updateSuggestion(attrs: LensSavedObjectAttributes) { - const viz = this.savedVis; - const newViz = { - ...viz, - ...attrs, - }; - this.updateInput({ attributes: newViz }); - } - - /** - * Callback which allows the navigation to the editor. - * Used for the Edit in Lens link inside the inline editing flyout. - */ - private async navigateToLensEditor() { - const appContext = this.getAppContext(); - /** - * The origininating app variable is very important for the Save and Return button - * of the editor to work properly. - */ - const transferState = { - originatingApp: appContext?.currentAppId ?? 'dashboards', - originatingPath: appContext?.getCurrentPath?.(), - valueInput: this.getExplicitInput(), - embeddableId: this.id, - searchSessionId: this.getInput().searchSessionId, - }; - const transfer = new EmbeddableStateTransfer( - this.deps.coreStart.application.navigateToApp, - this.deps.coreStart.application.currentAppId$ - ); - if (transfer) { - await transfer.navigateToEditor(APP_ID, { - path: this.output.editPath, - state: transferState, - skipAppLeave: true, - }); - } - } - - public updateByRefInput(savedObjectId: string) { - const attrs = this.savedVis; - this.updateInput({ attributes: attrs, savedObjectId }); - } - - async openConfigPanel( - startDependencies: LensPluginStartDependencies, - isNewPanel?: boolean, - deletePanel?: () => void - ) { - const { getEditLensConfiguration } = await import('../async_services'); - const Component = await getEditLensConfiguration( - this.deps.coreStart, - startDependencies, - this.deps.visualizationMap, - this.deps.datasourceMap - ); - - const datasourceId = (this.activeDatasourceId ?? - 'formBased') as EditLensConfigurationProps['datasourceId']; - - const attributes = this.savedVis as TypedLensByValueInput['attributes']; - if (attributes) { - return ( - <Component - attributes={attributes} - updatePanelState={this.updateVisualization.bind(this)} - updateSuggestion={this.updateSuggestion.bind(this)} - datasourceId={datasourceId} - lensAdapters={this.lensInspector.adapters} - output$={this.getOutput$()} - panelId={this.id} - savedObjectId={this.savedVis?.savedObjectId} - updateByRefInput={this.updateByRefInput.bind(this)} - navigateToLensEditor={ - !this.isTextBasedLanguage() ? this.navigateToLensEditor.bind(this) : undefined - } - displayFlyoutHeader - canEditTextBasedQuery={this.isTextBasedLanguage()} - isNewPanel={isNewPanel} - deletePanel={deletePanel} - /> - ); - } - return null; - } - - async initializeSavedVis(input: LensEmbeddableInput) { - const unwrapResult: LensUnwrapResult | false = await this.deps.attributeService - .unwrapAttributes(input) - .catch((e: Error) => { - this.onFatalError(e); - return false; - }); - if (!unwrapResult || this.isDestroyed) { - return; - } - - const { metaInfo, attributes } = unwrapResult; - this.fullAttributes = attributes; - this.savedVis = { - ...attributes, - type: this.type, - savedObjectId: (input as LensByReferenceInput)?.savedObjectId, - }; - - if (this.isTextBasedLanguage()) { - this.updateInput({ - disabledActions: ['OPEN_FLYOUT_ADD_DRILLDOWN'], - }); - } - - try { - const { ast, indexPatterns, indexPatternRefs, activeVisualizationState } = - await getExpressionFromDocument(this.savedVis, this.deps.documentToExpression); - - this.expression = ast; - this.indexPatterns = indexPatterns; - this.indexPatternRefs = indexPatternRefs; - this.activeVisualizationState = activeVisualizationState; - } catch { - // nothing, errors should be reported via getUserMessages - } - - if (metaInfo?.sharingSavedObjectProps?.outcome === 'conflict' && !!this.deps.spaces) { - this.addUserMessages([ - { - uniqueId: 'url-conflict', - severity: 'error', - displayLocations: [{ id: 'visualization' }], - shortMessage: i18n.translate('xpack.lens.embeddable.legacyURLConflict.shortMessage', { - defaultMessage: `You've encountered a URL conflict`, - }), - longMessage: ( - <this.deps.spaces.ui.components.getEmbeddableLegacyUrlConflict - targetType={DOC_TYPE} - sourceId={metaInfo?.sharingSavedObjectProps?.sourceId!} - /> - ), - fixableInEditor: false, - }, - ]); - } - - await this.initializeOutput(); - - // deferred loading of this embeddable is complete - this.setInitializationFinished(); - - this.isInitialized = true; - } - - private getSearchWarningMessages(adapters?: Partial<DefaultInspectorAdapters>): UserMessage[] { - if (!this.activeDatasource || !this.activeDatasourceId || !adapters?.requests) { - return []; - } - - const docDatasourceState = this.savedVis?.state.datasourceStates[this.activeDatasourceId]; - - const requestWarnings = getSearchWarningMessages( - adapters.requests, - this.activeDatasource, - docDatasourceState, - { - searchService: this.deps.data.search, - } - ); - - return requestWarnings; - } - - private removeActiveDataWarningMessages: () => void = () => {}; - private updateActiveData: ExpressionWrapperProps['onData$'] = (data, adapters) => { - if (this.input.onLoad) { - // once onData$ is get's called from expression renderer, loading becomes false - this.input.onLoad(false, adapters, this.getOutput$()); - } - - const { type, error } = data as { type: string; error: ErrorLike }; - this.updateOutput({ - loading: false, - error: type === 'error' ? error : undefined, - }); - - const newActiveData = adapters?.tables?.tables; - - this.removeActiveDataWarningMessages(); - const searchWarningMessages = this.getSearchWarningMessages(adapters); - this.removeActiveDataWarningMessages = this.addUserMessages(searchWarningMessages); - - this.activeData = newActiveData; - - this.renderUserMessages(); - - this.loadViewUnderlyingDataArgs(); - }; - - private onRender: ExpressionWrapperProps['onRender$'] = () => { - let datasourceEvents: string[] = []; - let visualizationEvents: string[] = []; - - if (this.savedVis) { - datasourceEvents = Object.values(this.deps.datasourceMap).reduce<string[]>( - (acc, datasource) => [ - ...acc, - ...(datasource.getRenderEventCounters?.( - this.savedVis!.state.datasourceStates[datasource.id] - ) ?? []), - ], - [] - ); - - if (this.savedVis.visualizationType) { - visualizationEvents = - this.deps.visualizationMap[this.savedVis.visualizationType].getRenderEventCounters?.( - this.savedVis!.state.visualization - ) ?? []; - } - } - - const executionContext = this.getExecutionContext(); - - const events = [ - ...datasourceEvents, - ...visualizationEvents, - ...getExecutionContextEvents(executionContext), - ]; - - const adHocDataViews = Object.values(this.savedVis?.state.adHocDataViews || {}); - adHocDataViews.forEach(() => { - events.push('ad_hoc_data_view'); - }); - - trackUiCounterEvents(events, executionContext); - this.trackContentfulRender(); - - this.renderComplete.dispatchComplete(); - this.updateOutput({ - ...this.getOutput(), - rendered: true, - }); - - const inspectorAdapters = this.getInspectorAdapters(); - const timings = getSuccessfulRequestTimings(inspectorAdapters); - if (timings) { - const esRequestMetrics = { - eventName: 'lens_chart_es_request_totals', - duration: timings.requestTimeTotal, - key1: 'es_took_total', - value1: timings.esTookTotal, - }; - reportPerformanceMetricEvent(this.deps.coreStart.analytics, esRequestMetrics); - } - }; - - getExecutionContext() { - if (this.savedVis) { - const parentContext = this.parent?.getInput().executionContext || this.input.executionContext; - const child: KibanaExecutionContext = { - type: 'lens', - name: this.savedVis.visualizationType ?? '', - id: this.id, - description: this.savedVis.title || this.input.title || '', - url: this.output.editUrl, - }; - - return parentContext - ? { - ...parentContext, - child, - } - : child; - } - } - - /** - * - * @param {HTMLElement} domNode - * @param {ContainerState} containerState - */ - render(domNode: HTMLElement | Element) { - this.domNode = domNode; - if (!this.savedVis || !this.isInitialized || this.isDestroyed) { - return; - } - super.render(domNode as HTMLElement); - - if (this.input.onLoad) { - this.input.onLoad(true); - } - - this.domNode.setAttribute('data-shared-item', ''); - - const blockingErrors = this.getUserMessages(blockingMessageDisplayLocations, { - severity: 'error', - }); - - this.updateOutput({ - loading: true, - error: blockingErrors.length - ? new Error( - typeof blockingErrors[0].longMessage === 'string' - ? blockingErrors[0].longMessage - : blockingErrors[0].shortMessage - ) - : undefined, - }); - - if (blockingErrors.length) { - this.renderComplete.dispatchError(); - } else { - this.renderComplete.dispatchInProgress(); - } - - const input = this.getInput(); - - const getInternalTables = (states: Record<string, unknown>) => { - const result: Record<string, Datatable> = {}; - if ('textBased' in states) { - const layers = (states.textBased as TextBasedPersistedState).layers; - for (const layer in layers) { - if (layers[layer] && layers[layer].table) { - result[layer] = layers[layer].table!; - } - } - } - return result; - }; - - if (this.expression && !blockingErrors.length) { - render( - <> - <KibanaRenderContextProvider {...this.deps.coreStart}> - <ExpressionWrapper - ExpressionRenderer={this.expressionRenderer} - expression={this.expression || null} - lensInspector={this.lensInspector} - searchContext={this.getMergedSearchContext()} - variables={{ - embeddableTitle: this.getTitle(), - ...(input.palette ? { theme: { palette: input.palette } } : {}), - ...('overrides' in input ? { overrides: input.overrides } : {}), - ...getInternalTables(this.savedVis.state.datasourceStates), - }} - searchSessionId={this.getInput().searchSessionId} - handleEvent={this.handleEvent} - onData$={this.updateActiveData} - onRender$={this.onRender} - interactive={!input.disableTriggers} - renderMode={input.renderMode} - syncColors={input.syncColors} - syncTooltips={input.syncTooltips} - syncCursor={input.syncCursor} - hasCompatibleActions={this.hasCompatibleActions} - getCompatibleCellValueActions={this.getCompatibleCellValueActions} - className={input.className} - style={input.style} - executionContext={this.getExecutionContext()} - abortController={this.input.abortController} - addUserMessages={(messages) => this.addUserMessages(messages)} - onRuntimeError={(error) => { - this.updateOutput({ error }); - this.logError('runtime'); - }} - noPadding={this.visDisplayOptions.noPadding} - /> - </KibanaRenderContextProvider> - <MessagesBadge - onMount={(el) => { - this.badgeDomNode = el; - this.renderBadgeMessages(); - }} - /> - </>, - domNode - ); - } - - this.renderUserMessages(); - } - - private trackContentfulRender() { - if (!this.activeData || !canTrackContentfulRender(this.parent)) { - return; - } - - const hasData = Object.values(this.activeData).some((table) => { - if (table.meta?.statistics?.totalCount != null) { - // if totalCount is set, refer to total count - return table.meta.statistics.totalCount > 0; - } - // if not, fall back to check the rows of the table - return table.rows.length > 0; - }); - - if (hasData) { - this.parent.trackContentfulRender(); - } - } - - private renderUserMessages() { - const errors = this.getUserMessages(['visualization', 'visualizationOnEmbeddable'], { - severity: 'error', - }); - - if (errors.length && this.domNode) { - render( - <> - <KibanaRenderContextProvider {...this.deps.coreStart}> - <VisualizationErrorPanel - errors={errors} - canEdit={this.getIsEditable() && this.input.viewMode === 'edit'} - /> - </KibanaRenderContextProvider> - <MessagesBadge - onMount={(el) => { - this.badgeDomNode = el; - this.renderBadgeMessages(); - }} - /> - </>, - this.domNode - ); - } - - this.renderBadgeMessages(); - } - - badgeDomNode?: HTMLDivElement; - - /** - * This method is called on every render, and also whenever the badges dom node is created - * That happens after either the expression renderer or the visualization error panel is rendered. - * - * You should not call this method on its own. Use renderUserMessages instead. - */ - private renderBadgeMessages = () => { - const messages = this.getUserMessages('embeddableBadge'); - const [warningOrErrorMessages, infoMessages] = partition( - messages, - ({ severity }) => severity !== 'info' - ); - - if (this.badgeDomNode) { - render( - <KibanaRenderContextProvider {...this.deps.coreStart}> - <EmbeddableMessagesPopover messages={warningOrErrorMessages} /> - <EmbeddableFeatureBadge messages={infoMessages} /> - </KibanaRenderContextProvider>, - this.badgeDomNode - ); - } - }; - - private readonly hasCompatibleActions = async ( - event: ExpressionRendererEvent - ): Promise<boolean> => { - if ( - isLensTableRowContextMenuClickEvent(event) || - isLensMultiFilterEvent(event) || - isLensFilterEvent(event) - ) { - const { getTriggerCompatibleActions } = this.deps; - if (!getTriggerCompatibleActions) { - return false; - } - const actions = await getTriggerCompatibleActions(VIS_EVENT_TO_TRIGGER[event.name], { - data: event.data, - embeddable: this, - }); - - return actions.length > 0; - } - - return false; - }; - - private readonly getCompatibleCellValueActions: GetCompatibleCellValueActions = async (data) => { - const { getTriggerCompatibleActions } = this.deps; - if (getTriggerCompatibleActions) { - const embeddable = this; - const actions: Array<Action<CellValueContext>> = (await getTriggerCompatibleActions( - CELL_VALUE_TRIGGER, - { data, embeddable } - )) as Array<Action<CellValueContext>>; - return actions - .sort((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity)) - .map((action) => ({ - id: action.id, - type: action.type, - iconType: action.getIconType({ embeddable, data, trigger: cellValueTrigger })!, - displayName: action.getDisplayName({ embeddable, data, trigger: cellValueTrigger }), - execute: (cellData) => - action.execute({ embeddable, data: cellData, trigger: cellValueTrigger }), - })); - } - return []; - }; - - /** - * Combines the embeddable context with the saved object context, and replaces - * any references to index patterns - */ - private getMergedSearchContext(): ExecutionContextSearch { - if (!this.savedVis) { - throw new Error('savedVis is required for getMergedSearchContext'); - } - - const input = this.getInput(); - const context: ExecutionContextSearch = { - now: this.deps.data.nowProvider.get().getTime(), - timeRange: - input.timeslice !== undefined - ? { - from: new Date(input.timeslice[0]).toISOString(), - to: new Date(input.timeslice[1]).toISOString(), - mode: 'absolute' as 'absolute', - } - : input.timeRange, - query: [this.savedVis.state.query], - filters: this.deps.injectFilterReferences( - this.savedVis.state.filters, - this.savedVis.references - ), - disableWarningToasts: true, - }; - - if (input.query) { - context.query = [input.query, ...(context.query as Query[])]; - } - - if (input.filters?.length) { - context.filters = [ - ...input.filters.filter((filter) => !filter.meta.disabled), - ...(context.filters as Filter[]), - ]; - } - - return context; - } - - private get onEditAction(): Visualization['onEditAction'] { - const visType = this.savedVis?.visualizationType; - - if (!visType) { - return; - } - - return this.deps.visualizationMap[visType].onEditAction; - } - - handleEvent = async (event: ExpressionRendererEvent) => { - if (!this.deps.getTrigger || this.input.disableTriggers) { - return; - } - - let eventHandler: - | LensBaseEmbeddableInput['onBrushEnd'] - | LensBaseEmbeddableInput['onFilter'] - | LensBaseEmbeddableInput['onTableRowClick']; - let shouldExecuteDefaultTriggers = true; - - if (isLensBrushEvent(event)) { - eventHandler = this.input.onBrushEnd; - } else if (isLensFilterEvent(event) || isLensMultiFilterEvent(event)) { - eventHandler = this.input.onFilter; - } else if (isLensTableRowContextMenuClickEvent(event)) { - eventHandler = this.input.onTableRowClick; - } - // if the embeddable is located in an app where there is the Unified search bar with the ES|QL editor, then use this query - // otherwise use the query from the saved object - let esqlQuery: AggregateQuery | Query | undefined; - if (this.isTextBasedLanguage()) { - const query = this.deps.data.query.queryString.getQuery(); - esqlQuery = isOfAggregateQueryType(query) ? query : this.savedVis?.state.query; - } - - eventHandler?.({ - ...event.data, - preventDefault: () => { - shouldExecuteDefaultTriggers = false; - }, - }); - - if (isLensFilterEvent(event) || isLensMultiFilterEvent(event) || isLensBrushEvent(event)) { - if (shouldExecuteDefaultTriggers) { - this.deps.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec({ - data: { - ...event.data, - timeFieldName: - event.data.timeFieldName || inferTimeField(this.deps.data.datatableUtilities, event), - query: esqlQuery, - }, - embeddable: this, - }); - } - } - - if (isLensTableRowContextMenuClickEvent(event)) { - if (shouldExecuteDefaultTriggers) { - this.deps.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec( - { - data: event.data, - embeddable: this, - }, - true - ); - } - } - - // We allow for edit actions in the Embeddable for display purposes only (e.g. changing the datatable sort order). - // No state changes made here with an edit action are persisted. - if (isLensEditEvent(event) && this.onEditAction) { - if (!this.savedVis) return; - - // have to dance since this.savedVis.state is readonly - const newVis = JSON.parse(JSON.stringify(this.savedVis)) as Document; - newVis.state.visualization = this.onEditAction(newVis.state.visualization, event); - this.savedVis = newVis; - - const { ast } = await getExpressionFromDocument( - this.savedVis, - this.deps.documentToExpression - ); - - this.expression = ast; - - this.reload(); - } - }; - - reload() { - if (!this.savedVis || !this.isInitialized || this.isDestroyed) { - return; - } - - if (this.domNode) { - this.render(this.domNode); - } - } - - private async loadViewUnderlyingDataArgs(): Promise<void> { - if ( - !this.savedVis || - !this.activeData || - !this.activeDatasource || - !this.activeDatasourceState || - !this.activeVisualization || - !this.activeVisualizationState - ) { - this.canViewUnderlyingData$.next(false); - return; - } - - const mergedSearchContext = this.getMergedSearchContext(); - - if (!mergedSearchContext.timeRange) { - this.canViewUnderlyingData$.next(false); - return; - } - - const viewUnderlyingDataArgs = getViewUnderlyingDataArgs({ - activeDatasource: this.activeDatasource, - activeDatasourceState: this.activeDatasourceState, - activeVisualization: this.activeVisualization, - activeVisualizationState: this.activeVisualizationState, - activeData: this.activeData, - dataViews: this.internalDataViews, - capabilities: this.deps.capabilities, - query: mergedSearchContext.query, - filters: mergedSearchContext.filters || [], - timeRange: mergedSearchContext.timeRange, - esQueryConfig: getEsQueryConfig(this.deps.uiSettings), - indexPatternsCache: this.indexPatterns, - }); - - const loaded = typeof viewUnderlyingDataArgs !== 'undefined'; - if (loaded) { - this.viewUnderlyingDataArgs = viewUnderlyingDataArgs; - } - - this.canViewUnderlyingData$.next(loaded); - } - - /** - * Returns the necessary arguments to view the underlying data in discover. - * - * Only makes sense to call this after canViewUnderlyingData has been checked - */ - public getViewUnderlyingDataArgs() { - return this.viewUnderlyingDataArgs; - } - - public canViewUnderlyingData$ = new BehaviorSubject<boolean>(false); - - async initializeOutput() { - if (!this.savedVis) { - return; - } - - const { indexPatterns } = await getIndexPatternsObjects( - this.savedVis?.references.map(({ id }) => id) || [], - this.deps.dataViews - ); - ( - await Promise.all( - Object.values(this.savedVis?.state.adHocDataViews || {}).map((spec) => - this.deps.dataViews.create(spec) - ) - ) - ).forEach((dataView) => indexPatterns.push(dataView)); - - this.internalDataViews = uniqBy(indexPatterns, 'id'); - - // passing edit url and index patterns to the output of this embeddable for - // the container to pick them up and use them to configure filter bar and - // config dropdown correctly. - const input = this.getInput(); - - // if at least one indexPattern is time based, then the Lens embeddable requires the timeRange prop - // this is necessary for the dataview embeddable but not the ES|QL one - if ( - !Boolean(this.isTextBasedLanguage()) && - input.timeRange == null && - indexPatterns.some((indexPattern) => indexPattern.isTimeBased()) - ) { - this.addUserMessages([ - { - uniqueId: 'missing-time-range-on-embeddable', - severity: 'error', - fixableInEditor: false, - displayLocations: [{ id: 'visualization' }], - shortMessage: i18n.translate('xpack.lens.embeddable.missingTimeRangeParam.shortMessage', { - defaultMessage: `Missing timeRange property`, - }), - longMessage: i18n.translate('xpack.lens.embeddable.missingTimeRangeParam.longMessage', { - defaultMessage: `The timeRange property is required for the given configuration`, - }), - }, - ]); - } - - const blockingErrors = this.getUserMessages(blockingMessageDisplayLocations, { - severity: 'error', - }); - if (blockingErrors.length) { - this.logError('validation'); - } - - const title = input.hidePanelTitles ? '' : input.title ?? this.savedVis.title; - const description = input.hidePanelTitles ? '' : input.description ?? this.savedVis.description; - const savedObjectId = (input as LensByReferenceInput).savedObjectId; - this.updateOutput({ - defaultTitle: this.savedVis.title, - defaultDescription: this.savedVis.description, - /** lens visualizations allow inline editing action - * navigation to the editor is allowed through the flyout - */ - editable: this.getIsEditable(), - inlineEditable: true, - title, - description, - editPath: getEditPath(savedObjectId), - editUrl: this.deps.basePath.prepend(`/app/lens${getEditPath(savedObjectId)}`), - indexPatterns: this.internalDataViews, - }); - } - - public getIsEditable() { - // for ES|QL, editing is allowed only if the advanced setting is on - if (Boolean(this.isTextBasedLanguage()) && !this.deps.uiSettings.get(ENABLE_ESQL)) { - return false; - } - return ( - this.deps.capabilities.canSaveVisualizations || - (!this.inputIsRefType(this.getInput()) && - this.deps.capabilities.canSaveDashboards && - this.deps.capabilities.canOpenVisualizations) - ); - } - - public inputIsRefType = ( - input: LensByValueInput | LensByReferenceInput - ): input is LensByReferenceInput => { - return this.deps.attributeService.inputIsRefType(input); - }; - - public getInputAsRefType = async (): Promise<LensByReferenceInput> => { - return this.deps.attributeService.getInputAsRefType(this.getExplicitInput(), { - showSaveModal: true, - saveModalTitle: this.getTitle(), - }); - }; - - public getInputAsValueType = async (): Promise<LensByValueInput> => { - return this.deps.attributeService.getInputAsValueType(this.getExplicitInput()); - }; - - /** - * Gets the Lens embeddable's local filters - * @returns Local/panel-level array of filters for Lens embeddable - */ - public getFilters() { - try { - return mapAndFlattenFilters( - this.deps.injectFilterReferences( - this.savedVis?.state.filters ?? [], - this.savedVis?.references ?? [] - ) - ); - } catch (e) { - // if we can't parse the filters, we publish an empty array. - return []; - } - } - - /** - * Gets the Lens embeddable's local query - * @returns Local/panel-level query for Lens embeddable - */ - public getQuery() { - return this.savedVis?.state.query; - } - - public getSavedVis(): Readonly<LensSavedObjectAttributes | undefined> { - if (!this.savedVis) { - return; - } - - // Why are 'type' and 'savedObjectId' keys being removed? - // Prior to removing them, - // this method returned 'Readonly<Document | undefined>' while consumers typed the results as 'LensSavedObjectAttributes'. - // Removing 'type' and 'savedObjectId' keys to align method results with consumer typing. - const savedVis = { ...this.savedVis }; - delete savedVis.type; - delete savedVis.savedObjectId; - return savedVis; - } - - destroy() { - this.isDestroyed = true; - super.destroy(); - if (this.inputReloadSubscriptions.length > 0) { - this.inputReloadSubscriptions.forEach((reloadSub) => { - reloadSub.unsubscribe(); - }); - } - if (this.domNode) { - unmountComponentAtNode(this.domNode); - } - } - - public getSelfStyledOptions() { - return { - hideTitle: this.visDisplayOptions.noPanelTitle, - }; - } - - private get visDisplayOptions(): VisualizationDisplayOptions { - if (!this.savedVis?.visualizationType) { - return {}; - } - - let displayOptions = - this.deps.visualizationMap[this.savedVis.visualizationType]?.getDisplayOptions?.() ?? {}; - - if (this.input.noPadding !== undefined) { - displayOptions = { - ...displayOptions, - noPadding: this.input.noPadding, - }; - } - - return displayOptions; - } -} diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx b/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx deleted file mode 100644 index f433f71d453b..000000000000 --- a/x-pack/plugins/lens/public/embeddable/embeddable_component.tsx +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React, { FC, useEffect } from 'react'; -import type { CoreStart } from '@kbn/core/public'; -import type { Action, UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import type { Start as InspectorStartContract } from '@kbn/inspector-plugin/public'; -import { PanelLoader } from '@kbn/panel-loader'; -import { EuiLoadingChart } from '@elastic/eui'; -import { - EmbeddableFactory, - EmbeddableInput, - EmbeddableOutput, - EmbeddablePanel, - EmbeddableRoot, - EmbeddableStart, - IEmbeddable, - useEmbeddableFactory, -} from '@kbn/embeddable-plugin/public'; -import type { LensByReferenceInput, LensByValueInput } from './embeddable'; -import type { Document } from '../persistence'; -import type { FormBasedPersistedState } from '../datasources/form_based/types'; -import type { TextBasedPersistedState } from '../datasources/text_based/types'; -import type { XYState } from '../visualizations/xy/types'; -import type { - PieVisualizationState, - LegacyMetricState, - AllowedGaugeOverrides, - AllowedPartitionOverrides, - AllowedSettingsOverrides, - AllowedXYOverrides, -} from '../../common/types'; -import type { DatatableVisualizationState } from '../visualizations/datatable/visualization'; -import type { MetricVisualizationState } from '../visualizations/metric/types'; -import type { HeatmapVisualizationState } from '../visualizations/heatmap/types'; -import type { GaugeVisualizationState } from '../visualizations/gauge/constants'; - -type LensAttributes<TVisType, TVisState> = Omit< - Document, - 'savedObjectId' | 'type' | 'state' | 'visualizationType' -> & { - visualizationType: TVisType; - state: Omit<Document['state'], 'datasourceStates' | 'visualization'> & { - datasourceStates: { - formBased?: FormBasedPersistedState; - textBased?: TextBasedPersistedState; - }; - visualization: TVisState; - }; -}; - -/** - * Type-safe variant of by value embeddable input for Lens. - * This can be used to hardcode certain Lens chart configurations within another app. - */ -export type TypedLensByValueInput = Omit<LensByValueInput, 'attributes' | 'overrides'> & { - attributes: - | LensAttributes<'lnsXY', XYState> - | LensAttributes<'lnsPie', PieVisualizationState> - | LensAttributes<'lnsHeatmap', HeatmapVisualizationState> - | LensAttributes<'lnsGauge', GaugeVisualizationState> - | LensAttributes<'lnsDatatable', DatatableVisualizationState> - | LensAttributes<'lnsLegacyMetric', LegacyMetricState> - | LensAttributes<'lnsMetric', MetricVisualizationState> - | LensAttributes<string, unknown>; - - /** - * Overrides can tweak the style of the final embeddable and are executed at the end of the Lens rendering pipeline. - * XY charts offer an override of the Settings ('settings') and Axis ('axisX', 'axisLeft', 'axisRight') components. - * While it is not possible to pass function/callback/handlers to the renderer, it is possible to stop them by passing the - * "ignore" string as override value (i.e. onBrushEnd: "ignore") - */ - overrides?: - | AllowedSettingsOverrides - | AllowedXYOverrides - | AllowedPartitionOverrides - | AllowedGaugeOverrides; -}; - -export type EmbeddableComponentProps = (TypedLensByValueInput | LensByReferenceInput) & { - withDefaultActions?: boolean; - extraActions?: Action[]; - showInspector?: boolean; - abortController?: AbortController; -}; - -export type EmbeddableComponent = React.ComponentType<EmbeddableComponentProps>; - -interface PluginsStartDependencies { - uiActions: UiActionsStart; - embeddable: EmbeddableStart; - inspector: InspectorStartContract; -} - -export function getEmbeddableComponent(core: CoreStart, plugins: PluginsStartDependencies) { - const { embeddable: embeddableStart, uiActions } = plugins; - const factory = embeddableStart.getEmbeddableFactory('lens')!; - return (props: EmbeddableComponentProps) => { - const input = { ...props }; - const hasActions = - Boolean(input.withDefaultActions) || (input.extraActions && input.extraActions?.length > 0); - - if (hasActions) { - return ( - <EmbeddablePanelWrapper - factory={factory} - uiActions={uiActions} - actionPredicate={() => hasActions} - input={input} - extraActions={input.extraActions} - showInspector={input.showInspector} - withDefaultActions={input.withDefaultActions} - /> - ); - } - return <EmbeddableRootWrapper factory={factory} input={input} />; - }; -} - -function EmbeddableRootWrapper({ - factory, - input, -}: { - factory: EmbeddableFactory<EmbeddableInput, EmbeddableOutput>; - input: EmbeddableComponentProps; -}) { - const [embeddable, loading, error] = useEmbeddableFactory({ factory, input }); - if (loading) { - return <EuiLoadingChart />; - } - return <EmbeddableRoot embeddable={embeddable} loading={loading} error={error} input={input} />; -} - -interface EmbeddablePanelWrapperProps { - factory: EmbeddableFactory<EmbeddableInput, EmbeddableOutput>; - uiActions: PluginsStartDependencies['uiActions']; - actionPredicate: (id: string) => boolean; - input: EmbeddableComponentProps; - extraActions?: Action[]; - showInspector?: boolean; - withDefaultActions?: boolean; - abortController?: AbortController; -} - -const EmbeddablePanelWrapper: FC<EmbeddablePanelWrapperProps> = ({ - factory, - uiActions, - actionPredicate, - input, - extraActions, - showInspector = true, - withDefaultActions, - abortController, -}) => { - const [embeddable, loading] = useEmbeddableFactory({ factory, input }); - useEffect(() => { - if (embeddable) { - embeddable.updateInput(input); - } - }, [embeddable, input]); - - if (loading || !embeddable) { - return <PanelLoader />; - } - - return ( - <EmbeddablePanel - hideHeader={false} - embeddable={embeddable as IEmbeddable<EmbeddableInput, EmbeddableOutput>} - getActions={async (triggerId, context) => { - const actions = withDefaultActions - ? await uiActions.getTriggerCompatibleActions(triggerId, context) - : []; - - return [...(extraActions ?? []), ...actions]; - }} - hideInspector={!showInspector} - actionPredicate={actionPredicate} - showNotifications={false} - showShadow={false} - showBadges={false} - /> - ); -}; diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts b/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts deleted file mode 100644 index d84aca319a42..000000000000 --- a/x-pack/plugins/lens/public/embeddable/embeddable_factory.ts +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { - Capabilities, - CoreStart, - HttpSetup, - IUiSettingsClient, - ThemeServiceStart, -} from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import { RecursiveReadonly } from '@kbn/utility-types'; -import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; -import { DataPublicPluginStart, FilterManager, TimefilterContract } from '@kbn/data-plugin/public'; -import type { DataViewsContract } from '@kbn/data-views-plugin/public'; -import { ReactExpressionRendererType } from '@kbn/expressions-plugin/public'; -import { - EmbeddableFactoryDefinition, - IContainer, - ErrorEmbeddable, -} from '@kbn/embeddable-plugin/public'; -import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; -import type { Start as InspectorStart } from '@kbn/inspector-plugin/public'; -import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; -import type { LensByReferenceInput, LensEmbeddableInput } from './embeddable'; -import type { Document } from '../persistence/saved_object_store'; -import type { LensAttributeService } from '../lens_attribute_service'; -import { DOC_TYPE } from '../../common/constants'; -import { extract, inject } from '../../common/embeddable_factory'; -import type { DatasourceMap, VisualizationMap } from '../types'; -import type { DocumentToExpressionReturnType } from '../editor_frame_service/editor_frame'; - -export interface LensEmbeddableStartServices { - data: DataPublicPluginStart; - timefilter: TimefilterContract; - coreHttp: HttpSetup; - coreStart: CoreStart; - inspector: InspectorStart; - attributeService: LensAttributeService; - capabilities: RecursiveReadonly<Capabilities>; - expressionRenderer: ReactExpressionRendererType; - dataViews: DataViewsContract; - uiActions?: UiActionsStart; - usageCollection?: UsageCollectionSetup; - documentToExpression: (doc: Document) => Promise<DocumentToExpressionReturnType>; - injectFilterReferences: FilterManager['inject']; - visualizationMap: VisualizationMap; - datasourceMap: DatasourceMap; - spaces?: SpacesPluginStart; - theme: ThemeServiceStart; - uiSettings: IUiSettingsClient; -} - -export class EmbeddableFactory implements EmbeddableFactoryDefinition { - type = DOC_TYPE; - savedObjectMetaData = { - name: i18n.translate('xpack.lens.lensSavedObjectLabel', { - defaultMessage: 'Lens Visualization', - }), - type: DOC_TYPE, - getIconForSavedObject: () => 'lensApp', - }; - - constructor(private getStartServices: () => Promise<LensEmbeddableStartServices>) {} - - public isEditable = async () => { - const { capabilities } = await this.getStartServices(); - return Boolean(capabilities.visualize.save || capabilities.dashboard?.showWriteControls); - }; - - canCreateNew() { - return false; - } - - getDisplayName() { - return i18n.translate('xpack.lens.embeddableDisplayName', { - defaultMessage: 'Lens', - }); - } - - createFromSavedObject = async ( - savedObjectId: string, - input: LensEmbeddableInput, - parent?: IContainer - ) => { - if (!(input as LensByReferenceInput).savedObjectId) { - (input as LensByReferenceInput).savedObjectId = savedObjectId; - } - return this.create(input, parent); - }; - - async create(input: LensEmbeddableInput, parent?: IContainer) { - try { - const { - data, - timefilter, - expressionRenderer, - documentToExpression, - injectFilterReferences, - visualizationMap, - datasourceMap, - uiActions, - coreHttp, - coreStart, - attributeService, - dataViews, - capabilities, - usageCollection, - inspector, - spaces, - uiSettings, - } = await this.getStartServices(); - - const { Embeddable } = await import('../async_services'); - - return new Embeddable( - { - attributeService, - data, - dataViews, - timefilter, - inspector, - expressionRenderer, - basePath: coreHttp.basePath, - getTrigger: uiActions?.getTrigger, - getTriggerCompatibleActions: uiActions?.getTriggerCompatibleActions, - documentToExpression, - injectFilterReferences, - visualizationMap, - datasourceMap, - capabilities: { - canSaveDashboards: Boolean(capabilities.dashboard?.showWriteControls), - canSaveVisualizations: Boolean(capabilities.visualize.save), - canOpenVisualizations: Boolean(capabilities.visualize.show), - navLinks: capabilities.navLinks, - discover: capabilities.discover, - }, - coreStart, - usageCollection, - spaces, - uiSettings, - }, - input, - parent - ); - } catch (e) { - return new ErrorEmbeddable(e, input, parent); - } - } - - extract = extract; - inject = inject; -} diff --git a/x-pack/plugins/lens/public/embeddable/interfaces/lens_api.ts b/x-pack/plugins/lens/public/embeddable/interfaces/lens_api.ts deleted file mode 100644 index 11b70cd6e776..000000000000 --- a/x-pack/plugins/lens/public/embeddable/interfaces/lens_api.ts +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { - HasParentApi, - HasType, - PublishesUnifiedSearch, - PublishesPanelTitle, - PublishingSubject, -} from '@kbn/presentation-publishing'; -import { - apiIsOfType, - apiPublishesUnifiedSearch, - apiPublishesPanelTitle, -} from '@kbn/presentation-publishing'; -import { LensSavedObjectAttributes, ViewUnderlyingDataArgs } from '../embeddable'; - -export type HasLensConfig = HasType<'lens'> & { - getSavedVis: () => Readonly<LensSavedObjectAttributes | undefined>; - canViewUnderlyingData$: PublishingSubject<boolean>; - getViewUnderlyingDataArgs: () => ViewUnderlyingDataArgs; - getFullAttributes: () => LensSavedObjectAttributes | undefined; -}; - -export type LensApi = HasLensConfig & - PublishesPanelTitle & - PublishesUnifiedSearch & - Partial<HasParentApi<Partial<PublishesUnifiedSearch>>>; - -export const isLensApi = (api: unknown): api is LensApi => { - return Boolean( - api && - apiIsOfType(api, 'lens') && - typeof (api as HasLensConfig).getSavedVis === 'function' && - (api as HasLensConfig).canViewUnderlyingData$ && - typeof (api as HasLensConfig).getViewUnderlyingDataArgs === 'function' && - typeof (api as HasLensConfig).getFullAttributes === 'function' && - apiPublishesPanelTitle(api) && - apiPublishesUnifiedSearch(api) - ); -}; diff --git a/x-pack/plugins/lens/public/index.ts b/x-pack/plugins/lens/public/index.ts index 026da7988a30..aea728024b57 100644 --- a/x-pack/plugins/lens/public/index.ts +++ b/x-pack/plugins/lens/public/index.ts @@ -7,12 +7,21 @@ import { LensPlugin } from './plugin'; -export { isLensApi } from './embeddable/interfaces/lens_api'; +export { isLensApi } from './react_embeddable/type_guards'; +export { type EmbeddableComponent } from './react_embeddable/renderer/lens_custom_renderer_component'; export type { - EmbeddableComponentProps, - EmbeddableComponent, + LensApi, + LensSerializedState, + LensRuntimeState, + LensByValueInput, + LensByReferenceInput, TypedLensByValueInput, -} from './embeddable/embeddable_component'; + LensEmbeddableInput, + LensEmbeddableOutput, + LensSavedObjectAttributes, + LensRendererProps as EmbeddableComponentProps, +} from './react_embeddable/types'; + export type { XYState, XYReferenceLineLayerConfig, @@ -110,14 +119,6 @@ export type { export type { InlineEditLensEmbeddableContext } from './trigger_actions/open_lens_config/in_app_embeddable_edit/types'; -export type { - LensApi, - LensEmbeddableInput, - LensSavedObjectAttributes, - Embeddable, - LensEmbeddableOutput, -} from './embeddable'; - export type { ChartInfo } from './chart_info_api'; export { layerTypes } from '../common/layer_types'; diff --git a/x-pack/plugins/lens/public/lens_attribute_service.ts b/x-pack/plugins/lens/public/lens_attribute_service.ts index eb827d87d641..b5eeaae5d0f5 100644 --- a/x-pack/plugins/lens/public/lens_attribute_service.ts +++ b/x-pack/plugins/lens/public/lens_attribute_service.ts @@ -6,27 +6,52 @@ */ import type { CoreStart } from '@kbn/core/public'; -import type { AttributeService } from '@kbn/embeddable-plugin/public'; +import type { SavedObjectReference } from '@kbn/core/types'; import { OnSaveProps } from '@kbn/saved-objects-plugin/public'; import { SavedObjectCommon } from '@kbn/saved-objects-finder-plugin/common'; +import { noop } from 'lodash'; +import { EmbeddableStateWithType } from '@kbn/embeddable-plugin/common'; import type { LensPluginStartDependencies } from './plugin'; -import type { LensSavedObjectAttributes as LensSavedObjectAttributesWithoutReferences } from '../common/content_management'; import type { - LensSavedObjectAttributes, - LensByValueInput, - LensUnwrapMetaInfo, - LensUnwrapResult, - LensByReferenceInput, -} from './embeddable/embeddable'; + LensSavedObject, + LensSavedObjectAttributes as LensSavedObjectAttributesWithoutReferences, +} from '../common/content_management'; +import { extract, inject } from '../common/embeddable_factory'; import { SavedObjectIndexStore, checkForDuplicateTitle } from './persistence'; import { DOC_TYPE } from '../common/constants'; +import { SharingSavedObjectProps } from './types'; +import { LensRuntimeState, LensSavedObjectAttributes } from './react_embeddable/types'; -export type LensAttributeService = AttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput, - LensUnwrapMetaInfo ->; +type Reference = LensSavedObject['references'][number]; + +type CheckDuplicateTitleProps = OnSaveProps & { + id?: string; + displayName: string; + lastSavedTitle: string; + copyOnSave: boolean; +}; + +export interface LensAttributesService { + loadFromLibrary: (savedObjectId: string) => Promise<{ + attributes: LensSavedObjectAttributes; + sharingSavedObjectProps: SharingSavedObjectProps; + managed: boolean; + }>; + saveToLibrary: ( + attributes: LensSavedObjectAttributesWithoutReferences, + references: Reference[], + savedObjectId?: string + ) => Promise<string>; + checkForDuplicateTitle: (props: CheckDuplicateTitleProps) => Promise<{ isDuplicate: boolean }>; + injectReferences: ( + runtimeState: LensRuntimeState, + references: SavedObjectReference[] | undefined + ) => LensRuntimeState; + extractReferences: (runtimeState: LensRuntimeState) => { + rawState: LensRuntimeState; + references: SavedObjectReference[]; + }; +} export const savedObjectToEmbeddableAttributes = ( savedObject: SavedObjectCommon<LensSavedObjectAttributesWithoutReferences> @@ -41,60 +66,86 @@ export const savedObjectToEmbeddableAttributes = ( export function getLensAttributeService( core: CoreStart, startDependencies: LensPluginStartDependencies -): LensAttributeService { +): LensAttributesService { const savedObjectStore = new SavedObjectIndexStore(startDependencies.contentManagement); - return startDependencies.embeddable.getAttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput, - LensUnwrapMetaInfo - >(DOC_TYPE, { - saveMethod: async (attributes: LensSavedObjectAttributes, savedObjectId?: string) => { - const savedDoc = await savedObjectStore.save({ + return { + loadFromLibrary: async ( + savedObjectId: string + ): Promise<{ + attributes: LensSavedObjectAttributes; + sharingSavedObjectProps: SharingSavedObjectProps; + managed: boolean; + }> => { + const { meta, item } = await savedObjectStore.load(savedObjectId); + return { + attributes: { + ...item.attributes, + state: item.attributes.state as LensSavedObjectAttributes['state'], + references: item.references, + }, + sharingSavedObjectProps: { + aliasTargetId: meta.aliasTargetId, + outcome: meta.outcome, + aliasPurpose: meta.aliasPurpose, + sourceId: item.id, + }, + managed: Boolean(item.managed), + }; + }, + saveToLibrary: async ( + attributes: LensSavedObjectAttributesWithoutReferences, + references: Reference[], + savedObjectId?: string + ) => { + const result = await savedObjectStore.save({ ...attributes, + state: attributes.state as LensSavedObjectAttributes['state'], + references, savedObjectId, - type: DOC_TYPE, }); - return { id: savedDoc.savedObjectId }; + return result.savedObjectId; }, - unwrapMethod: async (savedObjectId: string): Promise<LensUnwrapResult> => { - const { - item: savedObject, - meta: { outcome, aliasTargetId, aliasPurpose }, - } = await savedObjectStore.load(savedObjectId); - const { id } = savedObject; - - const sharingSavedObjectProps = { - aliasTargetId, - outcome, - aliasPurpose, - sourceId: id, - }; - + checkForDuplicateTitle: async ({ + newTitle, + isTitleDuplicateConfirmed, + onTitleDuplicate = noop, + displayName = DOC_TYPE, + lastSavedTitle = '', + copyOnSave = false, + id, + }: CheckDuplicateTitleProps) => { return { - attributes: savedObjectToEmbeddableAttributes(savedObject), - metaInfo: { - sharingSavedObjectProps, - managed: savedObject.managed, - }, + isDuplicate: await checkForDuplicateTitle( + { + id, + title: newTitle, + isTitleDuplicateConfirmed, + displayName, + lastSavedTitle, + copyOnSave, + }, + onTitleDuplicate, + { + client: savedObjectStore, + ...core, + } + ), }; }, - checkForDuplicateTitle: (props: OnSaveProps) => { - return checkForDuplicateTitle( - { - title: props.newTitle, - displayName: DOC_TYPE, - isTitleDuplicateConfirmed: props.isTitleDuplicateConfirmed, - lastSavedTitle: '', - copyOnSave: false, - }, - props.onTitleDuplicate, - { - client: savedObjectStore, - ...core, - } - ); + // Make sure to inject references from the container down to the runtime state + // this ensure migrations/copy to spaces works correctly + injectReferences: (runtimeState, references) => { + return inject( + runtimeState as unknown as EmbeddableStateWithType, + references ?? runtimeState.attributes.references + ) as unknown as LensRuntimeState; }, - }); + // Make sure to move the internal references into the parent references + // so migrations/move to spaces can work properly + extractReferences: (runtimeState) => { + const { state, references } = extract(runtimeState as unknown as EmbeddableStateWithType); + return { rawState: state as unknown as LensRuntimeState, references }; + }, + }; } diff --git a/x-pack/plugins/lens/public/lens_inspector_service.ts b/x-pack/plugins/lens/public/lens_inspector_service.ts index 4de0a8ec1340..052a741851ba 100644 --- a/x-pack/plugins/lens/public/lens_inspector_service.ts +++ b/x-pack/plugins/lens/public/lens_inspector_service.ts @@ -18,7 +18,7 @@ export const getLensInspectorService = (inspector: InspectorStartContract) => { const adapters: Adapters = createDefaultInspectorAdapters(); let overlayRef: InspectorSession | undefined; return { - adapters, + getInspectorAdapters: () => adapters, inspect: (options?: InspectorOptions) => { overlayRef = inspector.open(adapters, options); overlayRef.onClose.then(() => { @@ -28,7 +28,7 @@ export const getLensInspectorService = (inspector: InspectorStartContract) => { }); return overlayRef; }, - close: () => overlayRef?.close(), + closeInspector: async () => overlayRef?.close(), }; }; diff --git a/x-pack/plugins/lens/public/lens_suggestions_api/helpers.test.ts b/x-pack/plugins/lens/public/lens_suggestions_api/helpers.test.ts index 177a7e2e0d33..fa53ec84293c 100644 --- a/x-pack/plugins/lens/public/lens_suggestions_api/helpers.test.ts +++ b/x-pack/plugins/lens/public/lens_suggestions_api/helpers.test.ts @@ -7,7 +7,7 @@ import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { mergeSuggestionWithVisContext } from './helpers'; import { mockAllSuggestions } from '../mocks'; -import type { TypedLensByValueInput } from '../embeddable/embeddable_component'; +import { TypedLensByValueInput } from '../react_embeddable/types'; const context = { dataViewSpec: { diff --git a/x-pack/plugins/lens/public/lens_suggestions_api/helpers.ts b/x-pack/plugins/lens/public/lens_suggestions_api/helpers.ts index 394d32e8c5bb..5e000d1f14c8 100644 --- a/x-pack/plugins/lens/public/lens_suggestions_api/helpers.ts +++ b/x-pack/plugins/lens/public/lens_suggestions_api/helpers.ts @@ -7,7 +7,7 @@ import type { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; import { getDatasourceId } from '@kbn/visualization-utils'; import type { VisualizeEditorContext, Suggestion } from '../types'; -import type { TypedLensByValueInput } from '../embeddable/embeddable_component'; +import { TypedLensByValueInput } from '../react_embeddable/types'; /** * Returns the suggestion updated with external visualization state for ES|QL charts diff --git a/x-pack/plugins/lens/public/lens_suggestions_api/index.ts b/x-pack/plugins/lens/public/lens_suggestions_api/index.ts index c73379d9a42c..6f3f558b60b1 100644 --- a/x-pack/plugins/lens/public/lens_suggestions_api/index.ts +++ b/x-pack/plugins/lens/public/lens_suggestions_api/index.ts @@ -10,7 +10,7 @@ import type { ChartType } from '@kbn/visualization-utils'; import { getSuggestions } from '../editor_frame_service/editor_frame/suggestion_helpers'; import type { DatasourceMap, VisualizationMap, VisualizeEditorContext } from '../types'; import type { DataViewsState } from '../state_management'; -import type { TypedLensByValueInput } from '../embeddable/embeddable_component'; +import type { TypedLensByValueInput } from '../react_embeddable/types'; import { mergeSuggestionWithVisContext } from './helpers'; interface SuggestionsApiProps { diff --git a/x-pack/plugins/lens/public/lens_suggestions_api/lens_suggestions_api.test.ts b/x-pack/plugins/lens/public/lens_suggestions_api/lens_suggestions_api.test.ts index e5e60284e491..784c0ae03e56 100644 --- a/x-pack/plugins/lens/public/lens_suggestions_api/lens_suggestions_api.test.ts +++ b/x-pack/plugins/lens/public/lens_suggestions_api/lens_suggestions_api.test.ts @@ -10,7 +10,7 @@ import { ChartType } from '@kbn/visualization-utils'; import { createMockVisualization, DatasourceMock, createMockDatasource } from '../mocks'; import { DatasourceSuggestion } from '../types'; import { suggestionsApi } from '.'; -import type { TypedLensByValueInput } from '../embeddable/embeddable_component'; +import { TypedLensByValueInput } from '../react_embeddable/types'; const generateSuggestion = (state = {}, layerId: string = 'first'): DatasourceSuggestion => ({ state, diff --git a/x-pack/plugins/lens/public/mocks/data_plugin_mock.ts b/x-pack/plugins/lens/public/mocks/data_plugin_mock.ts index db7ab00de22e..8628cc29c194 100644 --- a/x-pack/plugins/lens/public/mocks/data_plugin_mock.ts +++ b/x-pack/plugins/lens/public/mocks/data_plugin_mock.ts @@ -48,13 +48,13 @@ export function mockDataPlugin( function createMockSearchService() { let sessionIdCounter = initialSessionId ? 1 : 0; let currentSessionId: string | undefined = initialSessionId; - const start = () => { - currentSessionId = `sessionId-${++sessionIdCounter}`; - return currentSessionId; - }; + return { session: { - start: jest.fn(start), + start: jest.fn(() => { + currentSessionId = `sessionId-${++sessionIdCounter}`; + return currentSessionId; + }), clear: jest.fn(), getSessionId: jest.fn(() => currentSessionId), getSession$: jest.fn(() => sessionIdSubject.asObservable()), @@ -146,5 +146,6 @@ export function mockDataPlugin( fieldFormats: { deserialize: jest.fn(), }, + datatableUtilities: { getDateHistogramMeta: jest.fn(() => true) }, } as unknown as DataPublicPluginStart; } diff --git a/x-pack/plugins/lens/public/mocks/lens_plugin_mock.tsx b/x-pack/plugins/lens/public/mocks/lens_plugin_mock.tsx index 4e5f83c7db83..cbb2f0c5dddb 100644 --- a/x-pack/plugins/lens/public/mocks/lens_plugin_mock.tsx +++ b/x-pack/plugins/lens/public/mocks/lens_plugin_mock.tsx @@ -16,7 +16,7 @@ type Start = jest.Mocked<LensPublicStart>; export const lensPluginMock = { createStartContract: (): Start => { const startContract: Start = { - EmbeddableComponent: jest.fn(() => { + EmbeddableComponent: jest.fn((props) => { return <span>Lens Embeddable Component</span>; }), SaveModalComponent: jest.fn(() => { diff --git a/x-pack/plugins/lens/public/mocks/services_mock.tsx b/x-pack/plugins/lens/public/mocks/services_mock.tsx index 18fa29fd6caf..b5366984c435 100644 --- a/x-pack/plugins/lens/public/mocks/services_mock.tsx +++ b/x-pack/plugins/lens/public/mocks/services_mock.tsx @@ -5,7 +5,6 @@ * 2.0. */ -import React from 'react'; import { Subject } from 'rxjs'; import { coreMock } from '@kbn/core/public/mocks'; import { navigationPluginMock } from '@kbn/navigation-plugin/public/mocks'; @@ -20,46 +19,35 @@ import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; import { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; import { unifiedSearchPluginMock } from '@kbn/unified-search-plugin/public/mocks'; -import { - mockAttributeService, - createEmbeddableStateTransferMock, -} from '@kbn/embeddable-plugin/public/mocks'; +import { createEmbeddableStateTransferMock } from '@kbn/embeddable-plugin/public/mocks'; import { fieldFormatsServiceMock } from '@kbn/field-formats-plugin/public/mocks'; import type { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; import { presentationUtilPluginMock } from '@kbn/presentation-util-plugin/public/mocks'; import { uiActionsPluginMock } from '@kbn/ui-actions-plugin/public/mocks'; import type { EventAnnotationServiceType } from '@kbn/event-annotation-plugin/public'; -import type { LensAttributeService } from '../lens_attribute_service'; -import type { - LensByValueInput, - LensByReferenceInput, - LensSavedObjectAttributes, - LensUnwrapMetaInfo, -} from '../embeddable/embeddable'; -import { DOC_TYPE } from '../../common/constants'; + import { LensAppServices } from '../app_plugin/types'; import { mockDataPlugin } from './data_plugin_mock'; import { getLensInspectorService } from '../lens_inspector_service'; -import { SavedObjectIndexStore } from '../persistence'; +import { LensDocument, SavedObjectIndexStore } from '../persistence'; +import { LensAttributesService } from '../lens_attribute_service'; +import { mockDatasourceStates } from './store_mocks'; const startMock = coreMock.createStart(); -export const defaultDoc = { +export const defaultDoc: LensDocument = { savedObjectId: '1234', title: 'An extremely cool default document!', - expression: 'definitely a valid expression', visualizationType: 'testVis', state: { - query: 'kuery', + query: { query: 'test', language: 'kuery' }, filters: [{ query: { match_phrase: { src: 'test' } }, meta: { index: 'index-pattern-0' } }], - datasourceStates: { - testDatasource: 'datasource', - }, + datasourceStates: mockDatasourceStates(), visualization: {}, }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], -} as unknown as Document; +}; export const exactMatchDoc = { attributes: { @@ -70,6 +58,27 @@ export const exactMatchDoc = { }, }; +export function makeAttributeService(doc: LensDocument): jest.Mocked<LensAttributesService> { + const attributeServiceMock: jest.Mocked<LensAttributesService> = { + loadFromLibrary: jest.fn().mockResolvedValue(exactMatchDoc), + saveToLibrary: jest.fn().mockResolvedValue(doc.savedObjectId), + checkForDuplicateTitle: jest.fn(), + injectReferences: jest.fn((_runtimeState, references) => ({ + ..._runtimeState, + attributes: { + ..._runtimeState.attributes, + references: references?.length ? references : _runtimeState.attributes.references, + }, + })), + extractReferences: jest.fn((_runtimeState) => ({ + rawState: _runtimeState, + references: _runtimeState.attributes.references || [], + })), + }; + + return attributeServiceMock; +} + export function makeDefaultServices( sessionIdSubject = new Subject<string>(), sessionId: string | undefined = undefined, @@ -106,44 +115,16 @@ export function makeDefaultServices( const navigationStartMock = navigationPluginMock.createStartContract(); - jest - .spyOn(navigationStartMock.ui.AggregateQueryTopNavMenu.prototype, 'constructor') - .mockImplementation(() => { - return <div className="topNavMenu" />; - }); - - function makeAttributeService(): LensAttributeService { - const attributeServiceMock = mockAttributeService< - LensSavedObjectAttributes, - LensByValueInput, - LensByReferenceInput, - LensUnwrapMetaInfo - >( - DOC_TYPE, - { - saveMethod: jest.fn(), - unwrapMethod: jest.fn(), - checkForDuplicateTitle: jest.fn(), - }, - core - ); - attributeServiceMock.unwrapAttributes = jest.fn().mockResolvedValue(exactMatchDoc); - attributeServiceMock.wrapAttributes = jest.fn().mockResolvedValue({ - savedObjectId: (doc as unknown as LensByReferenceInput).savedObjectId, - }); - - return attributeServiceMock; - } - return { ...startMock, chrome: core.chrome, navigation: navigationStartMock, - attributeService: makeAttributeService(), + attributeService: makeAttributeService(doc), inspector: { - adapters: getLensInspectorService(inspectorPluginMock.createStartContract()).adapters, + getInspectorAdapters: getLensInspectorService(inspectorPluginMock.createStartContract()) + .getInspectorAdapters, inspect: jest.fn(), - close: jest.fn(), + closeInspector: jest.fn(), }, presentationUtil: presentationUtilPluginMock.createStartContract(), savedObjectStore: { @@ -158,6 +139,9 @@ export function makeDefaultServices( capabilities: { ...core.application.capabilities, visualize: { save: true, saveQuery: true, show: true, createShortUrl: true }, + dashboard: { + showWriteControls: true, + }, }, getUrlForApp: jest.fn((appId: string) => `/testbasepath/app/${appId}#/`), }, diff --git a/x-pack/plugins/lens/public/mocks/store_mocks.tsx b/x-pack/plugins/lens/public/mocks/store_mocks.tsx index f465eadc9dfd..87667c21fed2 100644 --- a/x-pack/plugins/lens/public/mocks/store_mocks.tsx +++ b/x-pack/plugins/lens/public/mocks/store_mocks.tsx @@ -8,7 +8,6 @@ import React, { PropsWithChildren, ReactElement } from 'react'; import { ReactWrapper, mount } from 'enzyme'; import { Provider } from 'react-redux'; -import { act } from 'react-dom/test-utils'; import { PreloadedState } from '@reduxjs/toolkit'; import { RenderOptions, render } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n-react'; @@ -20,17 +19,25 @@ import { mockVisualizationMap } from './visualization_mock'; import { mockDatasourceMap } from './datasource_mock'; import { makeDefaultServices } from './services_mock'; -export const mockStoreDeps = (deps?: { - lensServices?: LensAppServices; - datasourceMap?: DatasourceMap; - visualizationMap?: VisualizationMap; -}) => { - return { - datasourceMap: deps?.datasourceMap || mockDatasourceMap(), - visualizationMap: deps?.visualizationMap || mockVisualizationMap(), - lensServices: deps?.lensServices || makeDefaultServices(), - }; -}; +export const mockStoreDeps = ( + { + lensServices = makeDefaultServices(), + datasourceMap = mockDatasourceMap(), + visualizationMap = mockVisualizationMap(), + }: { + lensServices?: LensAppServices; + datasourceMap?: DatasourceMap; + visualizationMap?: VisualizationMap; + } = { + lensServices: makeDefaultServices(), + datasourceMap: mockDatasourceMap(), + visualizationMap: mockVisualizationMap(), + } +) => ({ + datasourceMap, + visualizationMap, + lensServices, +}); export function mockDatasourceStates() { return { @@ -138,12 +145,7 @@ export const mountWithProvider = async ( } ) => { const { mountArgs, lensStore, deps } = getMountWithProviderParams(component, store, options); - - let instance: ReactWrapper = {} as ReactWrapper; - - await act(async () => { - instance = mount(mountArgs.component, mountArgs.options); - }); + const instance = mount(mountArgs.component, mountArgs.options); return { instance, lensStore, deps }; }; diff --git a/x-pack/plugins/lens/public/persistence/saved_object_store.ts b/x-pack/plugins/lens/public/persistence/saved_object_store.ts index d15386548dac..9edd481f7b62 100644 --- a/x-pack/plugins/lens/public/persistence/saved_object_store.ts +++ b/x-pack/plugins/lens/public/persistence/saved_object_store.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { Filter, Query } from '@kbn/es-query'; -import { SavedObjectReference } from '@kbn/core/public'; +import type { AggregateQuery, Filter, Query } from '@kbn/es-query'; +import type { SavedObjectReference } from '@kbn/core/public'; import type { DataViewSpec } from '@kbn/data-views-plugin/public'; import type { ContentManagementPublicStart } from '@kbn/content-management-plugin/public'; import type { SearchQuery } from '@kbn/content-management-plugin/common'; @@ -14,7 +14,7 @@ import type { VisualizationClient } from '@kbn/visualizations-plugin/public'; import type { LensSavedObjectAttributes, LensSearchQuery } from '../../common/content_management'; import { getLensClient } from './lens_client'; -export interface Document { +export interface LensDocument { savedObjectId?: string; type?: string; visualizationType: string | null; @@ -23,7 +23,7 @@ export interface Document { state: { datasourceStates: Record<string, unknown>; visualization: unknown; - query: Query; + query: Query | AggregateQuery; globalPalette?: { activePaletteId: string; state?: unknown; @@ -36,7 +36,7 @@ export interface Document { } export interface DocumentSaver { - save: (vis: Document) => Promise<{ savedObjectId: string }>; + save: (vis: LensDocument) => Promise<{ savedObjectId: string }>; } export interface DocumentLoader { @@ -52,9 +52,8 @@ export class SavedObjectIndexStore implements SavedObjectStore { this.client = getLensClient(cm); } - save = async (vis: Document) => { - const { savedObjectId, type, references, ...rest } = vis; - const attributes = rest; + save = async (vis: LensDocument) => { + const { savedObjectId, type, references, ...attributes } = vis; if (savedObjectId) { const result = await this.client.update({ @@ -65,15 +64,14 @@ export class SavedObjectIndexStore implements SavedObjectStore { }, }); return { ...vis, savedObjectId: result.item.id }; - } else { - const result = await this.client.create({ - data: attributes, - options: { - references, - }, - }); - return { ...vis, savedObjectId: result.item.id }; } + const result = await this.client.create({ + data: attributes, + options: { + references, + }, + }); + return { ...vis, savedObjectId: result.item.id }; }; async load(savedObjectId: string) { diff --git a/x-pack/plugins/lens/public/plugin.ts b/x-pack/plugins/lens/public/plugin.ts index 3145606abaf6..38f831ce3415 100644 --- a/x-pack/plugins/lens/public/plugin.ts +++ b/x-pack/plugins/lens/public/plugin.ts @@ -14,8 +14,9 @@ import type { } from '@kbn/usage-collection-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; -import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { CONTEXT_MENU_TRIGGER } from '@kbn/embeddable-plugin/public'; +import type { EmbeddableEnhancedPluginStart } from '@kbn/embeddable-enhanced-plugin/public'; import type { DataViewsPublicPluginStart, DataView } from '@kbn/data-views-plugin/public'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { @@ -24,6 +25,7 @@ import type { ExpressionsStart, } from '@kbn/expressions-plugin/public'; import { + ACTION_CONVERT_DASHBOARD_PANEL_TO_LENS, DASHBOARD_VISUALIZATION_PANEL_TRIGGER, VisualizationsSetup, VisualizationsStart, @@ -94,7 +96,13 @@ import type { HeatmapVisualization as HeatmapVisualizationType } from './visuali import type { GaugeVisualization as GaugeVisualizationType } from './visualizations/gauge'; import type { TagcloudVisualization as TagcloudVisualizationType } from './visualizations/tagcloud'; -import { APP_ID, getEditPath, NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../common/constants'; +import { + APP_ID, + getEditPath, + LENS_EMBEDDABLE_TYPE, + LENS_ICON, + NOT_INTERNATIONALIZED_PRODUCT_NAME, +} from '../common/constants'; import type { FormatFactory } from '../common/types'; import type { Visualization, @@ -103,10 +111,11 @@ import type { LensTopNavMenuEntryGenerator, VisualizeEditorContext, Suggestion, + DatasourceMap, + VisualizationMap, } from './types'; import { getLensAliasConfig } from './vis_type_alias'; import { createOpenInDiscoverAction } from './trigger_actions/open_in_discover_action'; -import { ConfigureInLensPanelAction } from './trigger_actions/open_lens_config/edit_action'; import { CreateESQLPanelAction } from './trigger_actions/open_lens_config/create_action'; import { inAppEmbeddableEditTrigger, @@ -115,12 +124,12 @@ import { import { EditLensEmbeddableAction } from './trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action'; import { visualizeFieldAction } from './trigger_actions/visualize_field_actions'; import { visualizeTSVBAction } from './trigger_actions/visualize_tsvb_actions'; -import { visualizeAggBasedVisAction } from './trigger_actions/visualize_agg_based_vis_actions'; -import { visualizeDashboardVisualizePanelction } from './trigger_actions/dashboard_visualize_panel_actions'; -import type { LensByValueInput, LensEmbeddableInput } from './embeddable'; -import { EmbeddableFactory, LensEmbeddableStartServices } from './embeddable/embeddable_factory'; -import { EmbeddableComponent, getEmbeddableComponent } from './embeddable/embeddable_component'; +import type { + LensEmbeddableStartServices, + LensSerializedState, + TypedLensByValueInput, +} from './react_embeddable/types'; import { getSaveModalComponent } from './app_plugin/shared/saved_modal_lazy'; import type { SaveModalContainerProps } from './app_plugin/save_modal_container'; @@ -130,15 +139,16 @@ import { OpenInDiscoverDrilldown } from './trigger_actions/open_in_discover_dril import { ChartInfoApi } from './chart_info_api'; import { type LensAppLocator, LensAppLocatorDefinition } from '../common/locator/locator'; import { downloadCsvShareProvider } from './app_plugin/csv_download_provider/csv_download_provider'; - +import { LensDocument } from './persistence/saved_object_store'; import { CONTENT_ID, LATEST_VERSION, LensSavedObjectAttributes, } from '../common/content_management'; import type { EditLensConfigurationProps } from './app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration'; -import { savedObjectToEmbeddableAttributes } from './lens_attribute_service'; -import type { TypedLensByValueInput } from './embeddable/embeddable_component'; +import { convertToLensActionFactory } from './trigger_actions/convert_to_lens_action'; +import { LensRenderer } from './react_embeddable/renderer/lens_custom_renderer_component'; +import { deserializeState } from './react_embeddable/helper'; export type { SaveProps } from './app_plugin'; @@ -182,6 +192,7 @@ export interface LensPluginStartDependencies { contentManagement: ContentManagementPublicStart; serverless?: ServerlessPluginStart; licensing?: LicensingPluginStart; + embeddableEnhanced?: EmbeddableEnhancedPluginStart; } export interface LensPublicSetup { @@ -221,7 +232,7 @@ export interface LensPublicStart { * * @experimental */ - EmbeddableComponent: EmbeddableComponent; + EmbeddableComponent: typeof LensRenderer; /** * React component which can be used to embed a Lens Visualization Save Modal Component. * See `x-pack/examples/embedded_lens_example` for exemplary usage. @@ -248,7 +259,7 @@ export interface LensPublicStart { * @experimental */ navigateToPrefilledEditor: ( - input: LensEmbeddableInput | undefined, + input: LensSerializedState | undefined, options?: { openInNewTab?: boolean; originatingApp?: string; @@ -303,9 +314,14 @@ export class LensPlugin { private topNavMenuEntries: LensTopNavMenuEntryGenerator[] = []; private hasDiscoverAccess: boolean = false; private dataViewsService: DataViewsPublicPluginStart | undefined; - private initDependenciesForApi: () => void = () => {}; private locator?: LensAppLocator; + // Note: this method will be overwritten in the setup flow + private initEditorFrameService = async (): Promise<{ + datasourceMap: DatasourceMap; + visualizationMap: VisualizationMap; + }> => ({ datasourceMap: {}, visualizationMap: {} }); + setup( core: CoreSetup<LensPluginStartDependencies, void>, { @@ -326,26 +342,16 @@ export class LensPlugin { const startServices = createStartServicesGetter(core.getStartServices); const getStartServicesForEmbeddable = async (): Promise<LensEmbeddableStartServices> => { - const { getLensAttributeService, setUsageCollectionStart, initMemoizedErrorNotification } = - await import('./async_services'); + const { setUsageCollectionStart, initMemoizedErrorNotification } = await import( + './async_services' + ); const { core: coreStart, plugins } = startServices(); - await this.initParts( - core, - data, - charts, - expressions, - fieldFormats, - plugins.fieldFormats.deserialize - ); - const [visualizationMap, datasourceMap] = await Promise.all([ - this.editorFrameService!.loadVisualizations(), - this.editorFrameService!.loadDatasources(), + const { visualizationMap, datasourceMap } = await this.initEditorFrameService(); + const [{ getLensAttributeService }, eventAnnotationService] = await Promise.all([ + import('./async_services'), + plugins.eventAnnotation.getService(), ]); - const { setVisualizationMap, setDatasourceMap } = await import('./async_services'); - setDatasourceMap(datasourceMap); - setVisualizationMap(visualizationMap); - const eventAnnotationService = await plugins.eventAnnotation.getService(); if (plugins.usageCollection) { setUsageCollectionStart(plugins.usageCollection); @@ -354,14 +360,14 @@ export class LensPlugin { initMemoizedErrorNotification(coreStart); return { + ...plugins, attributeService: getLensAttributeService(coreStart, plugins), capabilities: coreStart.application.capabilities, coreHttp: coreStart.http, coreStart, - data: plugins.data, timefilter: plugins.data.query.timefilter.timefilter, expressionRenderer: plugins.expressions.ReactExpressionRenderer, - documentToExpression: (doc) => + documentToExpression: (doc: LensDocument) => this.editorFrameService!.documentToExpression(doc, { dataViews: plugins.dataViews, storage: new Storage(localStorage), @@ -373,36 +379,45 @@ export class LensPlugin { injectFilterReferences: data.query.filterManager.inject.bind(data.query.filterManager), visualizationMap, datasourceMap, - dataViews: plugins.dataViews, - uiActions: plugins.uiActions, - usageCollection, - inspector: plugins.inspector, - spaces: plugins.spaces, theme: core.theme, uiSettings: core.uiSettings, }; }; if (embeddable) { - embeddable.registerEmbeddableFactory( - 'lens', - new EmbeddableFactory(getStartServicesForEmbeddable) - ); - - embeddable.registerSavedObjectToPanelMethod<LensSavedObjectAttributes, LensByValueInput>( - CONTENT_ID, - (savedObject) => { - if (!savedObject.managed) { - return { savedObjectId: savedObject.id }; - } - - const panel = { - attributes: savedObjectToEmbeddableAttributes(savedObject), - }; - - return panel; - } - ); + // Let Kibana know about the Lens embeddable + embeddable.registerReactEmbeddableFactory(LENS_EMBEDDABLE_TYPE, async () => { + const [deps, { createLensEmbeddableFactory }] = await Promise.all([ + getStartServicesForEmbeddable(), + import('./react_embeddable/lens_embeddable'), + ]); + return createLensEmbeddableFactory(deps); + }); + + // Let Dashboard know about the Lens panel type + embeddable.registerReactEmbeddableSavedObject<LensSavedObjectAttributes>({ + onAdd: async (container, savedObject) => { + const { attributeService } = await getStartServicesForEmbeddable(); + // deserialize the saved object from visualize library + // this make sure to fit into the new embeddable model, where the following build() + // function expects a fully loaded runtime state + const state = await deserializeState( + attributeService, + { savedObjectId: savedObject.id }, + savedObject.references + ); + container.addNewPanel({ + panelType: LENS_EMBEDDABLE_TYPE, + initialState: state, + }); + }, + embeddableType: LENS_EMBEDDABLE_TYPE, + savedObjectType: LENS_EMBEDDABLE_TYPE, + savedObjectName: i18n.translate('xpack.lens.mapSavedObjectLabel', { + defaultMessage: 'Lens', + }), + getIconForSavedObject: () => LENS_ICON, + }); } if (share) { @@ -509,9 +524,10 @@ export class LensPlugin { ); } - urlForwarding.forwardApp('lens', 'lens'); + urlForwarding.forwardApp(APP_ID, APP_ID); - this.initDependenciesForApi = async () => { + // Note: this overwrites a method defined above + this.initEditorFrameService = async () => { const { plugins } = startServices(); await this.initParts( core, @@ -521,6 +537,15 @@ export class LensPlugin { fieldFormats, plugins.fieldFormats.deserialize ); + // This needs to be executed before the import call to avoid race conditions + const [visualizationMap, datasourceMap] = await Promise.all([ + this.editorFrameService!.loadVisualizations(), + this.editorFrameService!.loadDatasources(), + ]); + const { setVisualizationMap, setDatasourceMap } = await import('./async_services'); + setDatasourceMap(datasourceMap); + setVisualizationMap(visualizationMap); + return { datasourceMap, visualizationMap }; }; return { @@ -625,21 +650,33 @@ export class LensPlugin { startDependencies.uiActions.addTriggerAction( DASHBOARD_VISUALIZATION_PANEL_TRIGGER, - visualizeDashboardVisualizePanelction(core.application) + convertToLensActionFactory( + ACTION_CONVERT_DASHBOARD_PANEL_TO_LENS, + i18n.translate('xpack.lens.visualizeLegacyVisualizationChart', { + defaultMessage: 'Visualize legacy visualization chart', + }), + i18n.translate('xpack.lens.dashboardLabel', { + defaultMessage: 'Dashboard', + }) + )(core.application) ); startDependencies.uiActions.addTriggerAction( AGG_BASED_VISUALIZATION_TRIGGER, - visualizeAggBasedVisAction(core.application) + convertToLensActionFactory( + ACTION_CONVERT_DASHBOARD_PANEL_TO_LENS, + i18n.translate('xpack.lens.visualizeAggBasedLegend', { + defaultMessage: 'Visualize agg based chart', + }), + i18n.translate('xpack.lens.AggBasedLabel', { + defaultMessage: 'aggregation based visualization', + }) + )(core.application) ); - const editInLensAction = new ConfigureInLensPanelAction(startDependencies, core); - // dashboard edit panel action - startDependencies.uiActions.addTriggerAction('CONTEXT_MENU_TRIGGER', editInLensAction); - - // Allows the Lens embeddable to easily open the inapp editing flyout + // Allows the Lens embeddable to easily open the inline editing flyout const editLensEmbeddableAction = new EditLensEmbeddableAction(startDependencies, core); - // embeddable edit panel action + // embeddable inline edit panel action startDependencies.uiActions.addTriggerAction( IN_APP_EMBEDDABLE_EDIT_TRIGGER, editLensEmbeddableAction @@ -648,7 +685,7 @@ export class LensPlugin { // Displays the add ESQL panel in the dashboard add Panel menu const createESQLPanelAction = new CreateESQLPanelAction(startDependencies, core, async () => { if (!this.editorFrameService) { - await this.initDependenciesForApi(); + await this.initEditorFrameService(); } return this.editorFrameService!; @@ -668,7 +705,7 @@ export class LensPlugin { } return { - EmbeddableComponent: getEmbeddableComponent(core, startDependencies), + EmbeddableComponent: LensRenderer, SaveModalComponent: getSaveModalComponent(core, startDependencies), navigateToPrefilledEditor: ( input, @@ -705,16 +742,15 @@ export class LensPlugin { const { createFormulaPublicApi, createChartInfoApi, suggestionsApi } = await import( './async_services' ); - if (!this.editorFrameService) { - await this.initDependenciesForApi(); - } - const [visualizationMap, datasourceMap] = await Promise.all([ - this.editorFrameService!.loadVisualizations(), - this.editorFrameService!.loadDatasources(), - ]); + + const { visualizationMap, datasourceMap } = await this.initEditorFrameService(); return { formula: createFormulaPublicApi(), - chartInfo: createChartInfoApi(startDependencies.dataViews, this.editorFrameService), + chartInfo: createChartInfoApi( + startDependencies.dataViews, + visualizationMap, + datasourceMap + ), suggestions: ( context, dataView, @@ -734,15 +770,11 @@ export class LensPlugin { }, }; }, + // TODO: remove this in faviour of the custom action thing + // This is currently used in Discover by the unified histogram plugin EditLensConfigPanelApi: async () => { + const { visualizationMap, datasourceMap } = await this.initEditorFrameService(); const { getEditLensConfiguration } = await import('./async_services'); - if (!this.editorFrameService) { - this.initDependenciesForApi(); - } - const [visualizationMap, datasourceMap] = await Promise.all([ - this.editorFrameService!.loadVisualizations(), - this.editorFrameService!.loadDatasources(), - ]); const Component = await getEditLensConfiguration( core, startDependencies, diff --git a/x-pack/plugins/lens/public/react_embeddable/data_loader.ts b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts new file mode 100644 index 000000000000..64b7ca4501b0 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/data_loader.ts @@ -0,0 +1,329 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; +import { fetch$, type FetchContext } from '@kbn/presentation-publishing'; +import { apiPublishesSearchSession } from '@kbn/presentation-publishing/interfaces/fetch/publishes_search_session'; +import { type KibanaExecutionContext } from '@kbn/core/public'; +import { + BehaviorSubject, + type Subscription, + distinctUntilChanged, + debounceTime, + skip, + pipe, + merge, + tap, + map, +} from 'rxjs'; +import fastIsEqual from 'fast-deep-equal'; +import { getEditPath } from '../../common/constants'; +import type { + GetStateType, + LensApi, + LensInternalApi, + LensPublicCallbacks, + VisualizationContextHelper, +} from './types'; +import { getExpressionRendererParams } from './expressions/expression_params'; +import type { LensEmbeddableStartServices } from './types'; +import { prepareCallbacks } from './expressions/callbacks'; +import { buildUserMessagesHelpers } from './user_messages/api'; +import { getLogError } from './expressions/telemetry'; +import type { SharingSavedObjectProps, UserMessagesDisplayLocationId } from '../types'; +import { apiHasLensComponentCallbacks } from './type_guards'; +import { getRenderMode, getParentContext } from './helper'; +import { addLog } from './logger'; +import { getUsedDataViews } from './expressions/update_data_views'; +import { getMergedSearchContext } from './expressions/merged_search_context'; + +const blockingMessageDisplayLocations: UserMessagesDisplayLocationId[] = [ + 'visualization', + 'visualizationOnEmbeddable', +]; + +type ReloadReason = + | 'attributes' + | 'savedObjectId' + | 'overrides' + | 'disableTriggers' + | 'viewMode' + | 'searchContext'; + +/** + * The function computes the expression used to render the panel and produces the necessary props + * for the ExpressionWrapper component, binding any outer context to them. + * @returns + */ +export function loadEmbeddableData( + uuid: string, + getState: GetStateType, + api: LensApi, + parentApi: unknown, + internalApi: LensInternalApi, + services: LensEmbeddableStartServices, + { getVisualizationContext, updateVisualizationContext }: VisualizationContextHelper, + metaInfo?: SharingSavedObjectProps +) { + const { onLoad, onBeforeBadgesRender, ...callbacks } = apiHasLensComponentCallbacks(parentApi) + ? parentApi + : ({} as LensPublicCallbacks); + + // Some convenience api for the user messaging + const { + getUserMessages, + addUserMessages, + updateBlockingErrors, + updateValidationErrors, + updateWarnings, + resetMessages, + updateMessages, + } = buildUserMessagesHelpers( + api, + internalApi, + getVisualizationContext, + services, + onBeforeBadgesRender, + services.spaces, + metaInfo + ); + + const dispatchBlockingErrorIfAny = () => { + const blockingErrors = getUserMessages(blockingMessageDisplayLocations, { + severity: 'error', + }); + updateValidationErrors(blockingErrors); + updateBlockingErrors(blockingErrors); + if (blockingErrors.length > 0) { + internalApi.dispatchError(); + } + return blockingErrors.length > 0; + }; + + const onRenderComplete = () => { + updateMessages(getUserMessages('embeddableBadge')); + // No issues so far, blocking errors are handled directly by Lens from this point on + if (!dispatchBlockingErrorIfAny()) { + internalApi.dispatchRenderComplete(); + } + }; + + const unifiedSearch$ = new BehaviorSubject< + Pick<FetchContext, 'query' | 'filters' | 'timeRange' | 'timeslice' | 'searchSessionId'> + >({ + query: undefined, + filters: undefined, + timeRange: undefined, + timeslice: undefined, + searchSessionId: undefined, + }); + + async function reload( + // make reload easier to debug + sourceId: ReloadReason + ) { + addLog(`Embeddable reload reason: ${sourceId}`); + resetMessages(); + + // reset the render on reload + internalApi.dispatchRenderStart(); + + // notify about data loading + internalApi.updateDataLoading(true); + + // the component is ready to load + if (apiHasLensComponentCallbacks(parentApi)) { + parentApi.onLoad?.(true); + } + + const currentState = getState(); + + const { searchSessionId, ...unifiedSearch } = unifiedSearch$.getValue(); + + const getExecutionContext = () => { + const parentContext = getParentContext(parentApi); + const lastState = getState(); + if (lastState.attributes) { + const child: KibanaExecutionContext = { + type: 'lens', + name: lastState.attributes.visualizationType ?? '', + id: uuid || 'new', + description: lastState.attributes.title || lastState.title || '', + url: `${services.coreStart.application.getUrlForApp('lens')}${getEditPath( + lastState.savedObjectId + )}`, + }; + + return parentContext + ? { + ...parentContext, + child, + } + : child; + } + }; + + const onDataCallback = (adapters: Partial<DefaultInspectorAdapters> | undefined) => { + updateVisualizationContext({ + activeData: adapters?.tables?.tables, + }); + // data has loaded + internalApi.updateDataLoading(false); + // The third argument here is an observable to let the + // consumer to be notified on data change + onLoad?.(false, adapters, api.dataLoading); + + api.loadViewUnderlyingData(); + + updateWarnings(); + // Render can still go wrong, so perfor a new check + dispatchBlockingErrorIfAny(); + }; + + const { onRender, onData, handleEvent, disableTriggers } = prepareCallbacks( + api, + internalApi, + parentApi, + getState, + services, + getExecutionContext(), + onDataCallback, + onRenderComplete, + callbacks + ); + + const searchContext = getMergedSearchContext( + currentState, + unifiedSearch, + api.timeRange$, + parentApi, + services + ); + + // Go concurrently: build the expression and fetch the dataViews + const [{ params, abortController, ...rest }, dataViews] = await Promise.all([ + getExpressionRendererParams(currentState, { + searchContext, + api, + settings: { + syncColors: currentState.syncColors, + syncCursor: currentState.syncCursor, + syncTooltips: currentState.syncTooltips, + }, + renderMode: getRenderMode(parentApi), + services, + searchSessionId, + abortController: internalApi.expressionAbortController$.getValue(), + getExecutionContext, + logError: getLogError(getExecutionContext), + addUserMessages, + onRender, + onData, + handleEvent, + disableTriggers, + updateBlockingErrors, + getDisplayOptions: internalApi.getDisplayOptions, + }), + getUsedDataViews( + currentState.attributes.references, + currentState.attributes.state?.adHocDataViews, + services.dataViews + ), + ]); + + // update the visualization context before anything else + // as it will be used to compute blocking errors also in case of issues + updateVisualizationContext({ + doc: currentState.attributes, + mergedSearchContext: params?.searchContext || {}, + ...rest, + }); + + // Publish the used dataViews on the Lens API + internalApi.updateDataViews(dataViews); + + if (params?.expression != null && !dispatchBlockingErrorIfAny()) { + internalApi.updateExpressionParams(params); + } + + internalApi.updateAbortController(abortController); + } + + // Build a custom operator to be resused for various observables + function waitUntilChanged() { + return pipe(distinctUntilChanged(fastIsEqual), skip(1)); + } + + const mergedSubscriptions = merge( + // on data change from the parentApi, reload + fetch$(api).pipe( + tap((data) => { + const searchSessionId = apiPublishesSearchSession(parentApi) ? data.searchSessionId : ''; + unifiedSearch$.next({ + query: data.query, + filters: data.filters, + timeRange: data.timeRange, + timeslice: data.timeslice, + searchSessionId, + }); + }), + map(() => 'searchContext' as ReloadReason) + ), + // On state change, reload + // this is used to refresh the chart on inline editing + // just make sure to avoid to rerender if there's no substantial change + // make sure to debounce one tick to make the refresh work + internalApi.attributes$.pipe( + waitUntilChanged(), + tap(() => { + // the ES|QL query may have changed, so recompute the args for view underlying data + if (api.isTextBasedLanguage()) { + api.loadViewUnderlyingData(); + } + }), + map(() => 'attributes' as ReloadReason) + ), + api.savedObjectId.pipe( + waitUntilChanged(), + map(() => 'savedObjectId' as ReloadReason) + ), + internalApi.overrides$.pipe( + waitUntilChanged(), + map(() => 'overrides' as ReloadReason) + ), + internalApi.disableTriggers$.pipe( + waitUntilChanged(), + map(() => 'disableTriggers' as ReloadReason) + ) + ); + + const subscriptions: Subscription[] = [ + mergedSubscriptions.pipe(debounceTime(0)).subscribe(reload), + // make sure to reload on viewMode change + api.viewMode.subscribe(() => { + // only reload if drilldowns are set + if (getState().enhancements?.dynamicActions) { + reload('viewMode'); + } + }), + ]; + // There are few key moments when errors are checked and displayed: + // * at setup time (here) before the first expression evaluation + // * at runtime => when the expression is running and ES/Kibana server could emit errors) + // * at data time => data has arrived but for something goes wrong + // * at render time => rendering happened but somethign went wrong + // Bubble the error up to the embeddable system if any + dispatchBlockingErrorIfAny(); + + return { + cleanup: () => { + for (const subscription of subscriptions) { + subscription.unsubscribe(); + } + }, + }; +} diff --git a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx b/x-pack/plugins/lens/public/react_embeddable/expression_wrapper.tsx similarity index 88% rename from x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx rename to x-pack/plugins/lens/public/react_embeddable/expression_wrapper.tsx index d16df5bf9d1e..e0d21d9ba835 100644 --- a/x-pack/plugins/lens/public/embeddable/expression_wrapper.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/expression_wrapper.tsx @@ -17,7 +17,7 @@ import { DefaultInspectorAdapters, RenderMode } from '@kbn/expressions-plugin/co import classNames from 'classnames'; import { getOriginalRequestErrorMessages } from '../editor_frame_service/error_helper'; import { LensInspector } from '../lens_inspector_service'; -import { AddUserMessages } from '../types'; +import { UserMessage } from '../types'; export interface ExpressionWrapperProps { ExpressionRenderer: ReactExpressionRendererType; @@ -31,7 +31,7 @@ export interface ExpressionWrapperProps { data: unknown, inspectorAdapters?: Partial<DefaultInspectorAdapters> | undefined ) => void; - onRender$: () => void; + onRender$: (count: number) => void; renderMode?: RenderMode; syncColors?: boolean; syncTooltips?: boolean; @@ -40,7 +40,7 @@ export interface ExpressionWrapperProps { getCompatibleCellValueActions?: ReactExpressionRendererProps['getCompatibleCellValueActions']; style?: React.CSSProperties; className?: string; - addUserMessages: AddUserMessages; + addUserMessages: (messages: UserMessage[]) => void; onRuntimeError: (error: Error) => void; executionContext?: KibanaExecutionContext; lensInspector: LensInspector; @@ -75,7 +75,11 @@ export function ExpressionWrapper({ }: ExpressionWrapperProps) { if (!expression) return null; return ( - <div className={classNames('lnsExpressionRenderer', className)} style={style}> + <div + className={classNames('lnsExpressionRenderer', className)} + style={style} + data-test-subj="lens-embeddable" + > <ExpressionRendererComponent className="lnsExpressionRenderer__component" padding={noPadding ? undefined : 's'} @@ -88,7 +92,7 @@ export function ExpressionWrapper({ // @ts-expect-error upgrade typescript v4.9.5 onData$={onData$} onRender$={onRender$} - inspectorAdapters={lensInspector.adapters} + inspectorAdapters={lensInspector.getInspectorAdapters()} renderMode={renderMode} syncColors={syncColors} syncTooltips={syncTooltips} @@ -98,12 +102,7 @@ export function ExpressionWrapper({ renderError={(errorMessage, error) => { const messages = getOriginalRequestErrorMessages(error || null); addUserMessages(messages); - if (error?.original) { - onRuntimeError(error.original); - } else { - onRuntimeError(new Error(errorMessage ? errorMessage : '')); - } - + onRuntimeError(error?.original || new Error(errorMessage ? errorMessage : '')); return <></>; // the embeddable will take care of displaying the messages }} onEvent={handleEvent} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/callbacks.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/callbacks.ts new file mode 100644 index 000000000000..78a9aa6ab918 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/callbacks.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaExecutionContext } from '@kbn/core/public'; +import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; +import { apiHasDisableTriggers } from '@kbn/presentation-publishing'; +import { + GetStateType, + LensApi, + LensEmbeddableStartServices, + LensInternalApi, + LensPublicCallbacks, +} from '../types'; +import { prepareOnRender } from './on_render'; +import { prepareEventHandler } from './on_event'; +import { addLog } from '../logger'; + +export function prepareCallbacks( + api: LensApi, + internalApi: LensInternalApi, + parentApi: unknown, + getState: GetStateType, + services: LensEmbeddableStartServices, + executionContext: KibanaExecutionContext | undefined, + onDataUpdate: (adapters: Partial<DefaultInspectorAdapters | undefined>) => void, + dispatchRenderComplete: () => void, + callbacks: LensPublicCallbacks +) { + const disableTriggers = apiHasDisableTriggers(parentApi) ? parentApi.disableTriggers : undefined; + return { + disableTriggers, + onRender: prepareOnRender( + api, + internalApi, + parentApi, + getState, + services, + executionContext, + dispatchRenderComplete + ), + onData: (_data: unknown, adapters: Partial<DefaultInspectorAdapters> | undefined) => { + addLog(`onData$`); + onDataUpdate(adapters); + }, + handleEvent: prepareEventHandler(api, getState, callbacks, services, disableTriggers), + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts new file mode 100644 index 000000000000..ff6206f3f70e --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/expression_params.ts @@ -0,0 +1,239 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import type { Action } from '@kbn/ui-actions-plugin/public'; +import { RenderMode } from '@kbn/expressions-plugin/common'; +import { ExpressionRendererEvent } from '@kbn/expressions-plugin/public'; +import { toExpression } from '@kbn/interpreter'; +import { noop } from 'lodash'; +import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; +import { + CellValueContext, + cellValueTrigger, + CELL_VALUE_TRIGGER, +} from '@kbn/embeddable-plugin/public'; +import { DocumentToExpressionReturnType } from '../../async_services'; +import { LensDocument } from '../../persistence'; +import { + GetCompatibleCellValueActions, + IndexPatternMap, + IndexPatternRef, + UserMessage, + VisualizationDisplayOptions, + isLensFilterEvent, + isLensMultiFilterEvent, + isLensTableRowContextMenuClickEvent, +} from '../../types'; +import type { + ExpressionWrapperProps, + LensApi, + LensEmbeddableStartServices, + LensRuntimeState, +} from '../types'; +import { getVariables } from './variables'; +// import { +// getSearchContextIncompatibleMessage, +// isSearchContextIncompatibleWithDataViews, +// } from '../user_messages/checks'; +import { getExecutionSearchContext, type MergedSearchContext } from './merged_search_context'; + +interface GetExpressionRendererPropsParams { + searchContext: MergedSearchContext; + disableTriggers?: boolean; + renderMode?: RenderMode; + settings: { + syncColors?: boolean; + syncCursor?: boolean; + syncTooltips?: boolean; + }; + services: LensEmbeddableStartServices; + getExecutionContext: () => KibanaExecutionContext | undefined; + searchSessionId?: string; + abortController?: AbortController; + onRender: (count: number) => void; + handleEvent: (event: ExpressionRendererEvent) => void; + onData: ExpressionWrapperProps['onData$']; + logError: (type: 'runtime' | 'validation') => void; + api: LensApi; + addUserMessages: (messages: UserMessage[]) => void; + updateBlockingErrors: (error: Error) => void; + getDisplayOptions: () => VisualizationDisplayOptions; +} + +async function getExpressionFromDocument( + document: LensDocument, + documentToExpression: (doc: LensDocument) => Promise<DocumentToExpressionReturnType> +) { + const { ast, indexPatterns, indexPatternRefs, activeVisualizationState, activeDatasourceState } = + await documentToExpression(document); + return { + expression: ast ? toExpression(ast) : null, + indexPatterns, + indexPatternRefs, + activeVisualizationState, + activeDatasourceState, + }; +} + +function buildHasCompatibleActions(api: LensApi, { uiActions }: LensEmbeddableStartServices) { + return async (event: ExpressionRendererEvent): Promise<boolean> => { + if (!uiActions?.getTriggerCompatibleActions) { + return false; + } + if ( + isLensTableRowContextMenuClickEvent(event) || + isLensMultiFilterEvent(event) || + isLensFilterEvent(event) + ) { + const actions = await uiActions.getTriggerCompatibleActions( + VIS_EVENT_TO_TRIGGER[event.name], + { + data: event.data, + embeddable: api, + } + ); + + return actions.length > 0; + } + + return false; + }; +} + +function buildGetCompatibleCellValueActions( + api: LensApi, + { uiActions }: LensEmbeddableStartServices +): GetCompatibleCellValueActions { + return async (data) => { + if (!uiActions?.getTriggerCompatibleActions) { + return []; + } + const actions: Array<Action<CellValueContext>> = (await uiActions.getTriggerCompatibleActions( + CELL_VALUE_TRIGGER, + { data, embeddable: api } + )) as Array<Action<CellValueContext>>; + return actions + .sort((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity)) + .map((action) => ({ + id: action.id, + type: action.type, + iconType: action.getIconType({ embeddable: api, data, trigger: cellValueTrigger })!, + displayName: action.getDisplayName({ embeddable: api, data, trigger: cellValueTrigger }), + execute: (cellData) => + action.execute({ embeddable: api, data: cellData, trigger: cellValueTrigger }), + })); + }; +} + +export async function getExpressionRendererParams( + state: LensRuntimeState, + { + settings: { syncColors = true, syncCursor = true, syncTooltips = false }, + services, + disableTriggers = false, + getExecutionContext, + searchSessionId, + abortController, + onRender, + handleEvent, + onData = noop, + logError, + api, + addUserMessages, + updateBlockingErrors, + searchContext, + getDisplayOptions, + }: GetExpressionRendererPropsParams +): Promise<{ + params: ExpressionWrapperProps | null; + abortController?: AbortController; + indexPatterns: IndexPatternMap; + indexPatternRefs: IndexPatternRef[]; + activeVisualizationState?: unknown; + activeDatasourceState?: unknown; +}> { + const { expressionRenderer, documentToExpression } = services; + + const { + expression, + indexPatterns, + indexPatternRefs, + activeVisualizationState, + activeDatasourceState, + } = await getExpressionFromDocument(state.attributes, documentToExpression); + + // Apparently this change produces had lots of issues with solutions not using + // the Embeddable incorrectly. Will comment for now and later on will restore it when + // https://github.com/elastic/kibana/issues/200236 is resolved + // + // if at least one indexPattern is time based, then the Lens embeddable requires the timeRange prop + // this is necessary for the dataview embeddable but not the ES|QL one + // if ( + // isSearchContextIncompatibleWithDataViews( + // api, + // getExecutionContext(), + // searchContext, + // indexPatternRefs, + // indexPatterns + // ) + // ) { + // addUserMessages([getSearchContextIncompatibleMessage()]); + // } + + if (expression) { + const params: ExpressionWrapperProps = { + expression, + syncColors, + syncCursor, + syncTooltips, + searchSessionId, + onRender$: onRender, + handleEvent, + onData$: onData, + // Remove ES|QL query from it + searchContext: getExecutionSearchContext(searchContext), + interactive: !disableTriggers, + executionContext: getExecutionContext(), + lensInspector: { + getInspectorAdapters: api.getInspectorAdapters, + inspect: api.inspect, + closeInspector: api.closeInspector, + }, + ExpressionRenderer: expressionRenderer, + addUserMessages, + onRuntimeError: (error: Error) => { + updateBlockingErrors(error); + logError('runtime'); + }, + abortController, + hasCompatibleActions: buildHasCompatibleActions(api, services), + getCompatibleCellValueActions: buildGetCompatibleCellValueActions(api, services), + variables: getVariables(api, state), + style: state.style, + className: state.className, + noPadding: getDisplayOptions().noPadding, + }; + return { + indexPatterns, + indexPatternRefs, + activeVisualizationState, + activeDatasourceState, + params, + abortController, + }; + } + + return { + params: null, + abortController, + indexPatterns, + indexPatternRefs, + activeVisualizationState, + activeDatasourceState, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/merged_search_context.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/merged_search_context.ts new file mode 100644 index 000000000000..5b467dd706a6 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/merged_search_context.ts @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { DataPublicPluginStart, FilterManager } from '@kbn/data-plugin/public'; +import { + type AggregateQuery, + type Filter, + isOfAggregateQueryType, + type Query, + type TimeRange, + ExecutionContextSearch, +} from '@kbn/es-query'; +import { PublishingSubject, apiPublishesTimeslice } from '@kbn/presentation-publishing'; +import type { LensRuntimeState } from '../types'; +import { nonNullable } from '../../utils'; + +export interface MergedSearchContext { + now: number; + timeRange: TimeRange | undefined; + query: Array<Query | AggregateQuery>; + filters: Filter[]; + disableWarningToasts: boolean; +} + +export function getMergedSearchContext( + { attributes }: LensRuntimeState, + { + filters, + query, + timeRange, + }: { + filters?: Filter[]; + query?: Query | AggregateQuery; + timeRange?: TimeRange; + }, + customTimeRange$: PublishingSubject<TimeRange | undefined>, + parentApi: unknown, + { + data, + injectFilterReferences, + }: { data: DataPublicPluginStart; injectFilterReferences: FilterManager['inject'] } +): MergedSearchContext { + const parentTimeSlice = apiPublishesTimeslice(parentApi) + ? parentApi.timeslice$.getValue() + : undefined; + + const timesliceTimeRange = parentTimeSlice + ? { + from: new Date(parentTimeSlice[0]).toISOString(), + to: new Date(parentTimeSlice[1]).toISOString(), + mode: 'absolute' as 'absolute', + } + : undefined; + + const customTimeRange = customTimeRange$.getValue(); + + const timeRangeToRender = customTimeRange ?? timesliceTimeRange ?? timeRange; + const context = { + now: data.nowProvider.get().getTime(), + timeRange: timeRangeToRender, + query: [attributes.state.query].filter(nonNullable), + filters: injectFilterReferences(attributes.state.filters || [], attributes.references), + disableWarningToasts: true, + }; + // Prepend query and filters from dashboard to the visualization ones + if (query) { + if (!isOfAggregateQueryType(query)) { + context.query.unshift(query); + } + } + if (filters) { + context.filters.unshift(...filters.filter(({ meta }) => !meta.disabled)); + } + return context; +} + +export function getExecutionSearchContext( + searchContext: MergedSearchContext +): ExecutionContextSearch { + if (!isOfAggregateQueryType(searchContext.query[0])) { + return searchContext as ExecutionContextSearch; + } + return { + ...searchContext, + query: [], + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts new file mode 100644 index 000000000000..dfddfe84b57c --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.test.ts @@ -0,0 +1,181 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExpressionRendererEvent } from '@kbn/expressions-plugin/public'; +import { getLensApiMock, getLensRuntimeStateMock, makeEmbeddableServices } from '../mocks'; +import { LensApi, LensEmbeddableStartServices, LensPublicCallbacks } from '../types'; +import { prepareEventHandler } from './on_event'; +import faker from 'faker'; +import { + LENS_EDIT_PAGESIZE_ACTION, + LENS_EDIT_RESIZE_ACTION, + LENS_EDIT_SORT_ACTION, + LENS_TOGGLE_ACTION, +} from '../../visualizations/datatable/components/constants'; + +describe('Embeddable interaction event handlers', () => { + beforeEach(() => { + // LensAPI mock is a static mock, so we need to reset it between tests + jest.resetAllMocks(); + }); + + function getCallbacks(shouldPreventDefault?: boolean) { + if (!shouldPreventDefault) { + return { onFilter: jest.fn(), onBrushEnd: jest.fn(), onTableRowClick: jest.fn() }; + } + return { + onFilter: jest.fn((event) => event.preventDefault()), + onBrushEnd: jest.fn((event) => event.preventDefault()), + onTableRowClick: jest.fn((event) => event.preventDefault()), + }; + } + + function getHandler( + api: LensApi = getLensApiMock(), + callbacks: LensPublicCallbacks = getCallbacks(), + services: LensEmbeddableStartServices = makeEmbeddableServices(), + disableTriggers: boolean = false + ) { + return prepareEventHandler( + api, + jest.fn(() => getLensRuntimeStateMock()), + callbacks, + services, + disableTriggers + ); + } + + function getTable() { + return { columns: { test: { meta: { field: '@timestamp', sourceParams: {} } } } }; + } + + async function submitEvent(event: ExpressionRendererEvent, callPreventDefault: boolean = false) { + const onEditAction = jest.fn(); + const callbacks = getCallbacks(callPreventDefault); + const services = makeEmbeddableServices(undefined, undefined, { + visOverrides: { id: 'lnsXY', onEditAction }, + }); + const lensApi = getLensApiMock(); + const handler = getHandler(lensApi, callbacks, services); + + await handler(event); + + return { + reSubmit: (newEvent: ExpressionRendererEvent) => handler(newEvent), + callbacks, + getTrigger: services.uiActions.getTrigger, + updateAttributes: lensApi.updateAttributes, + onEditAction, + }; + } + + it('should call onTableRowClick event ', async () => { + const event = { + name: 'tableRowContextMenuClick', + data: { rowIndex: 1, table: getTable() }, + }; + const { callbacks } = await submitEvent(event); + expect(callbacks.onTableRowClick).toHaveBeenCalledWith(expect.objectContaining(event.data)); + }); + it('should prevent onTableRowClick trigger when calling preventDefault ', async () => { + const event = { + name: 'tableRowContextMenuClick', + data: { rowIndex: 1, table: getTable() }, + }; + const { getTrigger } = await submitEvent(event, true); + expect(getTrigger).not.toHaveBeenCalled(); + }); + it('should call onBrush event on filter call ', async () => { + const event = { + name: 'brush', + data: { column: 'test', range: [1, 2], table: getTable() }, + }; + const { callbacks } = await submitEvent(event); + expect(callbacks.onBrushEnd).toHaveBeenCalledWith(expect.objectContaining(event.data)); + }); + it('should prevent the onBrush trigger when calling preventDefault', async () => { + const event = { + name: 'brush', + data: { column: 'test', range: [1, 2], table: getTable() }, + }; + const { getTrigger } = await submitEvent(event, true); + expect(getTrigger).not.toHaveBeenCalled(); + }); + it('should call onFilter event on filter call ', async () => { + const event = { + name: 'filter', + data: { + data: [{ value: faker.random.number(), row: 1, column: 'test', table: getTable() }], + }, + }; + const { callbacks } = await submitEvent(event); + expect(callbacks.onFilter).toHaveBeenCalledWith(expect.objectContaining(event.data)); + }); + it('should prevent the onFilter trigger when calling preventDefault', async () => { + const event = { + name: 'filter', + data: { + data: [{ value: faker.random.number(), row: 1, column: 'test', table: getTable() }], + }, + }; + const { getTrigger } = await submitEvent(event, true); + expect(getTrigger).not.toHaveBeenCalled(); + }); + + it('should reload on edit events', async () => { + const { reSubmit, onEditAction, updateAttributes } = await submitEvent({ + name: 'edit', + data: { action: LENS_EDIT_SORT_ACTION }, + }); + + expect(onEditAction).toHaveBeenCalled(); + expect(updateAttributes).toHaveBeenCalled(); + + await reSubmit({ name: 'edit', data: { action: LENS_EDIT_RESIZE_ACTION } }); + + expect(onEditAction).toHaveBeenCalled(); + expect(updateAttributes).toHaveBeenCalled(); + + await reSubmit({ name: 'edit', data: { action: LENS_TOGGLE_ACTION } }); + + expect(onEditAction).toHaveBeenCalled(); + expect(updateAttributes).toHaveBeenCalled(); + + await reSubmit({ name: 'edit', data: { action: LENS_EDIT_PAGESIZE_ACTION } }); + + expect(onEditAction).toHaveBeenCalled(); + expect(updateAttributes).toHaveBeenCalled(); + }); + + it('should not reload on non-edit events', async () => { + const { reSubmit, onEditAction, updateAttributes } = await submitEvent({ + name: 'tableRowContextMenuClick', + data: { rowIndex: 1, table: getTable() }, + }); + + expect(onEditAction).not.toHaveBeenCalled(); + expect(updateAttributes).not.toHaveBeenCalled(); + + await reSubmit({ + name: 'brush', + data: { column: 'test', range: [1, 2], table: getTable() }, + }); + + expect(onEditAction).not.toHaveBeenCalled(); + expect(updateAttributes).not.toHaveBeenCalled(); + + await reSubmit({ + name: 'filter', + data: { + data: [{ value: faker.random.number(), row: 1, column: 'test', table: getTable() }], + }, + }); + + expect(onEditAction).not.toHaveBeenCalled(); + expect(updateAttributes).not.toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.ts new file mode 100644 index 000000000000..71ce4e15693c --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/on_event.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ExpressionRendererEvent } from '@kbn/expressions-plugin/public'; +import { VIS_EVENT_TO_TRIGGER } from '@kbn/visualizations-plugin/public'; +import { type AggregateQuery, type Query, isOfAggregateQueryType } from '@kbn/es-query'; +import { + isLensBrushEvent, + isLensEditEvent, + isLensFilterEvent, + isLensMultiFilterEvent, + isLensTableRowContextMenuClickEvent, +} from '../../types'; +import { inferTimeField } from '../../utils'; +import type { + GetStateType, + LensApi, + LensEmbeddableStartServices, + LensPublicCallbacks, +} from '../types'; +import { isTextBasedLanguage } from '../helper'; +import { addLog } from '../logger'; + +export const prepareEventHandler = + ( + api: LensApi, + getState: GetStateType, + callbacks: LensPublicCallbacks, + { data, uiActions, visualizationMap }: LensEmbeddableStartServices, + disableTriggers: boolean | undefined + ) => + async (event: ExpressionRendererEvent) => { + if (!uiActions?.getTrigger || disableTriggers) { + return; + } + addLog(`onEvent$`); + + let eventHandler: + | LensPublicCallbacks['onBrushEnd'] + | LensPublicCallbacks['onFilter'] + | LensPublicCallbacks['onTableRowClick']; + let shouldExecuteDefaultTriggers = true; + + if (isLensBrushEvent(event)) { + eventHandler = callbacks.onBrushEnd; + } else if (isLensFilterEvent(event) || isLensMultiFilterEvent(event)) { + eventHandler = callbacks.onFilter; + } else if (isLensTableRowContextMenuClickEvent(event)) { + eventHandler = callbacks.onTableRowClick; + } + const currentState = getState(); + + eventHandler?.({ + ...event.data, + preventDefault: () => { + shouldExecuteDefaultTriggers = false; + }, + }); + + if (isLensFilterEvent(event) || isLensMultiFilterEvent(event) || isLensBrushEvent(event)) { + if (shouldExecuteDefaultTriggers) { + // if the embeddable is located in an app where there is the Unified search bar with the ES|QL editor, then use this query + // otherwise use the query from the saved object + let esqlQuery: AggregateQuery | Query | undefined; + if (isTextBasedLanguage(currentState)) { + const query = data.query.queryString.getQuery(); + esqlQuery = isOfAggregateQueryType(query) ? query : currentState.attributes.state.query; + } + uiActions.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec({ + data: { + ...event.data, + timeFieldName: + event.data.timeFieldName || inferTimeField(data.datatableUtilities, event), + query: esqlQuery, + }, + embeddable: api, + }); + } + } + + if (isLensTableRowContextMenuClickEvent(event)) { + if (shouldExecuteDefaultTriggers) { + uiActions.getTrigger(VIS_EVENT_TO_TRIGGER[event.name]).exec( + { + data: event.data, + embeddable: api, + }, + true + ); + } + } + + const onEditAction = currentState.attributes.visualizationType + ? visualizationMap[currentState.attributes.visualizationType]?.onEditAction + : undefined; + + // We allow for edit actions in the Embeddable for display purposes only (e.g. changing the datatable sort order). + // No state changes made here with an edit action are persisted. + if (isLensEditEvent(event) && onEditAction) { + // updating the state would trigger a reload + api.updateAttributes({ + ...currentState.attributes, + state: { + ...currentState.attributes.state, + visualization: onEditAction(currentState.attributes.state.visualization, event), + }, + }); + } + }; diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/on_render.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/on_render.ts new file mode 100644 index 000000000000..ba0a47b5944e --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/on_render.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaExecutionContext } from '@kbn/core-execution-context-common'; +import { canTrackContentfulRender } from '@kbn/presentation-containers'; +import { reportPerformanceMetricEvent } from '@kbn/ebt-tools'; +import { TableInspectorAdapter } from '../../editor_frame_service/types'; + +import { getExecutionContextEvents, trackUiCounterEvents } from '../../lens_ui_telemetry'; +import { GetStateType, LensApi, LensEmbeddableStartServices, LensInternalApi } from '../types'; +import { getSuccessfulRequestTimings } from '../../report_performance_metric_util'; +import { addLog } from '../logger'; + +function trackContentfulRender(activeData: TableInspectorAdapter, parentApi: unknown) { + if (!canTrackContentfulRender(parentApi)) { + return; + } + + const hasData = Object.values(activeData).some((table) => { + if (table.meta?.statistics?.totalCount != null) { + // if totalCount is set, refer to total count + return table.meta.statistics.totalCount > 0; + } + // if not, fall back to check the rows of the table + return table.rows.length > 0; + }); + + if (hasData) { + parentApi.trackContentfulRender(); + } +} + +function trackPerformanceMetrics( + api: LensApi, + coreStart: LensEmbeddableStartServices['coreStart'] +) { + const inspectorAdapters = api.getInspectorAdapters(); + const timings = getSuccessfulRequestTimings(inspectorAdapters); + if (timings) { + const esRequestMetrics = { + eventName: 'lens_chart_es_request_totals', + duration: timings.requestTimeTotal, + key1: 'es_took_total', + value1: timings.esTookTotal, + }; + reportPerformanceMetricEvent(coreStart.analytics, esRequestMetrics); + } +} + +export function prepareOnRender( + api: LensApi, + internalApi: LensInternalApi, + parentApi: unknown, + getState: GetStateType, + { datasourceMap, visualizationMap, coreStart }: LensEmbeddableStartServices, + executionContext: KibanaExecutionContext | undefined, + dispatchRenderComplete: () => void +) { + return function onRender$(count: number) { + addLog(`onRender$ ${count}`); + // for some reason onRender$ is emitting multiple times with the same render count + // so avoid to repeat the same logic on duplicate calls + if (count === internalApi.renderCount$.getValue()) { + return; + } + let datasourceEvents: string[] = []; + let visualizationEvents: string[] = []; + const currentState = getState(); + + if (currentState) { + datasourceEvents = Object.values(datasourceMap).reduce<string[]>( + (acc, datasource) => [ + ...acc, + ...(datasource.getRenderEventCounters?.( + currentState.attributes.state.datasourceStates[datasource.id] + ) ?? []), + ], + [] + ); + + if (currentState.attributes.visualizationType) { + visualizationEvents = + visualizationMap[currentState.attributes.visualizationType].getRenderEventCounters?.( + currentState.attributes.state.visualization + ) ?? []; + } + } + + const events = [ + ...datasourceEvents, + ...visualizationEvents, + ...getExecutionContextEvents(executionContext), + ]; + + const adHocDataViews = Object.values(currentState.attributes.state.adHocDataViews || {}); + adHocDataViews.forEach(() => { + events.push('ad_hoc_data_view'); + }); + + trackUiCounterEvents(events, executionContext); + + trackContentfulRender(api.getInspectorAdapters().tables?.tables, parentApi); + + dispatchRenderComplete(); + + trackPerformanceMetrics(api, coreStart); + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/telemetry.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/telemetry.ts new file mode 100644 index 000000000000..ede2f1b0aaf3 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/telemetry.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { KibanaExecutionContext } from '@kbn/core/public'; +import { trackUiCounterEvents } from '../../lens_ui_telemetry'; + +export function getLogError(getExecutionContext: () => KibanaExecutionContext | undefined) { + return (type: 'runtime' | 'validation') => { + trackUiCounterEvents( + type === 'runtime' ? 'embeddable_runtime_error' : 'embeddable_validation_error', + getExecutionContext() + ); + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/update_data_views.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/update_data_views.ts new file mode 100644 index 000000000000..0e7f130d339d --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/update_data_views.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { uniqBy } from 'lodash'; +import { getIndexPatternsObjects } from '../../utils'; +import { LensEmbeddableStartServices, LensRuntimeState } from '../types'; + +export async function getUsedDataViews( + references: LensRuntimeState['attributes']['references'], + adHocDataViewsSpecs: LensRuntimeState['attributes']['state']['adHocDataViews'], + dataViews: LensEmbeddableStartServices['dataViews'] +) { + const [{ indexPatterns }, ...adHocDataViews] = await Promise.all([ + getIndexPatternsObjects(references.map(({ id }) => id) || [], dataViews), + ...Object.values(adHocDataViewsSpecs || {}).map((spec) => dataViews.create(spec)), + ]); + + return uniqBy(indexPatterns.concat(adHocDataViews), 'id'); +} diff --git a/x-pack/plugins/lens/public/react_embeddable/expressions/variables.ts b/x-pack/plugins/lens/public/react_embeddable/expressions/variables.ts new file mode 100644 index 000000000000..c1fdda750199 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/expressions/variables.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Datatable } from '@kbn/expressions-plugin/common'; +import type { TextBasedPersistedState } from '../../datasources/text_based/types'; +import { LensApi, LensRuntimeState } from '../types'; + +function getInternalTables(states: Record<string, unknown>) { + const result: Record<string, Datatable> = {}; + if ('textBased' in states) { + const layers = (states.textBased as TextBasedPersistedState).layers; + for (const layer in layers) { + if (layers[layer]?.table) { + result[layer] = layers[layer].table!; + } + } + } + return result; +} + +/** + * Collect all the data that need to be forwarded at the end of the + * expression pipeline as overrides, palette, etc... and merged them all here + */ +export function getVariables(api: LensApi, state: LensRuntimeState) { + return { + embeddableTitle: api.defaultPanelTitle?.getValue(), + ...(state.palette ? { theme: { palette: state.palette } } : {}), + ...('overrides' in state ? { overrides: state.overrides } : {}), + ...getInternalTables(state.attributes.state.datasourceStates), + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/helper.test.ts b/x-pack/plugins/lens/public/react_embeddable/helper.test.ts new file mode 100644 index 000000000000..33a8d0d0093d --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/helper.test.ts @@ -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 { defaultDoc, makeAttributeService } from '../mocks/services_mock'; +import { deserializeState } from './helper'; + +describe('Embeddable helpers', () => { + describe('deserializeState', () => { + it('should forward a by value raw state', async () => { + const attributeService = makeAttributeService(defaultDoc); + const rawState = { + attributes: defaultDoc, + }; + const runtimeState = await deserializeState(attributeService, rawState); + expect(runtimeState).toEqual(rawState); + }); + + it('should wrap Lens doc/attributes into component state shape', async () => { + const attributeService = makeAttributeService(defaultDoc); + const runtimeState = await deserializeState(attributeService, defaultDoc); + expect(runtimeState).toEqual( + expect.objectContaining({ + attributes: { ...defaultDoc, references: defaultDoc.references }, + }) + ); + }); + + it('load a by-ref doc from the attribute service', async () => { + const attributeService = makeAttributeService(defaultDoc); + await deserializeState(attributeService, { + savedObjectId: '123', + }); + + expect(attributeService.loadFromLibrary).toHaveBeenCalledWith('123'); + }); + + it('should fallback to an empty Lens doc if the saved object is not found', async () => { + const attributeService = makeAttributeService(defaultDoc); + attributeService.loadFromLibrary.mockRejectedValueOnce(new Error('not found')); + const runtimeState = await deserializeState(attributeService, { + savedObjectId: '123', + }); + // check the visualizationType set to null for empty state + expect(runtimeState.attributes.visualizationType).toBeNull(); + }); + + describe('injected references should overwrite inner ones', () => { + // There are 3 possible scenarios here for reference injections: + // * default space for a by-value + // * default space for a by-ref with a "lens" panel reference type + // * other space for a by-value with new ref ids + + it('should inject correctly serialized references into runtime state for a by value in the default space', async () => { + const attributeService = makeAttributeService(defaultDoc); + const mockedReferences = [ + { id: 'serializedRefs', name: 'index-pattern-0', type: 'mocked-reference' }, + ]; + const runtimeState = await deserializeState( + attributeService, + { + attributes: defaultDoc, + }, + mockedReferences + ); + expect(attributeService.injectReferences).toHaveBeenCalled(); + expect(runtimeState.attributes.references).toEqual(mockedReferences); + }); + + it('should inject correctly serialized references into runtime state for a by ref in the default space', async () => { + const attributeService = makeAttributeService(defaultDoc); + const mockedReferences = [ + { id: 'serializedRefs', name: 'index-pattern-0', type: 'mocked-reference' }, + ]; + const runtimeState = await deserializeState( + attributeService, + { + savedObjectId: '123', + }, + mockedReferences + ); + expect(attributeService.injectReferences).not.toHaveBeenCalled(); + // Note the original references should be kept + expect(runtimeState.attributes.references).toEqual(defaultDoc.references); + }); + + it('should inject correctly serialized references into runtime state for a by value in another space', async () => { + const attributeService = makeAttributeService(defaultDoc); + const mockedReferences = [ + { id: 'serializedRefs', name: 'index-pattern-0', type: 'mocked-reference' }, + ]; + const runtimeState = await deserializeState( + attributeService, + { + attributes: defaultDoc, + }, + mockedReferences + ); + expect(attributeService.injectReferences).toHaveBeenCalled(); + // note: in this case the references are swapped + expect(runtimeState.attributes.references).toEqual(mockedReferences); + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/react_embeddable/helper.ts b/x-pack/plugins/lens/public/react_embeddable/helper.ts new file mode 100644 index 000000000000..3ee63d907068 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/helper.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + apiHasParentApi, + apiPublishesViewMode, + getInheritedViewMode, + ViewMode, + type PublishingSubject, + apiHasExecutionContext, +} from '@kbn/presentation-publishing'; +import { isObject } from 'lodash'; +import { BehaviorSubject } from 'rxjs'; +import fastIsEqual from 'fast-deep-equal'; +import { isOfAggregateQueryType } from '@kbn/es-query'; +import { RenderMode } from '@kbn/expressions-plugin/common'; +import { SavedObjectReference } from '@kbn/core/types'; +import { LensRuntimeState, LensSerializedState } from './types'; +import type { LensAttributesService } from '../lens_attribute_service'; + +export function createEmptyLensState( + visualizationType: null | string = null, + title?: LensSerializedState['title'], + description?: LensSerializedState['description'], + query?: LensSerializedState['query'], + filters?: LensSerializedState['filters'] +) { + const isTextBased = query && isOfAggregateQueryType(query); + return { + attributes: { + title: title ?? '', + description: description ?? '', + visualizationType, + references: [], + state: { + query: query || { query: '', language: 'kuery' }, + filters: filters || [], + internalReferences: [], + datasourceStates: { ...(isTextBased ? { text_based: {} } : { form_based: {} }) }, + visualization: {}, + }, + }, + }; +} + +// Shared logic to ensure the attributes are correctly loaded +// Make sure to inject references from the container down to the runtime state +// this ensure migrations/copy to spaces works correctly +export async function deserializeState( + attributeService: LensAttributesService, + rawState: LensSerializedState, + references?: SavedObjectReference[] +) { + if (rawState.savedObjectId) { + try { + const { attributes, managed, sharingSavedObjectProps } = + await attributeService.loadFromLibrary(rawState.savedObjectId); + return { ...rawState, attributes, managed, sharingSavedObjectProps }; + } catch (e) { + // return an empty Lens document if no saved object is found + return { ...rawState, attributes: createEmptyLensState().attributes }; + } + } + // Inject applied only to by-value SOs + return attributeService.injectReferences( + ('attributes' in rawState ? rawState : { attributes: rawState }) as LensRuntimeState, + references?.length ? references : undefined + ); +} + +export function emptySerializer() { + return {}; +} + +export type ComparatorType<T extends unknown> = [ + BehaviorSubject<T>, + (newValue: T) => void, + (a: T, b: T) => boolean +]; + +export function makeComparator<T extends unknown>( + observable: BehaviorSubject<T> +): ComparatorType<T> { + return [observable, (newValue: T) => observable.next(newValue), fastIsEqual]; +} + +/** + * Helper function to either extract an observable from an API or create a new one + * with a default value to start with. + * Note that extracting from the API will make subscription emit if the value changes upstream + * as it keeps the original reference without cloning. + * @returns the observable and a comparator to use for detecting "unsaved changes" on it + */ +export function buildObservableVariable<T extends unknown>( + variable: T | PublishingSubject<T> +): [BehaviorSubject<T>, ComparatorType<T>] { + if (variable instanceof BehaviorSubject) { + return [variable, makeComparator(variable)]; + } + const variable$ = new BehaviorSubject<T>(variable as T); + return [variable$, makeComparator(variable$)]; +} + +export function isTextBasedLanguage(state: LensRuntimeState) { + return isOfAggregateQueryType(state.attributes?.state.query); +} + +export function getViewMode(api: unknown) { + return apiPublishesViewMode(api) ? getInheritedViewMode(api) : undefined; +} + +export function getRenderMode(api: unknown): RenderMode { + const mode = getViewMode(api) ?? 'view'; + return mode === 'print' ? 'view' : mode; +} + +function apiHasExecutionContextFunction( + api: unknown +): api is { getAppContext: () => { currentAppId: string } } { + return isObject(api) && 'getAppContext' in api && typeof api.getAppContext === 'function'; +} + +export function getParentContext(parentApi: unknown) { + if (apiHasExecutionContext(parentApi)) { + return parentApi.executionContext; + } + if (apiHasExecutionContextFunction(parentApi)) { + return { type: parentApi.getAppContext().currentAppId }; + } + return; +} + +export function extractInheritedViewModeObservable( + parentApi?: unknown +): PublishingSubject<ViewMode> { + if (apiPublishesViewMode(parentApi)) { + return parentApi.viewMode; + } + if (apiHasParentApi(parentApi)) { + return extractInheritedViewModeObservable(parentApi.parentApi); + } + return new BehaviorSubject<ViewMode>('view'); +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts new file mode 100644 index 000000000000..a4f84c329bd3 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.test.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { pick } from 'lodash'; +import faker from 'faker'; +import type { LensRuntimeState, VisualizationContext } from '../types'; +import { initializeActionApi } from './initialize_actions'; +import { + getLensApiMock, + makeEmbeddableServices, + getLensRuntimeStateMock, + getVisualizationContextHelperMock, + createUnifiedSearchApi, +} from '../mocks'; +import { createEmptyLensState } from '../helper'; +const DATAVIEW_ID = 'myDataView'; + +jest.mock('../../app_plugin/show_underlying_data', () => { + return { + ...jest.requireActual('../../app_plugin/show_underlying_data'), + getLayerMetaInfo: jest.fn(() => ({ + meta: { + id: DATAVIEW_ID, + columns: ['a', 'b'], + filters: { disabled: [], enabled: [] }, + }, + error: undefined, + isVisible: true, + })), + }; +}); + +function setupActionsApi( + stateOverrides?: Partial<LensRuntimeState>, + contextOverrides?: Omit<VisualizationContext, 'doc'> +) { + const services = makeEmbeddableServices(undefined, undefined, { + visOverrides: { id: 'lnsXY' }, + dataOverrides: { id: 'form_based' }, + }); + const uuid = faker.random.uuid(); + const runtimeState = getLensRuntimeStateMock(stateOverrides); + const apiMock = getLensApiMock(); + + const { api } = initializeActionApi( + uuid, + runtimeState, + () => runtimeState, + createUnifiedSearchApi(), + pick(apiMock, ['timeRange$']), + pick(apiMock, ['panelTitle']), + getVisualizationContextHelperMock(stateOverrides?.attributes, contextOverrides), + { + ...services, + data: { + ...services.data, + nowProvider: { ...services.data.nowProvider, get: jest.fn(() => new Date()) }, + }, + } + ); + return api; +} + +describe('Dashboard actions', () => { + describe('Drilldowns', () => { + it('should expose drilldowns for DSL based visualization', async () => { + const api = setupActionsApi(); + expect(api.enhancements).toBeDefined(); + }); + + it('should not expose drilldowns for ES|QL chart types', async () => { + const api = setupActionsApi( + createEmptyLensState('lnsXY', faker.lorem.words(), faker.lorem.text(), { + esql: 'FROM index', + }) + ); + expect(api.enhancements).toBeUndefined(); + }); + }); + + describe('Explore in Discover', () => { + // make it pass the basic check on viewUnderlyingData + const visualizationContextMockOverrides = { + mergedSearchContext: {}, + indexPatterns: { + [DATAVIEW_ID]: { + id: DATAVIEW_ID, + title: 'idx1', + timeFieldName: 'timestamp', + hasRestrictions: false, + fields: [ + { + name: 'timestamp', + displayName: 'timestampLabel', + type: 'date', + aggregatable: true, + searchable: true, + }, + ], + getFieldByName: jest.fn(), + isPersisted: true, + spec: {}, + }, + }, + indexPatternRefs: [], + activeVisualizationState: {}, + activeDatasourceState: {}, + activeData: {}, + }; + it('should expose the "explore in discover" capability for DSL based visualization when compatible', async () => { + const api = setupActionsApi(undefined, visualizationContextMockOverrides); + api.loadViewUnderlyingData(); + expect(api.canViewUnderlyingData$.getValue()).toBe(true); + }); + + it('should expose the "explore in discover" capability for ES|QL chart types', async () => { + const api = setupActionsApi( + createEmptyLensState('lnsXY', faker.lorem.words(), faker.lorem.text(), { + esql: 'FROM index', + }), + visualizationContextMockOverrides + ); + api.loadViewUnderlyingData(); + expect(api.canViewUnderlyingData$.getValue()).toBe(true); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.ts new file mode 100644 index 000000000000..65fd13c8fca5 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_actions.ts @@ -0,0 +1,276 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Capabilities } from '@kbn/core-capabilities-common'; +import { getEsQueryConfig } from '@kbn/data-plugin/public'; +import { + AggregateQuery, + EsQueryConfig, + Filter, + Query, + TimeRange, + isOfQueryType, +} from '@kbn/es-query'; +import { + PublishingSubject, + StateComparators, + apiPublishesUnifiedSearch, + getUnchangingComparator, +} from '@kbn/presentation-publishing'; +import { HasDynamicActions } from '@kbn/embeddable-enhanced-plugin/public'; +import { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin'; +import { partition } from 'lodash'; +import { Visualization } from '../..'; +import { combineQueryAndFilters, getLayerMetaInfo } from '../../app_plugin/show_underlying_data'; +import { TableInspectorAdapter } from '../../editor_frame_service/types'; + +import { Datasource, IndexPatternMap } from '../../types'; +import { getMergedSearchContext } from '../expressions/merged_search_context'; +import { buildObservableVariable, isTextBasedLanguage } from '../helper'; +import type { + GetStateType, + LensEmbeddableStartServices, + LensRuntimeState, + ViewInDiscoverCallbacks, + ViewUnderlyingDataArgs, + VisualizationContextHelper, +} from '../types'; +import { getActiveDatasourceIdFromDoc, getActiveVisualizationIdFromDoc } from '../../utils'; + +function getViewUnderlyingDataArgs({ + activeDatasource, + activeDatasourceState, + activeVisualization, + activeVisualizationState, + activeData, + dataViews, + capabilities, + query, + filters, + timeRange, + esQueryConfig, +}: { + activeDatasource: Datasource; + activeDatasourceState: unknown; + activeVisualization: Visualization; + activeVisualizationState: unknown; + activeData: TableInspectorAdapter | undefined; + dataViews: IndexPatternMap; + capabilities: { + canSaveVisualizations: boolean; + canOpenVisualizations: boolean; + canSaveDashboards: boolean; + navLinks: Capabilities['navLinks']; + discover: Capabilities['discover']; + }; + query: Array<Query | AggregateQuery>; + filters: Filter[]; + timeRange: TimeRange; + esQueryConfig: EsQueryConfig; +}) { + const { error, meta } = getLayerMetaInfo( + activeDatasource, + activeDatasourceState, + activeVisualization, + activeVisualizationState, + activeData, + dataViews, + timeRange, + capabilities + ); + + if (error || !meta) { + return; + } + const luceneOrKuery: Query[] = []; + const aggregateQueries: AggregateQuery[] = []; + + if (Array.isArray(query)) { + const [kqlOrLuceneQueries, esqlQueries] = partition(query, isOfQueryType); + if (kqlOrLuceneQueries.length) { + luceneOrKuery.push(...kqlOrLuceneQueries); + } + if (esqlQueries.length) { + aggregateQueries.push(...esqlQueries); + } + } + + const { filters: newFilters, query: newQuery } = combineQueryAndFilters( + luceneOrKuery.length > 0 ? luceneOrKuery : aggregateQueries[0], + filters, + meta, + Object.values(dataViews), + esQueryConfig + ); + + const dataViewSpec = dataViews[meta.id]!.spec; + + return { + dataViewSpec, + timeRange, + filters: newFilters, + query: aggregateQueries.length > 0 ? aggregateQueries[0] : newQuery, + columns: meta.columns, + }; +} + +function loadViewUnderlyingDataArgs( + state: LensRuntimeState, + { getVisualizationContext }: VisualizationContextHelper, + searchContextApi: { timeRange$: PublishingSubject<TimeRange | undefined> }, + parentApi: unknown, + { + capabilities, + uiSettings, + injectFilterReferences, + data, + datasourceMap, + visualizationMap, + }: LensEmbeddableStartServices +) { + const { doc, activeData, activeDatasourceState, activeVisualizationState, indexPatterns } = + getVisualizationContext(); + const activeVisualizationId = getActiveVisualizationIdFromDoc(doc); + const activeDatasourceId = getActiveDatasourceIdFromDoc(doc); + const activeVisualization = activeVisualizationId + ? visualizationMap[activeVisualizationId] + : undefined; + const activeDatasource = activeDatasourceId ? datasourceMap[activeDatasourceId] : undefined; + if ( + !doc || + !activeData || + !activeDatasource || + !activeDatasourceState || + !activeVisualization || + !activeVisualizationState + ) { + return; + } + + const { filters$, query$, timeRange$ } = apiPublishesUnifiedSearch(parentApi) + ? parentApi + : { filters$: undefined, query$: undefined, timeRange$: undefined }; + + const mergedSearchContext = getMergedSearchContext( + state, + { + filters: filters$?.getValue(), + query: query$?.getValue(), + timeRange: timeRange$?.getValue(), + }, + searchContextApi.timeRange$, + parentApi, + { + data, + injectFilterReferences, + } + ); + + if (!mergedSearchContext.timeRange) { + return; + } + + const viewUnderlyingDataArgs = getViewUnderlyingDataArgs({ + activeDatasource, + activeDatasourceState, + activeVisualization, + activeVisualizationState, + activeData, + capabilities: { + canSaveDashboards: Boolean(capabilities.dashboard?.showWriteControls), + canSaveVisualizations: Boolean(capabilities.visualize.save), + canOpenVisualizations: Boolean(capabilities.visualize.show), + navLinks: capabilities.navLinks, + discover: capabilities.discover, + }, + query: mergedSearchContext.query, + filters: mergedSearchContext.filters || [], + timeRange: mergedSearchContext.timeRange, + esQueryConfig: getEsQueryConfig(uiSettings), + dataViews: indexPatterns, + }); + + return viewUnderlyingDataArgs; +} + +function createViewUnderlyingDataApis( + getState: GetStateType, + visualizationContextHelper: VisualizationContextHelper, + searchContextApi: { timeRange$: PublishingSubject<TimeRange | undefined> }, + parentApi: unknown, + services: LensEmbeddableStartServices +): ViewInDiscoverCallbacks { + let viewUnderlyingDataArgs: undefined | ViewUnderlyingDataArgs; + + const [canViewUnderlyingData$] = buildObservableVariable<boolean>(false); + + return { + canViewUnderlyingData$, + loadViewUnderlyingData: () => { + viewUnderlyingDataArgs = loadViewUnderlyingDataArgs( + getState(), + visualizationContextHelper, + searchContextApi, + parentApi, + services + ); + canViewUnderlyingData$.next(viewUnderlyingDataArgs != null); + }, + getViewUnderlyingDataArgs: () => { + return viewUnderlyingDataArgs; + }, + }; +} + +/** + * Initialize APIs used for actions on Lens panels + * This includes drilldowns, explore data, and more + */ +export function initializeActionApi( + uuid: string, + initialState: LensRuntimeState, + getLatestState: GetStateType, + parentApi: unknown, + searchContextApi: { timeRange$: PublishingSubject<TimeRange | undefined> }, + titleApi: { panelTitle: PublishingSubject<string | undefined> }, + visualizationContextHelper: VisualizationContextHelper, + services: LensEmbeddableStartServices +): { + api: ViewInDiscoverCallbacks & HasDynamicActions; + comparators: StateComparators<DynamicActionsSerializedState>; + serialize: () => {}; + cleanup: () => void; +} { + const dynamicActionsApi = services.embeddableEnhanced?.initializeReactEmbeddableDynamicActions( + uuid, + () => titleApi.panelTitle.getValue(), + initialState + ); + const maybeStopDynamicActions = dynamicActionsApi?.startDynamicActions(); + + return { + api: { + ...(isTextBasedLanguage(initialState) ? {} : dynamicActionsApi?.dynamicActionsApi ?? {}), + ...createViewUnderlyingDataApis( + getLatestState, + visualizationContextHelper, + searchContextApi, + parentApi, + services + ), + }, + comparators: { + ...(dynamicActionsApi?.dynamicActionsComparator ?? { + enhancements: getUnchangingComparator(), + }), + }, + serialize: () => dynamicActionsApi?.serializeDynamicActions() ?? {}, + cleanup: () => { + maybeStopDynamicActions?.stopDynamicActions(); + }, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts new file mode 100644 index 000000000000..2a0c469b3bbf --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_service.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LensRuntimeState } from '../types'; +import { getLensRuntimeStateMock, getLensInternalApiMock, makeEmbeddableServices } from '../mocks'; +import { initializeStateManagement } from './initialize_state_management'; +import { initializeDashboardServices } from './initialize_dashboard_services'; +import faker from 'faker'; +import { createEmptyLensState } from '../helper'; + +function setupDashboardServicesApi(runtimeOverrides?: Partial<LensRuntimeState>) { + const services = makeEmbeddableServices(); + const internalApiMock = getLensInternalApiMock(); + const runtimeState = getLensRuntimeStateMock(runtimeOverrides); + const stateManagementConfig = initializeStateManagement(runtimeState, internalApiMock); + const { api } = initializeDashboardServices( + runtimeState, + () => runtimeState, + internalApiMock, + stateManagementConfig, + {}, + services + ); + return api; +} + +describe('Transformation API', () => { + it("should not save to library if there's already a saveObjectId", async () => { + const api = setupDashboardServicesApi({ savedObjectId: faker.random.uuid() }); + expect(await api.canLinkToLibrary()).toBe(false); + }); + + it("should save to library if there's no saveObjectId declared", async () => { + const api = setupDashboardServicesApi(); + expect(await api.canLinkToLibrary()).toBe(true); + }); + + it('should not save to library for ES|QL chart types', async () => { + // setup a state with an ES|QL query + const api = setupDashboardServicesApi( + createEmptyLensState('lnsXY', faker.lorem.words(), faker.lorem.text(), { + esql: 'FROM index', + }) + ); + expect(await api.canLinkToLibrary()).toBe(false); + }); +}); diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts new file mode 100644 index 000000000000..67a5d3a89a1c --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_dashboard_services.ts @@ -0,0 +1,190 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { noop } from 'lodash'; +import { + HasInPlaceLibraryTransforms, + HasLibraryTransforms, + PublishesWritablePanelTitle, + PublishesWritablePanelDescription, + SerializedTitles, + StateComparators, + getUnchangingComparator, + initializeTitles, +} from '@kbn/presentation-publishing'; +import { apiIsPresentationContainer, apiPublishesSettings } from '@kbn/presentation-containers'; +import { buildObservableVariable, isTextBasedLanguage } from '../helper'; +import type { + LensComponentProps, + LensPanelProps, + LensRuntimeState, + LensEmbeddableStartServices, + LensOverrides, + LensSharedProps, + IntegrationCallbacks, + LensInternalApi, + LensApi, +} from '../types'; +import { apiHasLensComponentProps } from '../type_guards'; +import { StateManagementConfig } from './initialize_state_management'; + +// Convenience type for the serialized props of this initializer +type SerializedProps = SerializedTitles & LensPanelProps & LensOverrides & LensSharedProps; + +export interface DashboardServicesConfig { + api: PublishesWritablePanelTitle & + PublishesWritablePanelDescription & + HasInPlaceLibraryTransforms & + HasLibraryTransforms<LensRuntimeState> & + Pick<LensApi, 'parentApi'> & + Pick<IntegrationCallbacks, 'updateOverrides' | 'getTriggerCompatibleActions'>; + serialize: () => SerializedProps; + comparators: StateComparators< + SerializedProps & Pick<LensApi, 'parentApi'> & { isNewPanel?: boolean } + >; + cleanup: () => void; +} + +/** + * Everything about panel and library services + */ +export function initializeDashboardServices( + initialState: LensRuntimeState, + getLatestState: () => LensRuntimeState, + internalApi: LensInternalApi, + stateConfig: StateManagementConfig, + parentApi: unknown, + { attributeService, uiActions }: LensEmbeddableStartServices +): DashboardServicesConfig { + const { titlesApi, serializeTitles, titleComparators } = initializeTitles(initialState); + // For some legacy reason the title and description default value is picked differently + // ( based on existing FTR tests ). + const [defaultPanelTitle$] = buildObservableVariable<string | undefined>( + initialState.title || internalApi.attributes$.getValue().title + ); + const [defaultPanelDescription$] = buildObservableVariable<string | undefined>( + initialState.savedObjectId + ? internalApi.attributes$.getValue().description || initialState.description + : initialState.description + ); + // The observable references here are the same to the internalApi, + // the buildObservableVariable re-uses the same observable when detected but it builds the right comparator + const [overrides$, overridesComparator] = buildObservableVariable<LensOverrides['overrides']>( + internalApi.overrides$ + ); + const [disableTriggers$, disabledTriggersComparator] = buildObservableVariable< + boolean | undefined + >(internalApi.disableTriggers$); + + return { + api: { + parentApi: apiIsPresentationContainer(parentApi) ? parentApi : undefined, + defaultPanelTitle: defaultPanelTitle$, + defaultPanelDescription: defaultPanelDescription$, + ...titlesApi, + libraryId$: stateConfig.api.savedObjectId, + updateOverrides: internalApi.updateOverrides, + getTriggerCompatibleActions: uiActions.getTriggerCompatibleActions, + // The functions below brings the HasInPlaceLibraryTransforms compliance (new interface) + saveToLibrary: async (title: string) => { + const { attributes } = getLatestState(); + const savedObjectId = await attributeService.saveToLibrary( + { + ...attributes, + title, + }, + attributes.references + ); + // keep in sync the state + stateConfig.api.updateSavedObjectId(savedObjectId); + return savedObjectId; + }, + checkForDuplicateTitle: async ( + newTitle: string, + isTitleDuplicateConfirmed: boolean, + onTitleDuplicate: () => void + ) => { + await attributeService.checkForDuplicateTitle({ + newTitle, + isTitleDuplicateConfirmed, + onTitleDuplicate, + newCopyOnSave: false, + newDescription: '', + displayName: '', + lastSavedTitle: '', + copyOnSave: false, + }); + }, + canLinkToLibrary: async () => + !getLatestState().savedObjectId && !isTextBasedLanguage(getLatestState()), + canUnlinkFromLibrary: async () => Boolean(getLatestState().savedObjectId), + unlinkFromLibrary: () => { + // broadcast the change to the main state serializer + stateConfig.api.updateSavedObjectId(undefined); + + if ((titlesApi.panelTitle.getValue() ?? '').length === 0) { + titlesApi.setPanelTitle(defaultPanelTitle$.getValue()); + } + if ((titlesApi.panelDescription.getValue() ?? '').length === 0) { + titlesApi.setPanelDescription(defaultPanelDescription$.getValue()); + } + defaultPanelTitle$.next(undefined); + defaultPanelDescription$.next(undefined); + }, + getByValueRuntimeSnapshot: (): Omit<LensRuntimeState, 'savedObjectId'> => { + const { savedObjectId, ...rest } = getLatestState(); + return rest; + }, + // The functions below brings the HasLibraryTransforms compliance (old interface) + getByReferenceState: () => getLatestState(), + getByValueState: (): Omit<LensRuntimeState, 'savedObjectId'> => { + const { savedObjectId, ...rest } = getLatestState(); + return rest; + }, + }, + serialize: () => { + const { style, className } = apiHasLensComponentProps(parentApi) + ? parentApi + : ({} as LensComponentProps); + const settings = apiPublishesSettings(parentApi) + ? { + syncColors: parentApi.settings.syncColors$.getValue(), + syncCursor: parentApi.settings.syncCursor$.getValue(), + syncTooltips: parentApi.settings.syncTooltips$.getValue(), + } + : {}; + return { + ...serializeTitles(), + style, + className, + ...settings, + palette: initialState.palette, + overrides: overrides$.getValue(), + disableTriggers: disableTriggers$.getValue(), + }; + }, + comparators: { + ...titleComparators, + id: getUnchangingComparator<SerializedTitles & LensPanelProps, 'id'>(), + palette: getUnchangingComparator<SerializedTitles & LensPanelProps, 'palette'>(), + renderMode: getUnchangingComparator<SerializedTitles & LensPanelProps, 'renderMode'>(), + syncColors: getUnchangingComparator<SerializedTitles & LensPanelProps, 'syncColors'>(), + syncCursor: getUnchangingComparator<SerializedTitles & LensPanelProps, 'syncCursor'>(), + syncTooltips: getUnchangingComparator<SerializedTitles & LensPanelProps, 'syncTooltips'>(), + executionContext: getUnchangingComparator<LensSharedProps, 'executionContext'>(), + noPadding: getUnchangingComparator<LensSharedProps, 'noPadding'>(), + viewMode: getUnchangingComparator<LensSharedProps, 'viewMode'>(), + style: getUnchangingComparator<LensSharedProps, 'style'>(), + className: getUnchangingComparator<LensSharedProps, 'className'>(), + overrides: overridesComparator, + disableTriggers: disabledTriggersComparator, + isNewPanel: getUnchangingComparator<{ isNewPanel?: boolean }, 'isNewPanel'>(), + parentApi: getUnchangingComparator<Pick<LensApi, 'parentApi'>, 'parentApi'>(), + }, + cleanup: noop, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_edit.tsx b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_edit.tsx new file mode 100644 index 000000000000..81372dad339f --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_edit.tsx @@ -0,0 +1,237 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + HasEditCapabilities, + HasSupportedTriggers, + PublishesDisabledActionIds, + PublishesViewMode, + ViewMode, + apiHasAppContext, + apiPublishesDisabledActionIds, +} from '@kbn/presentation-publishing'; +import { ENABLE_ESQL } from '@kbn/esql-utils'; +import { noop } from 'lodash'; +import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; +import { tracksOverlays } from '@kbn/presentation-containers'; +import { i18n } from '@kbn/i18n'; +import { APP_ID, getEditPath } from '../../../common/constants'; +import { + GetStateType, + LensEmbeddableStartServices, + LensInspectorAdapters, + LensInternalApi, + LensRuntimeState, +} from '../types'; +import { + buildObservableVariable, + emptySerializer, + extractInheritedViewModeObservable, +} from '../helper'; +import { prepareInlineEditPanel } from '../inline_editing/setup_inline_editing'; +import { setupPanelManagement } from '../inline_editing/panel_management'; +import { mountInlineEditPanel } from '../inline_editing/mount'; +import { StateManagementConfig } from './initialize_state_management'; +import { apiPublishesInlineEditingCapabilities } from '../type_guards'; + +function getSupportedTriggers( + getState: GetStateType, + visualizationMap: LensEmbeddableStartServices['visualizationMap'] +) { + return () => { + const currentState = getState(); + if (currentState.attributes?.visualizationType) { + return visualizationMap[currentState.attributes.visualizationType]?.triggers || []; + } + return []; + }; +} + +/** + * Initialize the edit API for the embeddable + **/ +export function initializeEditApi( + uuid: string, + initialState: LensRuntimeState, + getState: GetStateType, + internalApi: LensInternalApi, + stateApi: StateManagementConfig['api'], + inspectorApi: LensInspectorAdapters, + isTextBasedLanguage: (currentState: LensRuntimeState) => boolean, + startDependencies: LensEmbeddableStartServices, + parentApi?: unknown +): { + api: HasSupportedTriggers & + PublishesDisabledActionIds & + HasEditCapabilities & + PublishesViewMode & { uuid: string }; + comparators: {}; + serialize: () => {}; + cleanup: () => void; +} { + const supportedTriggers = getSupportedTriggers(getState, startDependencies.visualizationMap); + + const isESQLModeEnabled = () => uiSettings.get(ENABLE_ESQL); + + const [viewMode$] = buildObservableVariable<ViewMode>( + extractInheritedViewModeObservable(parentApi) + ); + + const { disabledActionIds, setDisabledActionIds } = apiPublishesDisabledActionIds(parentApi) + ? parentApi + : { disabledActionIds: undefined, setDisabledActionIds: noop }; + const [disabledActionIds$, disabledActionIdsComparator] = buildObservableVariable< + string[] | undefined + >(disabledActionIds); + + if (isTextBasedLanguage(initialState)) { + // do not expose the drilldown action for ES|QL + disabledActionIds$.next(disabledActionIds$.getValue()?.concat(['OPEN_FLYOUT_ADD_DRILLDOWN'])); + } + + /** + * Inline editing section + */ + const navigateToLensEditor = + (stateTransfer: EmbeddableStateTransfer, skipAppLeave?: boolean) => async () => { + if (!parentApi || !apiHasAppContext(parentApi)) { + return; + } + const parentApiContext = parentApi.getAppContext(); + const currentState = getState(); + await stateTransfer.navigateToEditor(APP_ID, { + path: getEditPath(currentState.savedObjectId), + state: { + embeddableId: uuid, + valueInput: currentState, + originatingApp: parentApiContext.currentAppId ?? 'dashboards', + originatingPath: parentApiContext.getCurrentPath?.(), + searchSessionId: currentState.searchSessionId, + }, + skipAppLeave, + }); + }; + + const panelManagementApi = setupPanelManagement(uuid, parentApi, { + isNewlyCreated$: internalApi.isNewlyCreated$, + setAsCreated: internalApi.setAsCreated, + }); + + const updateState = (newState: Pick<LensRuntimeState, 'attributes' | 'savedObjectId'>) => { + stateApi.updateAttributes(newState.attributes); + stateApi.updateSavedObjectId(newState.savedObjectId); + }; + + const openInlineEditor = prepareInlineEditPanel( + initialState, + getState, + updateState, + internalApi, + panelManagementApi, + inspectorApi, + startDependencies, + navigateToLensEditor, + uuid + ); + + /** + * The rest of the edit stuff + */ + const { uiSettings, capabilities, data } = startDependencies; + + const canEdit = () => { + if (viewMode$.getValue() !== 'edit') { + return false; + } + // check if it's in ES|QL mode + if (isTextBasedLanguage(getState()) && !isESQLModeEnabled()) { + return false; + } + return ( + Boolean(capabilities.visualize.save) || + (!getState().savedObjectId && + Boolean(capabilities.dashboard?.showWriteControls) && + Boolean(capabilities.visualize.show)) + ); + }; + + // this will force the embeddable to toggle the inline editing feature + const canEditInline = apiPublishesInlineEditingCapabilities(parentApi) + ? parentApi.canEditInline + : true; + + return { + comparators: { disabledActionIds: disabledActionIdsComparator }, + serialize: emptySerializer, + cleanup: noop, + api: { + uuid, + viewMode: viewMode$, + getTypeDisplayName: () => + i18n.translate('xpack.lens.embeddableDisplayName', { + defaultMessage: 'Lens', + }), + supportedTriggers, + disabledActionIds: disabledActionIds$, + setDisabledActionIds, + + /** + * This is the key method to enable the new Editing capabilities API + * Lens will leverage the netural nature of this function to build the inline editing experience + */ + onEdit: async () => { + if (!parentApi || !apiHasAppContext(parentApi)) { + return; + } + // just navigate directly to the editor + if (!canEditInline) { + const navigateFn = navigateToLensEditor( + new EmbeddableStateTransfer( + startDependencies.coreStart.application.navigateToApp, + startDependencies.coreStart.application.currentAppId$ + ), + true + ); + return navigateFn(); + } + + // save the initial state in case it needs to revert later on + const firstState = getState(); + + const rootEmbeddable = parentApi; + const overlayTracker = tracksOverlays(rootEmbeddable) ? rootEmbeddable : undefined; + const ConfigPanel = await openInlineEditor({ + onApply: (attributes: LensRuntimeState['attributes']) => + updateState({ ...getState(), attributes }), + // restore the first state found when the panel opened + onCancel: () => updateState({ ...firstState }), + }); + if (ConfigPanel) { + mountInlineEditPanel(ConfigPanel, startDependencies.coreStart, overlayTracker, uuid); + } + }, + /** + * Check everything here: user/app permissions and the current inline editing state + */ + isEditingEnabled: () => { + return apiHasAppContext(parentApi) && canEdit() && panelManagementApi.isEditingEnabled(); + }, + getEditHref: async () => { + if (!parentApi || !apiHasAppContext(parentApi)) { + return; + } + const currentState = getState(); + return getEditPath( + currentState.savedObjectId, + currentState.timeRange, + currentState.filters, + data.query.timefilter.timefilter.getRefreshInterval() + ); + }, + }, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_inspector.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_inspector.ts new file mode 100644 index 000000000000..733a1d4eac46 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_inspector.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { noop } from 'lodash'; +import { BehaviorSubject } from 'rxjs'; +import type { Adapters } from '@kbn/inspector-plugin/public'; +import { getLensInspectorService } from '../../lens_inspector_service'; +import { emptySerializer } from '../helper'; +import type { LensEmbeddableStartServices, LensInspectorAdapters } from '../types'; + +export function initializeInspector(services: LensEmbeddableStartServices): { + api: LensInspectorAdapters; + comparators: {}; + serialize: () => {}; + cleanup: () => void; +} { + const inspectorApi = getLensInspectorService(services.inspector); + + return { + api: { + ...inspectorApi, + adapters$: new BehaviorSubject<Adapters>(inspectorApi.getInspectorAdapters()), + }, + comparators: {}, + serialize: emptySerializer, + cleanup: noop, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_integrations.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_integrations.ts new file mode 100644 index 000000000000..c3501bdfcafb --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_integrations.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + getAggregateQueryMode, + getLanguageDisplayName, + isOfAggregateQueryType, +} from '@kbn/es-query'; +import { noop } from 'lodash'; +import type { HasSerializableState } from '@kbn/presentation-containers'; +import { emptySerializer, isTextBasedLanguage } from '../helper'; +import type { GetStateType, LensEmbeddableStartServices } from '../types'; +import type { IntegrationCallbacks } from '../types'; + +export function initializeIntegrations( + getLatestState: GetStateType, + { attributeService }: LensEmbeddableStartServices +): { + api: Omit< + IntegrationCallbacks, + | 'updateState' + | 'updateAttributes' + | 'updateDataViews' + | 'updateSavedObjectId' + | 'updateOverrides' + | 'updateDataLoading' + | 'getTriggerCompatibleActions' + > & + HasSerializableState; + cleanup: () => void; + serialize: () => {}; + comparators: {}; +} { + return { + api: { + serializeState: () => { + const currentState = getLatestState(); + return attributeService.extractReferences(currentState); + }, + // TODO: workout why we have this duplicated + getFullAttributes: () => getLatestState().attributes, + getSavedVis: () => getLatestState().attributes, + isTextBasedLanguage: () => isTextBasedLanguage(getLatestState()), + getTextBasedLanguage: () => { + const query = getLatestState().attributes?.state.query; + if (!query || !isOfAggregateQueryType(query)) { + return; + } + const language = getAggregateQueryMode(query); + return getLanguageDisplayName(language).toUpperCase(); + }, + }, + comparators: {}, + serialize: emptySerializer, + cleanup: noop, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts new file mode 100644 index 000000000000..e366c24a6c0e --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_internal_api.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BehaviorSubject } from 'rxjs'; +import { initializeTitles } from '@kbn/presentation-publishing'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import { buildObservableVariable, createEmptyLensState } from '../helper'; +import type { + ExpressionWrapperProps, + LensEmbeddableStartServices, + LensInternalApi, + LensOverrides, + LensRuntimeState, +} from '../types'; +import { apiHasAbortController, apiHasLensComponentProps } from '../type_guards'; +import type { UserMessage } from '../../types'; + +export function initializeInternalApi( + initialState: LensRuntimeState, + parentApi: unknown, + { visualizationMap }: LensEmbeddableStartServices +): LensInternalApi { + const { titlesApi } = initializeTitles(initialState); + const [hasRenderCompleted$] = buildObservableVariable<boolean>(false); + const [expressionParams$] = buildObservableVariable<ExpressionWrapperProps | null>(null); + const expressionAbortController$ = new BehaviorSubject<AbortController | undefined>(undefined); + if (apiHasAbortController(parentApi)) { + expressionAbortController$.next(parentApi.abortController); + } + const [renderCount$] = buildObservableVariable<number>(0); + + const attributes$ = new BehaviorSubject<LensRuntimeState['attributes']>( + initialState.attributes || createEmptyLensState().attributes + ); + const overrides$ = new BehaviorSubject(initialState.overrides); + const disableTriggers$ = new BehaviorSubject(initialState.disableTriggers); + const dataLoading$ = new BehaviorSubject<boolean | undefined>(undefined); + + const dataViews$ = new BehaviorSubject<DataView[] | undefined>(undefined); + // This is an internal error state, not to be confused with the runtime error state thrown by the expression pipeline + // In both cases a blocking error can happen, but for Lens validation errors we want to have full control over the UI + // while for runtime errors the error will bubble up to the embeddable presentation layer + const validationMessages$ = new BehaviorSubject<UserMessage[]>([]); + // This other set of messages is for non-blocking messages that can be displayed in the UI + const messages$ = new BehaviorSubject<UserMessage[]>([]); + + // This should settle the thing once and for all + // the isNewPanel won't be serialized so it will be always false after the edit panel closes applying the changes + const isNewlyCreated$ = new BehaviorSubject<boolean>(initialState.isNewPanel || false); + + // No need to expose anything at public API right now, that would happen later on + // where each initializer will pick what it needs and publish it + return { + attributes$, + overrides$, + disableTriggers$, + dataLoading$, + hasRenderCompleted$, + expressionParams$, + expressionAbortController$, + renderCount$, + isNewlyCreated$, + dataViews: dataViews$, + dispatchError: () => { + hasRenderCompleted$.next(true); + renderCount$.next(renderCount$.getValue() + 1); + }, + dispatchRenderStart: () => hasRenderCompleted$.next(false), + dispatchRenderComplete: () => { + renderCount$.next(renderCount$.getValue() + 1); + hasRenderCompleted$.next(true); + }, + updateExpressionParams: (newParams: ExpressionWrapperProps | null) => + expressionParams$.next(newParams), + updateDataLoading: (newDataLoading: boolean | undefined) => dataLoading$.next(newDataLoading), + updateOverrides: (overrides: LensOverrides['overrides']) => overrides$.next(overrides), + updateAttributes: (attributes: LensRuntimeState['attributes']) => attributes$.next(attributes), + updateAbortController: (abortController: AbortController | undefined) => + expressionAbortController$.next(abortController), + updateDataViews: (dataViews: DataView[] | undefined) => dataViews$.next(dataViews), + messages$, + updateMessages: (newMessages: UserMessage[]) => messages$.next(newMessages), + validationMessages$, + updateValidationMessages: (newMessages: UserMessage[]) => validationMessages$.next(newMessages), + resetAllMessages: () => { + messages$.next([]); + validationMessages$.next([]); + }, + setAsCreated: () => isNewlyCreated$.next(false), + getDisplayOptions: () => { + const latestAttributes = attributes$.getValue(); + if (!latestAttributes.visualizationType) { + return {}; + } + + let displayOptions = + visualizationMap[latestAttributes.visualizationType]?.getDisplayOptions?.() ?? {}; + + if (apiHasLensComponentProps(parentApi) && parentApi.noPadding != null) { + displayOptions = { + ...displayOptions, + noPadding: parentApi.noPadding, + }; + } + + if (displayOptions.noPanelTitle == null && titlesApi.hidePanelTitle?.getValue()) { + displayOptions = { + ...displayOptions, + noPanelTitle: true, + }; + } + + return displayOptions; + }, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_search_context.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_search_context.ts new file mode 100644 index 000000000000..1a608de11e23 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_search_context.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Filter, Query, AggregateQuery } from '@kbn/es-query'; +import { + PublishesUnifiedSearch, + StateComparators, + getUnchangingComparator, + initializeTimeRange, +} from '@kbn/presentation-publishing'; +import { noop } from 'lodash'; +import { + PublishesSearchSession, + apiPublishesSearchSession, +} from '@kbn/presentation-publishing/interfaces/fetch/publishes_search_session'; +import { buildObservableVariable } from '../helper'; +import { LensInternalApi, LensRuntimeState, LensUnifiedSearchContext } from '../types'; + +export function initializeSearchContext( + initialState: LensRuntimeState, + internalApi: LensInternalApi, + parentApi: unknown +): { + api: PublishesUnifiedSearch & PublishesSearchSession; + comparators: StateComparators<LensUnifiedSearchContext>; + serialize: () => LensUnifiedSearchContext; + cleanup: () => void; +} { + const [searchSessionId$] = buildObservableVariable<string | undefined>( + apiPublishesSearchSession(parentApi) ? parentApi.searchSessionId$ : undefined + ); + + const attributes = internalApi.attributes$.getValue(); + + const [lastReloadRequestTime] = buildObservableVariable<number | undefined>(undefined); + + const [filters$] = buildObservableVariable<Filter[] | undefined>(attributes.state.filters); + + const [query$] = buildObservableVariable<Query | AggregateQuery | undefined>( + attributes.state.query + ); + + const [timeslice$] = buildObservableVariable<[number, number] | undefined>(undefined); + + const timeRange = initializeTimeRange(initialState); + return { + api: { + searchSessionId$, + filters$, + query$, + timeslice$, + isCompatibleWithUnifiedSearch: () => true, + ...timeRange.api, + }, + comparators: { + query: getUnchangingComparator<LensUnifiedSearchContext, 'query'>(), + filters: getUnchangingComparator<LensUnifiedSearchContext, 'filters'>(), + timeslice: getUnchangingComparator<LensUnifiedSearchContext, 'timeslice'>(), + searchSessionId: getUnchangingComparator<LensUnifiedSearchContext, 'searchSessionId'>(), + lastReloadRequestTime: getUnchangingComparator< + LensUnifiedSearchContext, + 'lastReloadRequestTime' + >(), + ...timeRange.comparators, + }, + cleanup: noop, + serialize: () => ({ + searchSessionId: searchSessionId$.getValue(), + filters: filters$.getValue(), + query: query$.getValue(), + timeslice: timeslice$.getValue(), + lastReloadRequestTime: lastReloadRequestTime.getValue(), + ...timeRange.serialize(), + }), + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts new file mode 100644 index 000000000000..1bf7853c0b26 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_state_management.ts @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + getUnchangingComparator, + type PublishesBlockingError, + type PublishesDataLoading, + type PublishesDataViews, + type PublishesSavedObjectId, + type StateComparators, + type PublishesRendered, +} from '@kbn/presentation-publishing'; +import { noop } from 'lodash'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import { BehaviorSubject } from 'rxjs'; +import type { IntegrationCallbacks, LensInternalApi, LensRuntimeState } from '../types'; +import { buildObservableVariable } from '../helper'; +import { SharingSavedObjectProps } from '../../types'; + +export interface StateManagementConfig { + api: Pick<IntegrationCallbacks, 'updateAttributes' | 'updateSavedObjectId'> & + PublishesSavedObjectId & + PublishesDataViews & + PublishesDataLoading & + PublishesRendered & + PublishesBlockingError; + serialize: () => Pick<LensRuntimeState, 'attributes' | 'savedObjectId'>; + comparators: StateComparators< + Pick<LensRuntimeState, 'attributes' | 'savedObjectId' | 'abortController'> & { + managed?: boolean | undefined; + sharingSavedObjectProps?: SharingSavedObjectProps | undefined; + } + >; + cleanup: () => void; +} + +/** + * Due to inline editing we need something advanced to handle the state + * management at the embeddable level, so here's the initializers for it + */ +export function initializeStateManagement( + initialState: LensRuntimeState, + internalApi: LensInternalApi +): StateManagementConfig { + const [attributes$, attributesComparator] = buildObservableVariable< + LensRuntimeState['attributes'] + >(internalApi.attributes$); + + const [savedObjectId$, savedObjectIdComparator] = buildObservableVariable< + LensRuntimeState['savedObjectId'] + >(initialState.savedObjectId); + + const [dataViews$] = buildObservableVariable<DataView[] | undefined>(internalApi.dataViews); + const [dataLoading$] = buildObservableVariable<boolean | undefined>(internalApi.dataLoading$); + const [rendered$] = buildObservableVariable<boolean>(internalApi.hasRenderCompleted$); + const [abortController$, abortControllerComparator] = buildObservableVariable< + AbortController | undefined + >(internalApi.expressionAbortController$); + + // This is the way to communicate to the embeddable panel to render a blocking error with the + // default panel error component - i.e. cannot find a Lens SO type of thing. + // For Lens specific errors, we use a Lens specific error component. + const [blockingError$] = buildObservableVariable<Error | undefined>(undefined); + return { + api: { + updateAttributes: internalApi.updateAttributes, + updateSavedObjectId: (newSavedObjectId: LensRuntimeState['savedObjectId']) => + savedObjectId$.next(newSavedObjectId), + savedObjectId: savedObjectId$, + dataViews: dataViews$, + dataLoading: dataLoading$, + blockingError: blockingError$, + rendered$, + }, + serialize: () => { + return { + attributes: attributes$.getValue(), + savedObjectId: savedObjectId$.getValue(), + abortController: abortController$.getValue(), + }; + }, + comparators: { + // need to force cast this to make it pass the type check + // @TODO: workout why this is needed + attributes: attributesComparator as [ + BehaviorSubject<LensRuntimeState['attributes']>, + (newValue: LensRuntimeState['attributes'] | undefined) => void, + ( + a: LensRuntimeState['attributes'] | undefined, + b: LensRuntimeState['attributes'] | undefined + ) => boolean + ], + savedObjectId: savedObjectIdComparator, + abortController: abortControllerComparator, + sharingSavedObjectProps: getUnchangingComparator(), + managed: getUnchangingComparator(), + }, + cleanup: noop, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_visualization_context.ts b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_visualization_context.ts new file mode 100644 index 000000000000..93d544013e71 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/initializers/initialize_visualization_context.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LensInternalApi, VisualizationContext, VisualizationContextHelper } from '../types'; + +export function initializeVisualizationContext( + internalApi: LensInternalApi +): VisualizationContextHelper { + // TODO: this will likely be merged together with the state$ observable + let visualizationContext: VisualizationContext = { + doc: internalApi.attributes$.getValue(), + mergedSearchContext: {}, + indexPatterns: {}, + indexPatternRefs: [], + activeVisualizationState: undefined, + activeDatasourceState: undefined, + activeData: undefined, + }; + return { + getVisualizationContext: () => visualizationContext, + updateVisualizationContext: (newVisualizationContext: Partial<VisualizationContext>) => { + visualizationContext = { + ...visualizationContext, + ...newVisualizationContext, + }; + }, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/inline_editing/mount.tsx b/x-pack/plugins/lens/public/react_embeddable/inline_editing/mount.tsx new file mode 100644 index 000000000000..566c5b27b654 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/inline_editing/mount.tsx @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreStart } from '@kbn/core/public'; +import { TracksOverlays } from '@kbn/presentation-containers'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +/** + * Shared logic to mount the inline config panel + * @param ConfigPanel + * @param coreStart + * @param overlayTracker + * @param uuid + * @param container + */ +export function mountInlineEditPanel( + ConfigPanel: JSX.Element, + coreStart: CoreStart, + overlayTracker: TracksOverlays | undefined, + uuid?: string, + container?: HTMLElement | null +) { + if (container) { + ReactDOM.render(ConfigPanel, container); + } else { + const handle = coreStart.overlays.openFlyout( + toMountPoint( + React.cloneElement(ConfigPanel, { + closeFlyout: () => { + overlayTracker?.clearOverlays(); + handle.close(); + }, + }), + coreStart + ), + { + className: 'lnsConfigPanel__overlay', + size: 's', + 'data-test-subj': 'customizeLens', + type: 'push', + paddingSize: 'm', + maxWidth: 800, + hideCloseButton: true, + isResizable: true, + onClose: (overlayRef) => { + overlayTracker?.clearOverlays(); + overlayRef.close(); + }, + outsideClickCloses: true, + } + ); + if (uuid) { + overlayTracker?.openOverlay(handle, { focusedPanelId: uuid }); + } + } +} diff --git a/x-pack/plugins/lens/public/react_embeddable/inline_editing/panel_management.tsx b/x-pack/plugins/lens/public/react_embeddable/inline_editing/panel_management.tsx new file mode 100644 index 000000000000..5753c8112d87 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/inline_editing/panel_management.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { apiIsPresentationContainer } from '@kbn/presentation-containers'; +import { BehaviorSubject } from 'rxjs'; +import { PublishingSubject } from '@kbn/presentation-publishing'; +import { LensRuntimeState } from '../types'; + +export interface PanelManagementApi { + isEditingEnabled: () => boolean; + isNewPanel: () => boolean; + onStopEditing: (isCancel: boolean, state: LensRuntimeState | undefined) => void; +} + +export function setupPanelManagement( + uuid: string, + parentApi: unknown, + { + isNewlyCreated$, + setAsCreated, + }: { + isNewlyCreated$: PublishingSubject<boolean>; + setAsCreated: () => void; + } +): PanelManagementApi { + const isEditing$ = new BehaviorSubject(false); + + return { + isEditingEnabled: () => true, + isNewPanel: () => isNewlyCreated$.getValue(), + onStopEditing: (isCancel: boolean = false, state: LensRuntimeState | undefined) => { + isEditing$.next(false); + if (isNewlyCreated$.getValue() && isCancel && !state) { + if (apiIsPresentationContainer(parentApi)) { + parentApi?.removePanel(uuid); + } + } + setAsCreated(); + }, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/inline_editing/setup_inline_editing.tsx b/x-pack/plugins/lens/public/react_embeddable/inline_editing/setup_inline_editing.tsx new file mode 100644 index 000000000000..e37e67113296 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/inline_editing/setup_inline_editing.tsx @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EmbeddableStateTransfer } from '@kbn/embeddable-plugin/public'; +import React from 'react'; +import { EditLensConfigurationProps } from '../../app_plugin/shared/edit_on_the_fly/get_edit_lens_configuration'; +import { EditConfigPanelProps } from '../../app_plugin/shared/edit_on_the_fly/types'; +import { getActiveDatasourceIdFromDoc } from '../../utils'; +import { isTextBasedLanguage } from '../helper'; +import { + GetStateType, + LensEmbeddableStartServices, + LensInspectorAdapters, + LensInternalApi, + LensRuntimeState, + TypedLensSerializedState, +} from '../types'; +import { PanelManagementApi } from './panel_management'; +import { getStateManagementForInlineEditing } from './state_management'; + +export function prepareInlineEditPanel( + initialState: LensRuntimeState, + getState: GetStateType, + updateState: (newState: Pick<LensRuntimeState, 'attributes' | 'savedObjectId'>) => void, + { dataLoading$, isNewlyCreated$ }: Pick<LensInternalApi, 'dataLoading$' | 'isNewlyCreated$'>, + panelManagementApi: PanelManagementApi, + inspectorApi: LensInspectorAdapters, + { + coreStart, + ...startDependencies + }: Omit< + LensEmbeddableStartServices, + | 'timefilter' + | 'coreHttp' + | 'capabilities' + | 'expressionRenderer' + | 'documentToExpression' + | 'injectFilterReferences' + | 'visualizationMap' + | 'datasourceMap' + | 'theme' + | 'uiSettings' + | 'attributeService' + >, + navigateToLensEditor?: ( + stateTransfer: EmbeddableStateTransfer, + skipAppLeave?: boolean + ) => () => Promise<void>, + uuid?: string +) { + return async function openConfigPanel({ + onApply, + onCancel, + hideTimeFilterInfo, + }: Partial<Pick<EditConfigPanelProps, 'onApply' | 'onCancel' | 'hideTimeFilterInfo'>> = {}) { + const { getEditLensConfiguration, getVisualizationMap, getDatasourceMap } = await import( + '../../async_services' + ); + const visualizationMap = getVisualizationMap(); + const datasourceMap = getDatasourceMap(); + + const currentState = getState(); + const attributes = currentState.attributes as TypedLensSerializedState['attributes']; + const activeDatasourceId = (getActiveDatasourceIdFromDoc(attributes) || + 'formBased') as EditLensConfigurationProps['datasourceId']; + + const { updatePanelState, updateSuggestion } = getStateManagementForInlineEditing( + activeDatasourceId, + () => getState().attributes as TypedLensSerializedState['attributes'], + (attrs: TypedLensSerializedState['attributes'], resetId: boolean = false) => { + updateState({ + attributes: attrs, + savedObjectId: resetId ? undefined : currentState.savedObjectId, + }); + }, + visualizationMap, + datasourceMap, + startDependencies.data.query.filterManager.extract + ); + + const updateByRefInput = (savedObjectId: LensRuntimeState['savedObjectId']) => { + updateState({ attributes, savedObjectId }); + }; + const Component = await getEditLensConfiguration( + coreStart, + startDependencies, + visualizationMap, + datasourceMap + ); + + if (attributes?.visualizationType == null) { + return null; + } + return ( + <Component + attributes={attributes} + updateByRefInput={updateByRefInput} + updatePanelState={updatePanelState} + updateSuggestion={updateSuggestion} + datasourceId={activeDatasourceId} + lensAdapters={inspectorApi.getInspectorAdapters()} + dataLoading$={dataLoading$} + panelId={uuid} + savedObjectId={currentState.savedObjectId} + navigateToLensEditor={ + !isTextBasedLanguage(currentState) && navigateToLensEditor + ? navigateToLensEditor( + new EmbeddableStateTransfer( + coreStart.application.navigateToApp, + coreStart.application.currentAppId$ + ), + true + ) + : undefined + } + displayFlyoutHeader + canEditTextBasedQuery={isTextBasedLanguage(currentState)} + isNewPanel={panelManagementApi.isNewPanel()} + onCancel={() => { + panelManagementApi.onStopEditing( + true, + // DSL/form based charts are created via the full editor, so there's + // an initial state to preserve. ES|QL charts are created inline, so it needs to pass an empty state + // and the panelManagementApi will decide whether to remove the panel or not + isNewlyCreated$.getValue() ? undefined : initialState + ); + onCancel?.(); + }} + onApply={(newAttributes) => { + panelManagementApi.onStopEditing(false, { ...getState(), attributes: newAttributes }); + if (newAttributes.visualizationType != null) { + onApply?.(newAttributes); + } + }} + hideTimeFilterInfo={hideTimeFilterInfo} + /> + ); + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/inline_editing/state_management.tsx b/x-pack/plugins/lens/public/react_embeddable/inline_editing/state_management.tsx new file mode 100644 index 000000000000..2a4f1f48fd0d --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/inline_editing/state_management.tsx @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FilterManager } from '@kbn/data-plugin/public'; +import { mergeToNewDoc } from '../../state_management/shared_logic'; +import type { DatasourceStates } from '../../state_management/types'; +import type { VisualizationMap, DatasourceMap } from '../../types'; +import type { TypedLensSerializedState } from '../types'; + +export function getStateManagementForInlineEditing( + activeDatasourceId: 'formBased' | 'textBased', + getAttributes: () => TypedLensSerializedState['attributes'], + updateAttributes: ( + newAttributes: TypedLensSerializedState['attributes'], + resetId?: boolean + ) => void, + visualizationMap: VisualizationMap, + datasourceMap: DatasourceMap, + extractFilterReferences: FilterManager['extract'] +) { + const updatePanelState = ( + datasourceState: unknown, + visualizationState: unknown, + visualizationType?: string + ) => { + const viz = getAttributes(); + const datasourceStates: DatasourceStates = { + [activeDatasourceId]: { + isLoading: false, + state: datasourceState, + }, + }; + const newViz = mergeToNewDoc( + viz, + { + activeId: visualizationType || viz.visualizationType, + state: visualizationState, + }, + datasourceStates, + viz.state.query, + viz.state.filters, + activeDatasourceId, + viz.state.adHocDataViews || {}, + { visualizationMap, datasourceMap, extractFilterReferences } + ); + const newDoc = { + ...viz, + ...newViz, + }; + + if (newDoc.state) { + updateAttributes(newDoc, true); + } + }; + + const updateSuggestion = updateAttributes; + + return { updateSuggestion, updatePanelState }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx b/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx new file mode 100644 index 000000000000..074ae451115b --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/lens_embeddable.tsx @@ -0,0 +1,190 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { ReactEmbeddableFactory } from '@kbn/embeddable-plugin/public'; +import { DOC_TYPE } from '../../common/constants'; +import { + LensApi, + LensEmbeddableStartServices, + LensRuntimeState, + LensSerializedState, +} from './types'; + +import { loadEmbeddableData } from './data_loader'; +import { isTextBasedLanguage, deserializeState } from './helper'; +import { initializeEditApi } from './initializers/initialize_edit'; +import { initializeInspector } from './initializers/initialize_inspector'; +import { initializeDashboardServices } from './initializers/initialize_dashboard_services'; +import { initializeInternalApi } from './initializers/initialize_internal_api'; +import { initializeSearchContext } from './initializers/initialize_search_context'; +import { initializeVisualizationContext } from './initializers/initialize_visualization_context'; +import { initializeActionApi } from './initializers/initialize_actions'; +import { initializeIntegrations } from './initializers/initialize_integrations'; +import { initializeStateManagement } from './initializers/initialize_state_management'; +import { LensEmbeddableComponent } from './renderer/lens_embeddable_component'; + +export const createLensEmbeddableFactory = ( + services: LensEmbeddableStartServices +): ReactEmbeddableFactory<LensSerializedState, LensRuntimeState, LensApi> => { + return { + type: DOC_TYPE, + /** + * This is called before the build and will make sure that the + * final state will contain the attributes object + */ + deserializeState: async ({ rawState, references }) => + deserializeState(services.attributeService, rawState, references), + /** + * This is called after the deserialize, so some assumptions can be made about its arguments: + * @param state the Lens "runtime" state, which means that 'attributes' is always present. + * The difference for a by-value and a by-ref can be determined by the presence of 'savedObjectId' in the state + * @param buildApi a utility function to build the Lens API together to instrument the embeddable container on how to detect + * significative changes in the state (i.e. worth a save or not) + * @param uuid a unique identifier for the embeddable panel + * @param parentApi a set of props passed down from the embeddable container. Note: no assumptions can be made about its content + * so the usage of type-guards is recommended before extracting data from it. + * Due to the new embeddable being rendered by a <ReactEmbeddableRenderer /> wrapper, this is the only way + * to pass data/props from a container. + * Typical use cases is the forwarding of the unifiedSearch context to the embeddable, or the passing props + * from the Lens component container to the Lens embeddable. + * @returns an object with the Lens API and the React component to render in the Embeddable + */ + buildEmbeddable: async (initialState, buildApi, uuid, parentApi) => { + /** + * Observables and functions declared here are used internally to store mutating state values + * This is an internal API not exposed outside of the embeddable. + */ + const internalApi = initializeInternalApi(initialState, parentApi, services); + + const visualizationContextHelper = initializeVisualizationContext(internalApi); + + /** + * Initialize various configurations required to build all the required + * parts for the Lens embeddable. + * Each initialize call returns an object with the following properties: + * - api: a set of methods or observables (also non-serializable) who can be picked up within the component + * - serialize: a serializable subset of the Lens runtime state + * - comparators: a set of comparators to help Dashboard determine if the state has changed since its saved state + * - cleanup: a function to clean up any resources when the component is unmounted + * + * Mind: the getState argument is ok to pass as long as it is lazy evaluated (i.e. called within a function). + * If there's something that should be immediately computed use the "initialState" deserialized variable. + */ + const stateConfig = initializeStateManagement(initialState, internalApi); + const dashboardConfig = initializeDashboardServices( + initialState, + getState, + internalApi, + stateConfig, + parentApi, + services + ); + + const inspectorConfig = initializeInspector(services); + + const editConfig = initializeEditApi( + uuid, + initialState, + getState, + internalApi, + stateConfig.api, + inspectorConfig.api, + isTextBasedLanguage, + services, + parentApi + ); + + const searchContextConfig = initializeSearchContext(initialState, internalApi, parentApi); + const integrationsConfig = initializeIntegrations(getState, services); + const actionsConfig = initializeActionApi( + uuid, + initialState, + getState, + parentApi, + searchContextConfig.api, + dashboardConfig.api, + visualizationContextHelper, + services + ); + + /** + * This is useful to have always the latest version of the state + * at hand when calling callbacks or performing actions + */ + function getState(): LensRuntimeState { + return { + ...actionsConfig.serialize(), + ...editConfig.serialize(), + ...inspectorConfig.serialize(), + ...dashboardConfig.serialize(), + ...searchContextConfig.serialize(), + ...integrationsConfig.serialize(), + ...stateConfig.serialize(), + }; + } + + /** + * Lens API is the object that can be passed to the final component/renderer and + * provide access to the services for and by the outside world + */ + const api: LensApi = buildApi( + // Note: the order matters here, so make sure to have the + // dashboardConfig who owns the savedObjectId after the + // stateConfig one who owns the inline editing + { + ...editConfig.api, + ...inspectorConfig.api, + ...searchContextConfig.api, + ...actionsConfig.api, + ...integrationsConfig.api, + ...stateConfig.api, + ...dashboardConfig.api, + }, + { + ...stateConfig.comparators, + ...editConfig.comparators, + ...inspectorConfig.comparators, + ...searchContextConfig.comparators, + ...actionsConfig.comparators, + ...integrationsConfig.comparators, + ...dashboardConfig.comparators, + } + ); + + // Compute the expression using the provided parameters + // Inside a subscription will be updated based on each unifiedSearch change + // and as side effect update few observables as expressionParams$, expressionAbortController$ and renderCount$ with the new values upon updates + const expressionConfig = loadEmbeddableData( + uuid, + getState, + api, + parentApi, + internalApi, + services, + visualizationContextHelper + ); + + const onUnmount = () => { + editConfig.cleanup(); + inspectorConfig.cleanup(); + searchContextConfig.cleanup(); + expressionConfig.cleanup(); + actionsConfig.cleanup(); + integrationsConfig.cleanup(); + dashboardConfig.cleanup(); + }; + + return { + api, + Component: () => ( + <LensEmbeddableComponent api={api} internalApi={internalApi} onUnmount={onUnmount} /> + ), + }; + }, + }; +}; diff --git a/x-pack/plugins/lens/public/react_embeddable/logger.ts b/x-pack/plugins/lens/public/react_embeddable/logger.ts new file mode 100644 index 000000000000..05454843b681 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/logger.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/** + * Conditional (window.ELASTIC_LENS_LOGGER needs to be set to true) logger function + * @param message - mandatory message to log + * @param payload - optional object to log + */ + +export const addLog = (message: string, payload?: unknown) => { + // @ts-expect-error + const logger = window?.ELASTIC_LENS_LOGGER; + + if (logger) { + if (logger === 'debug') { + // eslint-disable-next-line no-console + console.log(`[Lens] ${message}`, payload); + } else { + // eslint-disable-next-line no-console + console.log(`[Lens] ${message}`); + } + } +}; diff --git a/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx b/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx new file mode 100644 index 000000000000..ddcd5e608959 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/mocks/index.tsx @@ -0,0 +1,354 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BehaviorSubject, Subject } from 'rxjs'; +import deepMerge from 'deepmerge'; +import React from 'react'; +import faker from 'faker'; +import { Query, Filter, AggregateQuery, TimeRange } from '@kbn/es-query'; +import { PhaseEvent, ViewMode } from '@kbn/presentation-publishing'; +import { DataView } from '@kbn/data-views-plugin/common'; +import { Adapters } from '@kbn/inspector-plugin/common'; +import { coreMock } from '@kbn/core/public/mocks'; +import { visualizationsPluginMock } from '@kbn/visualizations-plugin/public/mocks'; +import { expressionsPluginMock } from '@kbn/expressions-plugin/public/mocks'; +import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks'; +import { chartPluginMock } from '@kbn/charts-plugin/public/mocks'; +import { ReactExpressionRendererProps } from '@kbn/expressions-plugin/public'; +import { ReactEmbeddableDynamicActionsApi } from '@kbn/embeddable-enhanced-plugin/public/plugin'; +import { DOC_TYPE } from '../../../common/constants'; +import { createEmptyLensState } from '../helper'; +import { + ExpressionWrapperProps, + LensApi, + LensEmbeddableStartServices, + LensInternalApi, + LensRendererProps, + LensRuntimeState, + LensSerializedState, + VisualizationContext, +} from '../types'; +import { + createMockDatasource, + createMockVisualization, + defaultDoc, + makeDefaultServices, +} from '../../mocks'; +import { + Datasource, + DatasourceMap, + UserMessage, + Visualization, + VisualizationMap, +} from '../../types'; + +const LensApiMock: LensApi = { + // Static props + type: DOC_TYPE, + uuid: faker.random.uuid(), + // Shared Embeddable Observables + panelTitle: new BehaviorSubject<string | undefined>(faker.lorem.words()), + hidePanelTitle: new BehaviorSubject<boolean | undefined>(false), + filters$: new BehaviorSubject<Filter[] | undefined>([]), + query$: new BehaviorSubject<Query | AggregateQuery | undefined>({ + query: 'test', + language: 'kuery', + }), + timeRange$: new BehaviorSubject<TimeRange | undefined>({ from: 'now-15m', to: 'now' }), + dataLoading: new BehaviorSubject<boolean | undefined>(false), + // Methods + getSavedVis: jest.fn(), + getFullAttributes: jest.fn(), + canViewUnderlyingData$: new BehaviorSubject<boolean>(false), + loadViewUnderlyingData: jest.fn(), + getViewUnderlyingDataArgs: jest.fn(() => ({ + dataViewSpec: { id: 'index-pattern-id' }, + timeRange: { from: 'now-7d', to: 'now' }, + filters: [], + query: undefined, + columns: [], + })), + isTextBasedLanguage: jest.fn(() => true), + getTextBasedLanguage: jest.fn(), + getInspectorAdapters: jest.fn(() => ({})), + inspect: jest.fn(), + closeInspector: jest.fn(async () => {}), + supportedTriggers: jest.fn(() => []), + canLinkToLibrary: jest.fn(async () => false), + canUnlinkFromLibrary: jest.fn(async () => false), + unlinkFromLibrary: jest.fn(), + checkForDuplicateTitle: jest.fn(), + /** New embeddable api inherited methods */ + resetUnsavedChanges: jest.fn(), + serializeState: jest.fn(), + snapshotRuntimeState: jest.fn(), + saveToLibrary: jest.fn(async () => 'saved-id'), + getByValueRuntimeSnapshot: jest.fn(), + onEdit: jest.fn(), + isEditingEnabled: jest.fn(() => true), + getTypeDisplayName: jest.fn(() => 'Lens'), + setPanelTitle: jest.fn(), + setHidePanelTitle: jest.fn(), + phase$: new BehaviorSubject<PhaseEvent | undefined>({ + id: faker.random.uuid(), + status: 'rendered', + timeToEvent: 1000, + }), + unsavedChanges: new BehaviorSubject<object | undefined>(undefined), + dataViews: new BehaviorSubject<DataView[] | undefined>(undefined), + libraryId$: new BehaviorSubject<string | undefined>(undefined), + savedObjectId: new BehaviorSubject<string | undefined>(undefined), + adapters$: new BehaviorSubject<Adapters>({}), + updateAttributes: jest.fn(), + updateSavedObjectId: jest.fn(), + updateOverrides: jest.fn(), + getByReferenceState: jest.fn(), + getByValueState: jest.fn(), + getTriggerCompatibleActions: jest.fn(), + blockingError: new BehaviorSubject<Error | undefined>(undefined), + panelDescription: new BehaviorSubject<string | undefined>(undefined), + setPanelDescription: jest.fn(), + viewMode: new BehaviorSubject<ViewMode>('view'), + disabledActionIds: new BehaviorSubject<string[] | undefined>(undefined), + setDisabledActionIds: jest.fn(), + rendered$: new BehaviorSubject<boolean>(false), +}; + +const LensSerializedStateMock: LensSerializedState = createEmptyLensState( + 'lnsXY', + faker.lorem.words(), + faker.lorem.text(), + { query: 'test', language: 'kuery' } +); + +export function getLensAttributesMock(attributes?: Partial<LensRuntimeState['attributes']>) { + return deepMerge(LensSerializedStateMock.attributes!, attributes ?? {}); +} + +export function getLensApiMock(overrides: Partial<LensApi> = {}) { + return { + ...LensApiMock, + ...overrides, + }; +} + +export function getLensSerializedStateMock(overrides: Partial<LensSerializedState> = {}) { + return { + savedObjectId: faker.random.uuid(), + ...LensSerializedStateMock, + ...overrides, + }; +} + +export function getLensRuntimeStateMock( + overrides: Partial<LensRuntimeState> = {} +): LensRuntimeState { + return { + ...(LensSerializedStateMock as LensRuntimeState), + ...overrides, + }; +} + +export function getLensComponentProps(overrides: Partial<LensRendererProps> = {}) { + return { + ...LensSerializedStateMock, + ...LensApiMock, + ...overrides, + }; +} + +export function makeEmbeddableServices( + sessionIdSubject = new Subject<string>(), + sessionId: string | undefined = undefined, + { + visOverrides, + dataOverrides, + }: { + visOverrides?: { id: string } & Partial<Visualization>; + dataOverrides?: { id: string } & Partial<Datasource>; + } = {} +): jest.Mocked<LensEmbeddableStartServices> { + const services = makeDefaultServices(sessionIdSubject, sessionId); + return { + ...services, + expressions: expressionsPluginMock.createStartContract(), + visualizations: visualizationsPluginMock.createStartContract(), + embeddable: embeddablePluginMock.createStartContract(), + eventAnnotation: {} as LensEmbeddableStartServices['eventAnnotation'], + timefilter: services.data.query.timefilter.timefilter, + coreHttp: services.http, + coreStart: coreMock.createStart(), + capabilities: services.application.capabilities, + expressionRenderer: jest.fn().mockReturnValue(null), + documentToExpression: jest.fn(), + injectFilterReferences: services.data.query.filterManager.inject as jest.Mock, + visualizationMap: mockVisualizationMap(visOverrides?.id, visOverrides), + datasourceMap: mockDatasourceMap(dataOverrides?.id, dataOverrides), + charts: chartPluginMock.createStartContract(), + inspector: { + ...services.inspector, + isAvailable: jest.fn().mockReturnValue(true), + open: jest.fn(), + }, + uiActions: { + ...services.uiActions, + getTrigger: jest.fn().mockImplementation(() => ({ exec: jest.fn() })), + }, + embeddableEnhanced: { + initializeReactEmbeddableDynamicActions: jest.fn( + () => + ({ + dynamicActionsApi: { + enhancements: { dynamicActions: {} }, + setDynamicActions: jest.fn(), + dynamicActionsState$: {}, + }, + dynamicActionsComparator: jest.fn(), + serializeDynamicActions: jest.fn(), + startDynamicActions: jest.fn(), + } as unknown as ReactEmbeddableDynamicActionsApi) + ), + }, + }; +} + +export const mockVisualizationMap = ( + type: string | undefined = undefined, + overrides: Partial<Visualization> = {} +): VisualizationMap => { + if (type == null) { + return {}; + } + return { + [type]: { ...createMockVisualization(type), ...overrides }, + }; +}; + +export const mockDatasourceMap = ( + type: string | undefined = undefined, + overrides: Partial<Datasource> = {} +): DatasourceMap => { + const baseMap = { + // define the existing ones + formBased: createMockDatasource('formBased'), + textBased: createMockDatasource('textBased'), + }; + if (type == null) { + return baseMap; + } + return { + // define the existing ones + ...baseMap, + // override at will + [type]: { + ...createMockDatasource(type), + ...overrides, + }, + }; +}; + +export function createExpressionRendererMock(): jest.Mock< + React.ReactElement, + [ReactExpressionRendererProps] +> { + return jest.fn(({ expression }) => ( + <span data-test-subj="lnsExpressionRenderer"> + {(expression as string) || 'Expression renderer mock'} + </span> + )); +} + +function getValidExpressionParams( + overrides: Partial<ExpressionWrapperProps> = {} +): ExpressionWrapperProps { + return { + ExpressionRenderer: createExpressionRendererMock(), + expression: 'test', + searchContext: {}, + handleEvent: jest.fn(), + onData$: jest.fn(), + onRender$: jest.fn(), + addUserMessages: jest.fn(), + onRuntimeError: jest.fn(), + lensInspector: { + getInspectorAdapters: jest.fn(), + inspect: jest.fn(), + closeInspector: jest.fn(), + }, + ...overrides, + }; +} + +const LensInternalApiMock: LensInternalApi = { + dataViews: new BehaviorSubject<DataView[] | undefined>(undefined), + attributes$: new BehaviorSubject<LensRuntimeState['attributes']>(defaultDoc), + overrides$: new BehaviorSubject<LensRuntimeState['overrides']>(undefined), + disableTriggers$: new BehaviorSubject<LensRuntimeState['disableTriggers']>(undefined), + dataLoading$: new BehaviorSubject<boolean | undefined>(undefined), + hasRenderCompleted$: new BehaviorSubject<boolean>(true), + expressionParams$: new BehaviorSubject<ExpressionWrapperProps | null>(getValidExpressionParams()), + expressionAbortController$: new BehaviorSubject<AbortController | undefined>(undefined), + renderCount$: new BehaviorSubject<number>(0), + messages$: new BehaviorSubject<UserMessage[]>([]), + validationMessages$: new BehaviorSubject<UserMessage[]>([]), + isNewlyCreated$: new BehaviorSubject<boolean>(true), + updateAttributes: jest.fn(), + updateOverrides: jest.fn(), + dispatchRenderStart: jest.fn(), + dispatchRenderComplete: jest.fn(), + updateDataLoading: jest.fn(), + updateExpressionParams: jest.fn(), + updateAbortController: jest.fn(), + updateDataViews: jest.fn(), + updateMessages: jest.fn(), + resetAllMessages: jest.fn(), + dispatchError: jest.fn(), + updateValidationMessages: jest.fn(), + setAsCreated: jest.fn(), + getDisplayOptions: jest.fn(() => ({})), +}; + +export function getLensInternalApiMock(overrides: Partial<LensInternalApi> = {}): LensInternalApi { + return { + ...LensInternalApiMock, + ...overrides, + }; +} + +export function getVisualizationContextHelperMock( + attributesOverrides?: Partial<LensRuntimeState['attributes']>, + contextOverrides?: Omit<Partial<VisualizationContext>, 'doc'> +) { + return { + getVisualizationContext: jest.fn(() => ({ + mergedSearchContext: {}, + indexPatterns: {}, + indexPatternRefs: [], + activeVisualizationState: undefined, + activeDatasourceState: undefined, + activeData: undefined, + ...contextOverrides, + doc: getLensAttributesMock(attributesOverrides), + })), + updateVisualizationContext: jest.fn(), + }; +} + +export function createUnifiedSearchApi( + query: Query | AggregateQuery = { + query: '', + language: 'kuery', + }, + filters: Filter[] = [], + timeRange: TimeRange = { from: 'now-7d', to: 'now' } +) { + return { + filters$: new BehaviorSubject<Filter[] | undefined>(filters), + query$: new BehaviorSubject<Query | AggregateQuery | undefined>(query), + timeRange$: new BehaviorSubject<TimeRange | undefined>(timeRange), + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/hooks.ts b/x-pack/plugins/lens/public/react_embeddable/renderer/hooks.ts new file mode 100644 index 000000000000..c6d97d16ad38 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/hooks.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { partition } from 'lodash'; +import { useEffect, useMemo, useRef } from 'react'; +import { useStateFromPublishingSubject } from '@kbn/presentation-publishing'; +import { dispatchRenderComplete, dispatchRenderStart } from '@kbn/kibana-utils-plugin/public'; +import { LensApi, LensInternalApi } from '../types'; + +/** + * This hooks known how to extract message based on types for the UI + */ +export function useMessages({ messages$ }: LensInternalApi) { + const latestMessages = useStateFromPublishingSubject(messages$); + return useMemo( + () => partition(latestMessages, ({ severity }) => severity !== 'info'), + [latestMessages] + ); +} + +/** + * This hook is responsible to emit the render start/complete JS event + * The render error is handled by the data_loader itself when updating the blocking errors + */ +export function useDispatcher(hasRendered: boolean, api: LensApi) { + const rootRef = useRef<HTMLDivElement | null>(null); + useEffect(() => { + if (!rootRef.current || api.blockingError?.getValue()) { + return; + } + if (hasRendered) { + dispatchRenderComplete(rootRef.current); + } else { + dispatchRenderStart(rootRef.current); + } + }, [hasRendered, api.blockingError, rootRef]); + return rootRef; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx new file mode 100644 index 000000000000..5bc55d43c321 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_custom_renderer_component.tsx @@ -0,0 +1,158 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ReactEmbeddableRenderer } from '@kbn/embeddable-plugin/public'; +import { useSearchApi } from '@kbn/presentation-publishing'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { BehaviorSubject } from 'rxjs'; +import type { PresentationPanelProps } from '@kbn/presentation-panel-plugin/public'; +import type { LensApi, LensRendererProps, LensRuntimeState, LensSerializedState } from '../types'; +import { LENS_EMBEDDABLE_TYPE } from '../../../common/constants'; +import { createEmptyLensState } from '../helper'; + +// This little utility uses the same pattern of the useSearchApi hook: +// create the Subject once and then update its value on change +function useObservableVariable<T extends unknown>(value: T) { + // eslint-disable-next-line react-hooks/exhaustive-deps + const observable = useMemo(() => new BehaviorSubject<T>(value), []); + + // update the observable on change + useEffect(() => { + observable.next(value); + }, [observable, value]); + + return observable; +} + +type PanelProps = Pick< + PresentationPanelProps<LensApi>, + | 'showShadow' + | 'showBorder' + | 'showBadges' + | 'showNotifications' + | 'hideLoader' + | 'hideHeader' + | 'hideInspector' + | 'getActions' +>; + +/** + * The aim of this component is to provide a wrapper for other plugins who want to + * use a Lens component into their own page. This hides the embeddable parts of it + * by wrapping it into a ReactEmbeddableRenderer component and exposing a custom API + */ +export function LensRenderer({ + title, + withDefaultActions, + extraActions, + showInspector, + syncColors, + syncCursor, + syncTooltips, + viewMode, + id, + query, + filters, + timeRange, + disabledActions, + ...props +}: LensRendererProps) { + // Use the settings interface to store panel settings + const settings = useMemo(() => { + return { + syncColors$: new BehaviorSubject(false), + syncCursor$: new BehaviorSubject(false), + syncTooltips$: new BehaviorSubject(false), + }; + }, []); + const disabledActionIds$ = useObservableVariable(disabledActions); + const viewMode$ = useObservableVariable(viewMode); + + // Lens API will be set once, but when set trigger a reflow to adopt the latest attributes + const [lensApi, setLensApi] = useState<LensApi | undefined>(undefined); + const initialStateRef = useRef<LensSerializedState>( + props.attributes ? { attributes: props.attributes } : createEmptyLensState(null, title) + ); + + const searchApi = useSearchApi({ query, filters, timeRange }); + + const showPanelChrome = Boolean(withDefaultActions) || (extraActions?.length || 0) > 0; + + // Re-render on changes + // internally the embeddable will evaluate whether it is worth to actual render or not + useEffect(() => { + // trigger a re-render if the attributes change + if (lensApi) { + lensApi.updateAttributes({ + ...('attributes' in initialStateRef.current + ? initialStateRef.current.attributes + : initialStateRef.current), + ...props.attributes, + }); + lensApi.updateOverrides(props.overrides); + } + }, [lensApi, props.attributes, props.overrides]); + + useEffect(() => { + if (syncColors != null && settings.syncColors$.getValue() !== syncColors) { + settings.syncColors$.next(syncColors); + } + if (syncCursor != null && settings.syncCursor$.getValue() !== syncCursor) { + settings.syncCursor$.next(syncCursor); + } + if (syncTooltips != null && settings.syncTooltips$.getValue() !== syncTooltips) { + settings.syncTooltips$.next(syncTooltips); + } + }, [settings, syncColors, syncCursor, syncTooltips]); + + const panelProps: PanelProps = useMemo(() => { + return { + hideInspector: !showInspector, + hideHeader: showPanelChrome, + showNotifications: false, + showShadow: false, + showBadges: false, + getActions: async (triggerId, context) => { + const actions = withDefaultActions + ? await lensApi?.getTriggerCompatibleActions(triggerId, context) + : []; + + return (extraActions ?? []).concat(actions || []); + }, + }; + }, [showInspector, showPanelChrome, withDefaultActions, extraActions, lensApi]); + + return ( + <ReactEmbeddableRenderer<LensSerializedState, LensRuntimeState, LensApi> + type={LENS_EMBEDDABLE_TYPE} + maybeId={id} + getParentApi={() => ({ + // forward the Lens components to the embeddable + ...props, + // forward the unified search context + ...searchApi, + disabledActionIds: disabledActionIds$, + setDisabledActionIds: (ids: string[] | undefined) => disabledActionIds$.next(ids), + viewMode: viewMode$, + // pass the sync* settings with the unified settings interface + settings, + // make sure to provide the initial state (useful for the comparison check) + getSerializedStateForChild: () => ({ rawState: initialStateRef.current, references: [] }), + // update the runtime state on changes + getRuntimeStateForChild: () => ({ + ...initialStateRef.current, + attributes: props.attributes, + }), + })} + onApiAvailable={setLensApi} + hidePanelChrome={!showPanelChrome} + panelProps={panelProps} + /> + ); +} + +export type EmbeddableComponent = React.ComponentType<LensRendererProps>; diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx new file mode 100644 index 000000000000..f444f429250b --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.test.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, screen } from '@testing-library/react'; +import { getLensApiMock, getLensInternalApiMock } from '../mocks'; +import { LensApi, LensInternalApi } from '../types'; +import { BehaviorSubject } from 'rxjs'; +import { PublishingSubject } from '@kbn/presentation-publishing'; +import React from 'react'; +import { LensEmbeddableComponent } from './lens_embeddable_component'; + +jest.mock('../expression_wrapper', () => ({ + ExpressionWrapper: () => ( + <div className="lnsExpressionRenderer" data-test-subj="lens-embeddable" /> + ), +})); + +type GetValueType<Type> = Type extends PublishingSubject<infer X> ? X : never; + +function getDefaultProps({ + internalApiOverrides = undefined, + apiOverrides = undefined, +}: { internalApiOverrides?: Partial<LensInternalApi>; apiOverrides?: Partial<LensApi> } = {}) { + return { + internalApi: getLensInternalApiMock(internalApiOverrides), + api: getLensApiMock(apiOverrides), + onUnmount: jest.fn(), + }; +} + +describe('Lens Embeddable component', () => { + it('should not render the visualization if any error arises', () => { + const props = getDefaultProps({ + internalApiOverrides: { + expressionParams$: new BehaviorSubject<GetValueType<LensInternalApi['expressionParams$']>>( + null + ), + }, + }); + + render(<LensEmbeddableComponent {...props} />); + expect(screen.queryByTestId('lens-embeddable')).not.toBeInTheDocument(); + }); + + it('shoud not render the title if the visualization forces the title to be hidden', () => { + const getDisplayOptions = jest.fn(() => ({ noPanelTitle: true })); + const props = getDefaultProps({ + internalApiOverrides: { + getDisplayOptions, + }, + }); + + render(<LensEmbeddableComponent {...props} />); + expect(props.internalApi.getDisplayOptions).toHaveBeenCalled(); + expect(screen.getByTestId('lens-embeddable').parentElement).not.toHaveAttribute('data-title'); + }); +}); diff --git a/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx new file mode 100644 index 000000000000..122891788a80 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/renderer/lens_embeddable_component.tsx @@ -0,0 +1,91 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useBatchedPublishingSubjects } from '@kbn/presentation-publishing'; +import React, { useEffect } from 'react'; +import { LensApi } from '../..'; +import { ExpressionWrapper } from '../expression_wrapper'; +import { LensInternalApi } from '../types'; +import { UserMessages } from '../user_messages/container'; +import { useMessages, useDispatcher } from './hooks'; +import { getViewMode } from '../helper'; +import { addLog } from '../logger'; + +export function LensEmbeddableComponent({ + internalApi, + api, + onUnmount, +}: { + internalApi: LensInternalApi; + api: LensApi; + onUnmount: () => void; +}) { + const [ + // Pick up updated params from the observable + expressionParams, + // used for functional tests + renderCount, + // these are blocking errors that can be shown in a badge + // without replacing the entire panel + blockingErrors, + // has the render completed? + hasRendered, + // has view mode changed? + latestViewMode, + ] = useBatchedPublishingSubjects( + internalApi.expressionParams$, + internalApi.renderCount$, + internalApi.validationMessages$, + api.rendered$, + api.viewMode + ); + const canEdit = Boolean(api.isEditingEnabled?.() && getViewMode(latestViewMode) === 'edit'); + + const [warningOrErrors, infoMessages] = useMessages(internalApi); + + // On unmount call all the cleanups + useEffect(() => { + addLog(`Mounting Lens Embeddable component: ${api.defaultPanelTitle?.getValue()}`); + return onUnmount; + }, [api, onUnmount]); + + // take care of dispatching the event from the DOM node + const rootRef = useDispatcher(hasRendered, api); + + // Publish the data attributes only if avaialble/visible + const title = internalApi.getDisplayOptions()?.noPanelTitle + ? undefined + : { 'data-title': api.panelTitle?.getValue() ?? api.defaultPanelTitle?.getValue() }; + const description = api.panelDescription?.getValue() + ? { + 'data-description': + api.panelDescription?.getValue() ?? api.defaultPanelDescription?.getValue(), + } + : undefined; + + return ( + <div + style={{ width: '100%', height: '100%' }} + data-rendering-count={renderCount + 1} + data-render-complete={hasRendered} + {...title} + {...description} + data-shared-item + ref={rootRef} + > + {expressionParams == null || blockingErrors.length ? null : ( + <ExpressionWrapper {...expressionParams} /> + )} + <UserMessages + blockingErrors={blockingErrors} + warningOrErrors={warningOrErrors} + infoMessages={infoMessages} + canEdit={canEdit} + /> + </div> + ); +} diff --git a/x-pack/plugins/lens/public/react_embeddable/type_guards.ts b/x-pack/plugins/lens/public/react_embeddable/type_guards.ts new file mode 100644 index 000000000000..95e8311a7a3c --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/type_guards.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + apiIsOfType, + apiPublishesPanelTitle, + apiPublishesUnifiedSearch, +} from '@kbn/presentation-publishing'; +import { isObject } from 'lodash'; +import { + LensApiCallbacks, + LensApi, + LensComponentForwardedProps, + LensPublicCallbacks, +} from './types'; + +function apiHasLensCallbacks(api: unknown): api is LensApiCallbacks { + const fns = [ + 'getSavedVis', + 'getViewUnderlyingDataArgs', + 'isTextBasedLanguage', + 'getTextBasedLanguage', + ] as Array<keyof LensApiCallbacks>; + return fns.every((fn) => typeof (api as LensApiCallbacks)[fn] === 'function'); +} + +export const isLensApi = (api: unknown): api is LensApi => { + return Boolean( + api && + apiIsOfType(api, 'lens') && + 'canViewUnderlyingData$' in api && + apiHasLensCallbacks(api) && + apiPublishesPanelTitle(api) && + apiPublishesUnifiedSearch(api) + ); +}; + +export function apiHasLensComponentCallbacks(api: unknown): api is LensPublicCallbacks { + return ( + isObject(api) && + ['onFilter', 'onBrushEnd', 'onLoad', 'onTableRowClick', 'onBeforeBadgesRender'].some((fn) => + Object.hasOwn(api, fn) + ) + ); +} + +export function apiHasLensComponentProps(api: unknown): api is LensComponentForwardedProps { + return ( + isObject(api) && + ['style', 'className', 'noPadding', 'viewMode', 'abortController'].some((prop) => + Object.hasOwn(api, prop) + ) + ); +} + +export function apiHasAbortController(api: unknown): api is { abortController: AbortController } { + return isObject(api) && Object.hasOwn(api, 'abortController'); +} + +export function apiHasLastReloadRequestTime( + api: unknown +): api is { lastReloadRequestTime: number } { + return isObject(api) && Object.hasOwn(api, 'lastReloadRequestTime'); +} + +export function apiPublishesInlineEditingCapabilities( + api: unknown +): api is { canEditInline: boolean } { + return isObject(api) && Object.hasOwn(api, 'canEditInline'); +} diff --git a/x-pack/plugins/lens/public/react_embeddable/types.ts b/x-pack/plugins/lens/public/react_embeddable/types.ts new file mode 100644 index 000000000000..c860c543570c --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/types.ts @@ -0,0 +1,503 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { DefaultEmbeddableApi } from '@kbn/embeddable-plugin/public'; +import type { + AggregateQuery, + ExecutionContextSearch, + Filter, + Query, + TimeRange, +} from '@kbn/es-query'; +import type { Adapters, InspectorOptions } from '@kbn/inspector-plugin/public'; +import type { + HasEditCapabilities, + HasInPlaceLibraryTransforms, + HasLibraryTransforms, + HasParentApi, + HasSupportedTriggers, + PublishesBlockingError, + PublishesDataLoading, + PublishesDataViews, + PublishesDisabledActionIds, + PublishesSavedObjectId, + PublishesUnifiedSearch, + PublishesViewMode, + PublishesRendered, + PublishesWritablePanelDescription, + PublishesWritablePanelTitle, + PublishingSubject, + SerializedTitles, + ViewMode, +} from '@kbn/presentation-publishing'; +import type { DynamicActionsSerializedState } from '@kbn/embeddable-enhanced-plugin/public/plugin'; +import type { + BrushTriggerEvent, + ClickTriggerEvent, + MultiClickTriggerEvent, +} from '@kbn/charts-plugin/public'; +import type { PaletteOutput } from '@kbn/coloring'; +import type { DefaultInspectorAdapters, RenderMode } from '@kbn/expressions-plugin/common'; +import type { + Capabilities, + CoreStart, + HttpSetup, + IUiSettingsClient, + KibanaExecutionContext, + OverlayRef, + SavedObjectReference, + ThemeServiceStart, +} from '@kbn/core/public'; +import type { TimefilterContract, FilterManager } from '@kbn/data-plugin/public'; +import type { DataView, DataViewSpec } from '@kbn/data-views-plugin/common'; +import type { + ExpressionRendererEvent, + ReactExpressionRendererProps, + ReactExpressionRendererType, +} from '@kbn/expressions-plugin/public'; +import type { RecursiveReadonly } from '@kbn/utility-types'; +import type { AllowedChartOverrides, AllowedSettingsOverrides } from '@kbn/charts-plugin/common'; +import type { AllowedGaugeOverrides } from '@kbn/expression-gauge-plugin/common'; +import type { AllowedPartitionOverrides } from '@kbn/expression-partition-vis-plugin/common'; +import type { AllowedXYOverrides } from '@kbn/expression-xy-plugin/common'; +import type { Action } from '@kbn/ui-actions-plugin/public'; +import { PresentationContainer } from '@kbn/presentation-containers'; +import type { LegacyMetricState } from '../../common'; +import type { LensDocument } from '../persistence'; +import type { LensInspector } from '../lens_inspector_service'; +import type { LensAttributesService } from '../lens_attribute_service'; +import type { + DatatableVisualizationState, + DocumentToExpressionReturnType, + HeatmapVisualizationState, + XYState, +} from '../async_services'; +import type { + DatasourceMap, + IndexPatternMap, + IndexPatternRef, + LensTableRowContextMenuEvent, + SharingSavedObjectProps, + Simplify, + UserMessage, + VisualizationDisplayOptions, + VisualizationMap, +} from '../types'; +import type { LensPluginStartDependencies } from '../plugin'; +import type { TableInspectorAdapter } from '../editor_frame_service/types'; +import type { PieVisualizationState } from '../../common/types'; +import type { FormBasedPersistedState } from '..'; +import type { TextBasedPersistedState } from '../datasources/text_based/types'; +import type { GaugeVisualizationState } from '../visualizations/gauge/constants'; +import type { MetricVisualizationState } from '../visualizations/metric/types'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +interface LensApiProps {} + +export type LensSavedObjectAttributes = Omit<LensDocument, 'savedObjectId' | 'type'>; + +export interface VisualizationContext { + doc: LensDocument | undefined; + mergedSearchContext: ExecutionContextSearch; + indexPatterns: IndexPatternMap; + indexPatternRefs: IndexPatternRef[]; + activeVisualizationState: unknown; + activeDatasourceState: unknown; + activeData?: TableInspectorAdapter; +} + +export interface VisualizationContextHelper { + getVisualizationContext: () => VisualizationContext; + updateVisualizationContext: (newContext: Partial<VisualizationContext>) => void; +} + +export interface ViewUnderlyingDataArgs { + dataViewSpec: DataViewSpec; + timeRange: TimeRange; + filters: Filter[]; + query: Query | AggregateQuery | undefined; + columns: string[]; +} + +export type LensEmbeddableStartServices = Simplify< + LensPluginStartDependencies & { + timefilter: TimefilterContract; + coreHttp: HttpSetup; + coreStart: CoreStart; + capabilities: RecursiveReadonly<Capabilities>; + expressionRenderer: ReactExpressionRendererType; + documentToExpression: (doc: LensDocument) => Promise<DocumentToExpressionReturnType>; + injectFilterReferences: FilterManager['inject']; + visualizationMap: VisualizationMap; + datasourceMap: DatasourceMap; + theme: ThemeServiceStart; + uiSettings: IUiSettingsClient; + attributeService: LensAttributesService; + } +>; + +export interface PreventableEvent { + preventDefault(): void; +} + +interface LensByValue { + // by-value + attributes?: Simplify<LensSavedObjectAttributes>; +} + +export interface LensOverrides { + /** + * Overrides can tweak the style of the final embeddable and are executed at the end of the Lens rendering pipeline. + * Each visualization type offers various type of overrides, per component (i.e. 'setting', 'axisX', 'partition', etc...) + * + * While it is not possible to pass function/callback/handlers to the renderer, it is possible to overwrite + * the current behaviour by passing the "ignore" string to the override prop (i.e. onBrushEnd: "ignore" to stop brushing) + */ + overrides?: + | AllowedChartOverrides + | AllowedSettingsOverrides + | AllowedXYOverrides + | AllowedPartitionOverrides + | AllowedGaugeOverrides; +} + +/** + * Lens embeddable props broken down by type + */ + +export interface LensByReference { + // by-reference + savedObjectId?: string; +} + +interface ContentManagementProps { + sharingSavedObjectProps?: SharingSavedObjectProps; + managed?: boolean; +} + +export type LensPropsVariants = (LensByValue & LensByReference) & { + references?: SavedObjectReference[]; +}; + +export interface ViewInDiscoverCallbacks extends LensApiProps { + canViewUnderlyingData$: PublishingSubject<boolean>; + loadViewUnderlyingData: () => void; + getViewUnderlyingDataArgs: () => ViewUnderlyingDataArgs | undefined; +} + +export interface IntegrationCallbacks extends LensApiProps { + isTextBasedLanguage: () => boolean | undefined; + getTextBasedLanguage: () => string | undefined; + getSavedVis: () => Readonly<LensSavedObjectAttributes | undefined>; + getFullAttributes: () => LensDocument | undefined; + updateAttributes: (newAttributes: LensRuntimeState['attributes']) => void; + updateSavedObjectId: (newSavedObjectId: LensRuntimeState['savedObjectId']) => void; + updateOverrides: (newOverrides: LensOverrides['overrides']) => void; + getTriggerCompatibleActions: (triggerId: string, context: object) => Promise<Action[]>; +} + +/** + * Public Callbacks are function who are exposed thru the Lens custom renderer component, + * so not directly exposed in the Lens API, rather passed down as parentApi to the Lens Embeddable + */ +export interface LensPublicCallbacks extends LensApiProps { + onBrushEnd?: (data: Simplify<BrushTriggerEvent['data'] & PreventableEvent>) => void; + onLoad?: ( + isLoading: boolean, + adapters?: Partial<DefaultInspectorAdapters>, + dataLoading$?: PublishingSubject<boolean | undefined> + ) => void; + onFilter?: ( + data: Simplify<(ClickTriggerEvent['data'] | MultiClickTriggerEvent['data']) & PreventableEvent> + ) => void; + onTableRowClick?: ( + data: Simplify<LensTableRowContextMenuEvent['data'] & PreventableEvent> + ) => void; + /** + * Let the consumer overwrite embeddable user messages + */ + onBeforeBadgesRender?: (userMessages: UserMessage[]) => UserMessage[]; +} + +/** + * API callbacks are function who are used by direct Embeddable consumers (i.e. Dashboard or our own Lens custom renderer) + */ +export type LensApiCallbacks = Simplify<ViewInDiscoverCallbacks & IntegrationCallbacks>; + +export interface LensUnifiedSearchContext { + filters?: Filter[]; + query?: Query | AggregateQuery; + timeRange?: TimeRange; + timeslice?: [number, number]; + searchSessionId?: string; + lastReloadRequestTime?: number; +} + +export interface LensPanelProps { + id?: string; + renderMode?: ViewMode; + disableTriggers?: boolean; + syncColors?: boolean; + syncTooltips?: boolean; + syncCursor?: boolean; + palette?: PaletteOutput; +} + +/** + * This set of props are exposes by the Lens component too + */ +export interface LensSharedProps { + executionContext?: KibanaExecutionContext; + style?: React.CSSProperties; + className?: string; + noPadding?: boolean; + viewMode?: ViewMode; +} + +interface LensRequestHandlersProps { + /** + * Custom abort controller to be used for the ES client + */ + abortController?: AbortController; +} + +/** + * Compose together all the props and make them inspectable via Simplify + * + * The LensSerializedState is the state stored for a dashboard panel + * that contains: + * * Lens document state + * * Panel settings + * * other props from the embeddable + */ +export type LensSerializedState = Simplify< + LensPropsVariants & + LensOverrides & + LensUnifiedSearchContext & + LensPanelProps & + SerializedTitles & + Omit<LensSharedProps, 'noPadding'> & + Partial<DynamicActionsSerializedState> & { isNewPanel?: boolean } +>; + +/** + * Custom props exposed on the Lens exported component + */ +export type LensComponentProps = Simplify< + LensRequestHandlersProps & + LensSharedProps & { + /** + * When enabled the Lens component will render as a dashboard panel + */ + withDefaultActions?: boolean; + /** + * Allow custom actions to be rendered in the panel + */ + extraActions?: Action[]; + /** + * Disable specific actions for the embeddable + */ + disabledActions?: string[]; + /** + * Toggles the inspector + */ + showInspector?: boolean; + /** + * Toggle inline editing feature + */ + canEditInline?: boolean; + } +>; + +/** + * This is the subset of props that from the LensComponent will be forwarded to the Lens embeddable + */ +export type LensComponentForwardedProps = Pick< + LensComponentProps, + 'style' | 'className' | 'noPadding' | 'abortController' | 'executionContext' | 'viewMode' +>; + +/** + * Carefully chosen props to expose on the Lens renderer component used by + * other plugins + */ + +type ComponentProps = LensComponentProps & LensPublicCallbacks; +type ComponentSerializedProps = TypedLensSerializedState; + +type LensRendererPrivateProps = ComponentSerializedProps & ComponentProps; +export type LensRendererProps = Simplify<LensRendererPrivateProps>; + +/** + * The LensRuntimeState is the state stored for a dashboard panel + * that contains: + * * Lens document state + * * Panel settings + * * other props from the embeddable + */ +export type LensRuntimeState = Simplify< + Omit<ComponentSerializedProps, 'attributes' | 'references'> & { + attributes: NonNullable<LensSerializedState['attributes']>; + } & Pick<LensComponentForwardedProps, 'viewMode' | 'abortController' | 'executionContext'> & + ContentManagementProps +>; + +export interface LensInspectorAdapters { + getInspectorAdapters: () => Adapters; + inspect: (options?: InspectorOptions) => OverlayRef; + closeInspector: () => Promise<void>; + // expose a handler for the inspector adapters + // to be able to subscribe to changes + // a typical use case is the inline editing, where the editor + // needs to be updated on data changes + adapters$: PublishingSubject<Adapters>; +} + +export type LensApi = Simplify< + DefaultEmbeddableApi<LensSerializedState, LensRuntimeState> & + // This is used by actions to operate the edit action + HasEditCapabilities & + // for blocking errors leverage the embeddable panel UI + PublishesBlockingError & + // This is used by dashboard/container to show filters/queries on the panel + PublishesUnifiedSearch & + // Let the container know the loading state + PublishesDataLoading & + // Let the container know when the rendering has completed rendering + PublishesRendered & + // Let the container know the used data views + PublishesDataViews & + // Let the container operate on panel title/description + PublishesWritablePanelTitle & + PublishesWritablePanelDescription & + // This embeddable can narrow down specific triggers usage + HasSupportedTriggers & + PublishesDisabledActionIds & + // Offers methods to operate from/on the linked saved object + HasInPlaceLibraryTransforms & + HasLibraryTransforms<LensRuntimeState> & + // Let the container know the view mode + PublishesViewMode & + // forward the parentApi, note that will be exposed only if it satisfy the PresentationContainer interface + Partial<HasParentApi<PresentationContainer>> & + // Let the container know the saved object id + PublishesSavedObjectId & + // Lens specific API methods: + // Let the container know when the data has been loaded/updated + LensInspectorAdapters & + LensRequestHandlersProps & + LensApiCallbacks +>; + +// This is an API only used internally to the embeddable but not exported elsewhere +// there's some overlapping between this and the LensApi but they are shared references +export type LensInternalApi = Simplify< + Pick<IntegrationCallbacks, 'updateAttributes' | 'updateOverrides'> & + PublishesDataViews & { + attributes$: PublishingSubject<LensRuntimeState['attributes']>; + overrides$: PublishingSubject<LensOverrides['overrides']>; + disableTriggers$: PublishingSubject<LensPanelProps['disableTriggers']>; + dataLoading$: PublishingSubject<boolean | undefined>; + hasRenderCompleted$: PublishingSubject<boolean>; + isNewlyCreated$: PublishingSubject<boolean>; + setAsCreated: () => void; + dispatchRenderStart: () => void; + dispatchRenderComplete: () => void; + dispatchError: () => void; + updateDataLoading: (newDataLoading: boolean | undefined) => void; + expressionParams$: PublishingSubject<ExpressionWrapperProps | null>; + updateExpressionParams: (newParams: ExpressionWrapperProps | null) => void; + expressionAbortController$: PublishingSubject<AbortController | undefined>; + updateAbortController: (newAbortController: AbortController | undefined) => void; + renderCount$: PublishingSubject<number>; + updateDataViews: (dataViews: DataView[] | undefined) => void; + messages$: PublishingSubject<UserMessage[]>; + updateMessages: (newMessages: UserMessage[]) => void; + validationMessages$: PublishingSubject<UserMessage[]>; + updateValidationMessages: (newMessages: UserMessage[]) => void; + resetAllMessages: () => void; + getDisplayOptions: () => VisualizationDisplayOptions; + } +>; + +export interface ExpressionWrapperProps { + ExpressionRenderer: ReactExpressionRendererType; + expression: string | null; + variables?: Record<string, unknown>; + interactive?: boolean; + searchContext: ExecutionContextSearch; + searchSessionId?: string; + handleEvent: (event: ExpressionRendererEvent) => void; + onData$: ( + data: unknown, + inspectorAdapters?: Partial<DefaultInspectorAdapters> | undefined + ) => void; + onRender$: (count: number) => void; + renderMode?: RenderMode; + syncColors?: boolean; + syncTooltips?: boolean; + syncCursor?: boolean; + hasCompatibleActions?: ReactExpressionRendererProps['hasCompatibleActions']; + getCompatibleCellValueActions?: ReactExpressionRendererProps['getCompatibleCellValueActions']; + style?: React.CSSProperties; + className?: string; + addUserMessages: (messages: UserMessage[]) => void; + onRuntimeError: (error: Error) => void; + executionContext?: KibanaExecutionContext; + lensInspector: LensInspector; + noPadding?: boolean; + abortController?: AbortController; +} + +export type GetStateType = () => LensRuntimeState; + +/** + * Custom Lens component exported by the plugin + * For better DX of Lens component consumers, expose a typed version of the serialized state + */ + +/** Utility function to build typed version for each chart */ +type TypedLensAttributes<TVisType, TVisState> = Simplify< + Omit<LensDocument, 'savedObjectId' | 'type' | 'state' | 'visualizationType'> & { + visualizationType: TVisType; + state: Simplify< + Omit<LensDocument['state'], 'datasourceStates' | 'visualization'> & { + datasourceStates: { + formBased?: FormBasedPersistedState; + textBased?: TextBasedPersistedState; + }; + visualization: TVisState; + } + >; + } +>; + +/** + * Type-safe variant of by value embeddable input for Lens. + * This can be used to hardcode certain Lens chart configurations within another app. + */ +export type TypedLensSerializedState = Simplify< + Omit<LensSerializedState, 'attributes'> & { + attributes: + | TypedLensAttributes<'lnsXY', XYState> + | TypedLensAttributes<'lnsPie', PieVisualizationState> + | TypedLensAttributes<'lnsHeatmap', HeatmapVisualizationState> + | TypedLensAttributes<'lnsGauge', GaugeVisualizationState> + | TypedLensAttributes<'lnsDatatable', DatatableVisualizationState> + | TypedLensAttributes<'lnsLegacyMetric', LegacyMetricState> + | TypedLensAttributes<'lnsMetric', MetricVisualizationState> + | TypedLensAttributes<string, unknown>; + } +>; + +/** + * Backward compatibility types + */ +export type LensByValueInput = Omit<LensRendererPrivateProps, 'savedObjectId'>; +export type LensByReferenceInput = Omit<LensRendererPrivateProps, 'attributes'>; +export type TypedLensByValueInput = Omit<LensRendererProps, 'savedObjectId'>; +export type LensEmbeddableInput = LensByValueInput | LensByReferenceInput; +export type LensEmbeddableOutput = LensApi; diff --git a/x-pack/plugins/lens/public/react_embeddable/user_messages/api.ts b/x-pack/plugins/lens/public/react_embeddable/user_messages/api.ts new file mode 100644 index 000000000000..90061cfb7c2f --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/api.ts @@ -0,0 +1,288 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SpacesApi } from '@kbn/spaces-plugin/public'; +import { Adapters } from '@kbn/inspector-plugin/common'; +import { BehaviorSubject } from 'rxjs'; +import { + filterAndSortUserMessages, + getApplicationUserMessages, + handleMessageOverwriteFromConsumer, +} from '../../app_plugin/get_application_user_messages'; +import { getDatasourceLayers } from '../../state_management/utils'; +import { + UserMessagesGetter, + UserMessage, + FramePublicAPI, + SharingSavedObjectProps, +} from '../../types'; +import { + getActiveDatasourceIdFromDoc, + getActiveVisualizationIdFromDoc, + getInitialDataViewsObject, +} from '../../utils'; +import { + LensPublicCallbacks, + LensEmbeddableStartServices, + VisualizationContext, + VisualizationContextHelper, + LensApi, + LensInternalApi, +} from '../types'; +import { getLegacyURLConflictsMessage, hasLegacyURLConflict } from './checks'; +import { getSearchWarningMessages } from '../../utils'; +import { addLog } from '../logger'; + +function getUpdatedState( + getVisualizationContext: VisualizationContextHelper['getVisualizationContext'], + visualizationMap: LensEmbeddableStartServices['visualizationMap'], + datasourceMap: LensEmbeddableStartServices['datasourceMap'] +) { + const { + doc, + mergedSearchContext, + indexPatterns, + indexPatternRefs, + activeVisualizationState, + activeDatasourceState, + activeData, + } = getVisualizationContext(); + const activeVisualizationId = getActiveVisualizationIdFromDoc(doc); + const activeDatasourceId = getActiveDatasourceIdFromDoc(doc); + const activeDatasource = activeDatasourceId ? datasourceMap[activeDatasourceId] : null; + const activeVisualization = activeVisualizationId + ? visualizationMap[activeVisualizationId] + : undefined; + const dataViewObject = getInitialDataViewsObject(indexPatterns, indexPatternRefs); + return { + doc, + mergedSearchContext, + activeDatasource, + activeVisualization, + activeVisualizationId, + dataViewObject, + activeVisualizationState, + activeDatasourceState, + activeDatasourceId, + activeData, + }; +} + +function getWarningMessages( + { + activeDatasource, + activeDatasourceId, + activeDatasourceState, + }: ReturnType<typeof getUpdatedState>, + adapters: Adapters, + data: LensEmbeddableStartServices['data'] +) { + if (!activeDatasource || !activeDatasourceId || !adapters?.requests) { + return []; + } + + const requestWarnings = getSearchWarningMessages( + adapters.requests, + activeDatasource, + activeDatasourceState, + { + searchService: data.search, + } + ); + + return requestWarnings; +} + +export function buildUserMessagesHelpers( + api: LensApi, + internalApi: LensInternalApi, + getVisualizationContext: () => VisualizationContext, + { coreStart, data, visualizationMap, datasourceMap }: LensEmbeddableStartServices, + onBeforeBadgesRender: LensPublicCallbacks['onBeforeBadgesRender'], + spaces?: SpacesApi, + metaInfo?: SharingSavedObjectProps +): { + getUserMessages: UserMessagesGetter; + addUserMessages: (messages: UserMessage[]) => void; + updateWarnings: () => void; + updateMessages: (messages: UserMessage[]) => void; + resetMessages: () => void; + updateBlockingErrors: (blockingMessages: UserMessage[] | Error) => void; + updateValidationErrors: (messages: UserMessage[]) => void; +} { + let runtimeUserMessages: Record<string, UserMessage> = {}; + const addUserMessages = (messages: UserMessage[]) => { + if (messages.length) { + addLog(`addUserMessages: "${messages.map(({ uniqueId }) => uniqueId).join('", "')}"`); + } + for (const message of messages) { + runtimeUserMessages[message.uniqueId] = message; + } + }; + + const resetMessages = () => { + runtimeUserMessages = {}; + internalApi.resetAllMessages(); + }; + + const getUserMessages: UserMessagesGetter = (locationId, filters) => { + const { + doc, + activeVisualizationState, + activeVisualization, + activeVisualizationId, + activeDatasource, + activeDatasourceState, + activeDatasourceId, + dataViewObject, + mergedSearchContext, + activeData, + } = getUpdatedState(getVisualizationContext, visualizationMap, datasourceMap); + const userMessages: UserMessage[] = []; + + userMessages.push( + ...getApplicationUserMessages({ + visualizationType: doc?.visualizationType, + visualizationState: { + state: activeVisualizationState, + activeId: activeVisualizationId, + }, + visualization: activeVisualization, + activeDatasource, + activeDatasourceState: { + isLoading: !activeDatasourceState, + state: activeDatasourceState, + }, + dataViews: dataViewObject, + core: coreStart, + }) + ); + + if (!doc || !activeDatasourceState || !activeVisualizationState) { + return userMessages; + } + + const framePublicAPI: FramePublicAPI = { + dataViews: dataViewObject, + datasourceLayers: getDatasourceLayers( + { + [activeDatasourceId!]: { + isLoading: !activeDatasourceState, + state: activeDatasourceState, + }, + }, + datasourceMap, + dataViewObject.indexPatterns + ), + query: doc.state.query, + filters: mergedSearchContext.filters ?? [], + dateRange: { + fromDate: mergedSearchContext.timeRange?.from ?? '', + toDate: mergedSearchContext.timeRange?.to ?? '', + }, + absDateRange: { + fromDate: mergedSearchContext.timeRange?.from ?? '', + toDate: mergedSearchContext.timeRange?.to ?? '', + }, + activeData, + }; + + if (hasLegacyURLConflict(metaInfo, spaces)) { + userMessages.push(getLegacyURLConflictsMessage(metaInfo!, spaces!)); + } + + userMessages.push( + ...(activeDatasource?.getUserMessages(activeDatasourceState, { + setState: () => {}, + frame: framePublicAPI, + visualizationInfo: activeVisualization?.getVisualizationInfo?.( + activeVisualizationState, + framePublicAPI + ), + }) ?? []), + ...(activeVisualization?.getUserMessages?.(activeVisualizationState, { + frame: framePublicAPI, + }) ?? []) + ); + + return handleMessageOverwriteFromConsumer( + filterAndSortUserMessages( + userMessages.concat(Object.values(runtimeUserMessages)), + locationId, + filters ?? {} + ), + onBeforeBadgesRender + ); + }; + + return { + addUserMessages, + resetMessages, + getUserMessages, + /** + * Here pass all the messages that comes directly from the Lens validation/info system + * who includes: + * * configuration errors (i.e. missing fields) + * * warning messages (badge related) + * * info messages (badge related) + */ + updateMessages: (messages: UserMessage[]) => { + // update the messages only if something changed + const existingMessages = new Set( + internalApi.messages$.getValue().map(({ uniqueId }) => uniqueId) + ); + if ( + existingMessages.size !== messages.length || + messages.some(({ uniqueId }) => !existingMessages.has(uniqueId)) + ) { + internalApi.updateMessages(messages); + } + }, + updateValidationErrors: (messages: UserMessage[]) => { + addLog( + `Validation error: ${ + messages.length ? messages.map(({ uniqueId }) => uniqueId).join(', ') : 'No errors' + }` + ); + internalApi.updateValidationMessages(messages); + }, + /** + * This type of errors are those who need to be rendered in the embeddable native error panel + * like runtime errors. + */ + updateBlockingErrors: (blockingMessages: UserMessage[] | Error) => { + const error = + blockingMessages instanceof Error + ? blockingMessages + : blockingMessages.length + ? new Error( + typeof blockingMessages[0].longMessage === 'string' && blockingMessages[0].longMessage + ? blockingMessages[0].longMessage + : blockingMessages[0].shortMessage + ) + : undefined; + + if (error) { + addLog(`Blocking error: ${error?.message}`); + } + + if (error?.message !== api.blockingError.getValue()?.message) { + const finalError = error?.message === '' ? undefined : error; + (api.blockingError as BehaviorSubject<Error | undefined>).next(finalError); + } + }, + updateWarnings: () => { + addUserMessages( + getWarningMessages( + getUpdatedState(getVisualizationContext, visualizationMap, datasourceMap), + api.adapters$.getValue(), + data + ) + ); + }, + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/user_messages/checks.tsx b/x-pack/plugins/lens/public/react_embeddable/user_messages/checks.tsx new file mode 100644 index 000000000000..50250b31fdc7 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/checks.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type { SpacesApi } from '@kbn/spaces-plugin/public'; +import React from 'react'; +import { DOC_TYPE } from '../../../common/constants'; +import type { + IndexPatternMap, + IndexPatternRef, + SharingSavedObjectProps, + UserMessage, +} from '../../types'; +import type { LensApi } from '../types'; +import type { MergedSearchContext } from '../expressions/merged_search_context'; +import { MISSING_TIME_RANGE_ON_EMBEDDABLE, URL_CONFLICT } from '../../user_messages_ids'; + +export function hasLegacyURLConflict(metaInfo?: SharingSavedObjectProps, spaces?: SpacesApi) { + return metaInfo?.outcome === 'conflict' && spaces?.ui?.components?.getEmbeddableLegacyUrlConflict; +} + +export function getLegacyURLConflictsMessage( + metaInfo: SharingSavedObjectProps, + spaces: SpacesApi +): UserMessage { + const LegacyURLConfig = spaces.ui.components.getEmbeddableLegacyUrlConflict; + return { + uniqueId: URL_CONFLICT, + severity: 'error', + displayLocations: [{ id: 'visualization' }], + shortMessage: i18n.translate('xpack.lens.legacyURLConflict.shortMessage', { + defaultMessage: `You've encountered a URL conflict`, + }), + longMessage: <LegacyURLConfig targetType={DOC_TYPE} sourceId={metaInfo.sourceId!} />, + fixableInEditor: false, + }; +} + +export function isSearchContextIncompatibleWithDataViews( + api: LensApi, + context: { type?: string; id?: string } | undefined, + searchContext: MergedSearchContext, + indexPatternRefs: IndexPatternRef[], + indexPatterns: IndexPatternMap +) { + return ( + !api.isTextBasedLanguage() && + searchContext.timeRange == null && + indexPatternRefs.some(({ id }) => { + const indexPattern = indexPatterns[id]; + return indexPattern?.timeFieldName && indexPattern.getFieldByName(indexPattern.timeFieldName); + }) + ); +} + +export function getSearchContextIncompatibleMessage(): UserMessage { + return { + uniqueId: MISSING_TIME_RANGE_ON_EMBEDDABLE, + severity: 'error', + fixableInEditor: false, + displayLocations: [{ id: 'visualization' }], + shortMessage: i18n.translate('xpack.lens.missingTimeRangeParam.shortMessage', { + defaultMessage: `Missing timeRange property`, + }), + longMessage: i18n.translate('xpack.lens.missingTimeRangeParam.longMessage', { + defaultMessage: `The timeRange property is required for the given configuration`, + }), + }; +} diff --git a/x-pack/plugins/lens/public/react_embeddable/user_messages/container.tsx b/x-pack/plugins/lens/public/react_embeddable/user_messages/container.tsx new file mode 100644 index 000000000000..451de837e96e --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/container.tsx @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/react'; +import React from 'react'; +import type { UserMessage } from '../../types'; +import { VisualizationErrorPanel } from './error_panel'; +import { EmbeddableFeatureBadge } from './info_badges'; +import { MessagesPopover } from './message_popover'; + +export function UserMessages({ + blockingErrors, + warningOrErrors, + infoMessages, + canEdit, +}: { + canEdit: boolean; + blockingErrors: UserMessage[]; + warningOrErrors: UserMessage[]; + infoMessages: UserMessage[]; +}) { + if (!blockingErrors.length && !warningOrErrors.length && !infoMessages.length) { + return null; + } + return ( + <> + <VisualizationErrorPanel errors={blockingErrors} canEdit={canEdit} /> + <div + css={css({ + position: 'absolute', + zIndex: 2, + left: 0, + bottom: 0, + })} + > + <MessagesPopover messages={warningOrErrors} /> + <EmbeddableFeatureBadge messages={infoMessages} /> + </div> + </> + ); +} diff --git a/x-pack/plugins/lens/public/react_embeddable/user_messages/error_panel.tsx b/x-pack/plugins/lens/public/react_embeddable/user_messages/error_panel.tsx new file mode 100644 index 000000000000..ee050382914c --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/error_panel.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 { EuiEmptyPrompt } from '@elastic/eui'; +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { UserMessage } from '../../types'; +import { getLongMessage } from '../../user_messages_utils'; + +export function VisualizationErrorPanel({ + errors, + canEdit, +}: { + errors: UserMessage[]; + canEdit: boolean; +}) { + if (!errors.length) { + return null; + } + const showMore = errors.length > 1; + const canFixInLens = canEdit && errors.some(({ fixableInEditor }) => fixableInEditor); + return ( + <div className="lnsEmbeddedError"> + <EuiEmptyPrompt + iconType="warning" + iconColor="danger" + data-test-subj="embeddable-lens-failure" + body={ + <> + {errors.length ? ( + <> + <p>{getLongMessage(errors[0]) || errors[0].shortMessage}</p> + {showMore && !canFixInLens ? ( + <p> + <FormattedMessage + id="xpack.lens.moreErrors" + defaultMessage="Edit in Lens editor to see more errors" + /> + </p> + ) : null} + {canFixInLens ? ( + <p> + <FormattedMessage + id="xpack.lens.fixErrors" + defaultMessage="Edit in Lens editor to fix the error" + /> + </p> + ) : null} + </> + ) : ( + <p> + <FormattedMessage + id="xpack.lens.failure" + defaultMessage="Visualization couldn't be displayed" + /> + </p> + )} + </> + } + /> + </div> + ); +} diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_info_badges.scss b/x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.scss similarity index 62% rename from x-pack/plugins/lens/public/embeddable/embeddable_info_badges.scss rename to x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.scss index 55407855b49f..7435808095a1 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_info_badges.scss +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.scss @@ -1,4 +1,4 @@ -.lnsEmbeddablePanelFeatureList { +.lnsPanelFeatureList { max-height: $euiSize * 20; @include euiYScroll; } diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_info_badges.test.tsx b/x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.test.tsx similarity index 97% rename from x-pack/plugins/lens/public/embeddable/embeddable_info_badges.test.tsx rename to x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.test.tsx index b70b102a7848..ef3ee40e17d1 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_info_badges.test.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.test.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import '@testing-library/jest-dom'; import userEvent from '@testing-library/user-event'; -import { EmbeddableFeatureBadge } from './embeddable_info_badges'; -import { UserMessage } from '../types'; +import { EmbeddableFeatureBadge } from './info_badges'; +import { UserMessage } from '../../types'; describe('EmbeddableFeatureBadge', () => { async function renderPopup(messages: UserMessage[], count: number = messages.length) { diff --git a/x-pack/plugins/lens/public/embeddable/embeddable_info_badges.tsx b/x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.tsx similarity index 89% rename from x-pack/plugins/lens/public/embeddable/embeddable_info_badges.tsx rename to x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.tsx index 18cff3f2ac90..5b120625b662 100644 --- a/x-pack/plugins/lens/public/embeddable/embeddable_info_badges.tsx +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/info_badges.tsx @@ -18,9 +18,9 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; import { useState } from 'react'; -import type { UserMessage } from '../types'; -import './embeddable_info_badges.scss'; -import { getLongMessage } from '../user_messages_utils'; +import type { UserMessage } from '../../types'; +import './info_badges.scss'; +import { getLongMessage } from '../../user_messages_utils'; export const EmbeddableFeatureBadge = ({ messages }: { messages: UserMessage[] }) => { const { euiTheme } = useEuiTheme(); @@ -31,7 +31,7 @@ export const EmbeddableFeatureBadge = ({ messages }: { messages: UserMessage[] } if (!messages.length) { return null; } - const iconTitle = i18n.translate('xpack.lens.embeddable.featureBadge.iconDescription', { + const iconTitle = i18n.translate('xpack.lens.featureBadge.iconDescription', { defaultMessage: `{count} visualization {count, plural, one {modifier} other {modifiers}}`, values: { count: messages.length, @@ -51,7 +51,7 @@ export const EmbeddableFeatureBadge = ({ messages }: { messages: UserMessage[] } <EuiToolTip content={iconTitle}> <EuiButtonEmpty data-test-subj="lns-feature-badges-trigger" - className="lnsEmbeddablePanelFeatureList_button" + className="lnsPanelFeatureList_button" color={'text'} onClick={onButtonClick} title={iconTitle} @@ -64,6 +64,9 @@ export const EmbeddableFeatureBadge = ({ messages }: { messages: UserMessage[] } .euiButtonEmpty__content { gap: ${euiTheme.size.xs}; } + &:hover { + color: ${euiTheme.colors.text}; + } `} iconType="wrench" > @@ -98,7 +101,7 @@ export const EmbeddableFeatureBadge = ({ messages }: { messages: UserMessage[] } <EuiTitle size="xxs" css={css`color=${euiTheme.colors.title}`}> <h3>{shortMessage}</h3> </EuiTitle> - <ul className="lnsEmbeddablePanelFeatureList"> + <ul className="lnsPanelFeatureList"> {messageGroup.map((message, i) => ( <Fragment key={`${uniqueId}-${i}`}>{getLongMessage(message)}</Fragment> ))} diff --git a/x-pack/plugins/lens/public/react_embeddable/user_messages/message_popover.tsx b/x-pack/plugins/lens/public/react_embeddable/user_messages/message_popover.tsx new file mode 100644 index 000000000000..a6359bd683d1 --- /dev/null +++ b/x-pack/plugins/lens/public/react_embeddable/user_messages/message_popover.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEuiTheme, useEuiFontSize } from '@elastic/eui'; +import { css } from '@emotion/react'; + +import React from 'react'; +import { MessageList } from '../../editor_frame_service/editor_frame/workspace_panel/message_list'; +import { UserMessage } from '../../types'; + +export const MessagesPopover = ({ messages }: { messages: UserMessage[] }) => { + const { euiTheme } = useEuiTheme(); + const xsFontSize = useEuiFontSize('xs').fontSize; + + if (!messages.length) { + return null; + } + + return ( + <MessageList + messages={messages} + customButtonStyles={css` + block-size: ${euiTheme.size.l}; + font-size: ${xsFontSize}; + padding: 0 ${euiTheme.size.xs}; + & > * { + gap: ${euiTheme.size.xs}; + } + `} + /> + ); +}; diff --git a/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap b/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap index a1ae0da67680..8af3d61bf668 100644 --- a/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap +++ b/x-pack/plugins/lens/public/state_management/__snapshots__/load_initial.test.tsx.snap @@ -28,7 +28,6 @@ Object { "persistedDoc": Object { "exactMatchDoc": Object { "attributes": Object { - "expression": "definitely a valid expression", "references": Array [ Object { "id": "1", @@ -39,7 +38,10 @@ Object { "savedObjectId": "1234", "state": Object { "datasourceStates": Object { - "testDatasource": "datasource", + "testDatasource": Object { + "isLoading": false, + "state": Object {}, + }, }, "filters": Array [ Object { @@ -53,7 +55,10 @@ Object { }, }, ], - "query": "kuery", + "query": Object { + "language": "kuery", + "query": "test", + }, "visualization": Object {}, }, "title": "An extremely cool default document!", diff --git a/x-pack/plugins/lens/public/state_management/init_middleware/index.ts b/x-pack/plugins/lens/public/state_management/init_middleware/index.ts index 0858d9d8af78..b0011c3c822e 100644 --- a/x-pack/plugins/lens/public/state_management/init_middleware/index.ts +++ b/x-pack/plugins/lens/public/state_management/init_middleware/index.ts @@ -12,6 +12,7 @@ import { loadInitial as loadInitialAction } from '..'; import { loadInitial } from './load_initial'; import { readFromStorage } from '../../settings_storage'; import { AUTO_APPLY_DISABLED_STORAGE_KEY } from '../../editor_frame_service/editor_frame/workspace_panel/workspace_panel_wrapper'; +import { type InitialAppState } from '../lens_slice'; const autoApplyDisabled = () => { return readFromStorage(new Storage(localStorage), AUTO_APPLY_DISABLED_STORAGE_KEY) === 'true'; @@ -20,7 +21,7 @@ const autoApplyDisabled = () => { export const initMiddleware = (storeDeps: LensStoreDeps) => (store: MiddlewareAPI) => { return (next: Dispatch) => (action: PayloadAction) => { if (loadInitialAction.match(action)) { - return loadInitial(store, storeDeps, action.payload, autoApplyDisabled()); + return loadInitial(store, storeDeps, action.payload as InitialAppState, autoApplyDisabled()); } next(action); }; diff --git a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts index 606ede8cd268..458285096f7e 100644 --- a/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts +++ b/x-pack/plugins/lens/public/state_management/init_middleware/load_initial.ts @@ -9,51 +9,55 @@ import { cloneDeep } from 'lodash'; import { MiddlewareAPI } from '@reduxjs/toolkit'; import { i18n } from '@kbn/i18n'; import { History } from 'history'; -import { setState, initExisting, initEmpty, LensStoreDeps } from '..'; -import { disableAutoApply, getPreloadedState } from '../lens_slice'; +import { setState, initExisting, initEmpty, LensStoreDeps, LensAppState } from '..'; +import { type InitialAppState, disableAutoApply, getPreloadedState } from '../lens_slice'; import { SharingSavedObjectProps } from '../../types'; -import { LensEmbeddableInput, LensByReferenceInput } from '../../embeddable/embeddable'; import { getInitialDatasourceId, getInitialDataViewsObject } from '../../utils'; import { initializeSources } from '../../editor_frame_service/editor_frame'; import { LensAppServices } from '../../app_plugin/types'; import { getEditPath, getFullPath, LENS_EMBEDDABLE_TYPE } from '../../../common/constants'; -import { Document } from '../../persistence'; +import { LensDocument } from '../../persistence'; +import { LensSerializedState } from '../../react_embeddable/types'; -export const getPersisted = async ({ +interface PersistedDoc { + doc: LensDocument; + sharingSavedObjectProps: Omit<SharingSavedObjectProps, 'sourceId'>; + managed: boolean; +} + +/** + * This function returns a Saved object from a either a by reference or by value input + */ +export const getFromPreloaded = async ({ initialInput, lensServices, history, }: { - initialInput: LensEmbeddableInput; + initialInput: LensSerializedState; lensServices: Pick<LensAppServices, 'attributeService' | 'notifications' | 'spaces' | 'http'>; history?: History<unknown>; -}): Promise< - | { - doc: Document; - sharingSavedObjectProps: Omit<SharingSavedObjectProps, 'sourceId'>; - managed: boolean; - } - | undefined -> => { +}): Promise<PersistedDoc | undefined> => { const { notifications, spaces, attributeService } = lensServices; - let doc: Document; + let doc: LensDocument; try { - const result = await attributeService.unwrapAttributes(initialInput); - if (!result) { + const docFromSavedObject = await (initialInput.savedObjectId + ? attributeService.loadFromLibrary(initialInput.savedObjectId) + : undefined); + if (!docFromSavedObject) { return { + // @TODO: it would be nice to address this type checks once for all doc: { - ...initialInput, + ...initialInput.attributes, type: LENS_EMBEDDABLE_TYPE, - } as unknown as Document, + } as LensDocument, sharingSavedObjectProps: { outcome: 'exactMatch', }, managed: false, }; } - const { metaInfo, attributes } = result; - const sharingSavedObjectProps = metaInfo?.sharingSavedObjectProps; + const { sharingSavedObjectProps, attributes, managed } = docFromSavedObject; if (spaces && sharingSavedObjectProps?.outcome === 'aliasMatch' && history) { // We found this object by a legacy URL alias from its old ID; redirect the user to the page with its new ID, preserving any URL hash const newObjectId = sharingSavedObjectProps.aliasTargetId!; // This is always defined if outcome === 'aliasMatch' @@ -80,7 +84,7 @@ export const getPersisted = async ({ aliasTargetId: sharingSavedObjectProps?.aliasTargetId, outcome: sharingSavedObjectProps?.outcome, }, - managed: Boolean(metaInfo?.managed), + managed: Boolean(managed), }; } catch (e) { notifications.toasts.addDanger( @@ -91,30 +95,242 @@ export const getPersisted = async ({ } }; -export function loadInitial( +interface LoaderSharedArgs { + visualizationMap: LensStoreDeps['visualizationMap']; + datasourceMap: LensStoreDeps['datasourceMap']; + initialContext: LensStoreDeps['initialContext']; + dataViews: LensStoreDeps['lensServices']['dataViews']; + storage: LensStoreDeps['lensServices']['storage']; + eventAnnotationService: LensStoreDeps['lensServices']['eventAnnotationService']; + defaultIndexPatternId: string; +} + +type PreloadedState = Omit< + LensAppState, + 'resolvedDateRange' | 'searchSessionId' | 'isLinkedToOriginatingApp' +>; + +async function loadFromLocatorState( + store: MiddlewareAPI, + initialState: NonNullable<LensStoreDeps['initialStateFromLocator']>, + loaderSharedArgs: LoaderSharedArgs, + { notifications, data }: LensStoreDeps['lensServices'], + emptyState: PreloadedState, + autoApplyDisabled: boolean +) { + const { lens } = store.getState(); + const locatorReferences = 'references' in initialState ? initialState.references : undefined; + + const { + datasourceStates, + visualizationState, + indexPatterns, + indexPatternRefs, + annotationGroups, + } = await initializeSources( + { + visualizationState: emptyState.visualization, + datasourceStates: emptyState.datasourceStates, + adHocDataViews: lens.persistedDoc?.state.adHocDataViews || initialState.dataViewSpecs, + references: locatorReferences, + ...loaderSharedArgs, + }, + { + isFullEditor: true, + } + ); + const currentSessionId = initialState?.searchSessionId || data.search.session.getSessionId(); + store.dispatch( + initExisting({ + isSaveable: true, + filters: initialState.filters || data.query.filterManager.getFilters(), + query: initialState.query || emptyState.query, + searchSessionId: currentSessionId, + activeDatasourceId: emptyState.activeDatasourceId, + visualization: { + activeId: emptyState.visualization.activeId, + state: visualizationState, + }, + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), + datasourceStates: Object.entries(datasourceStates).reduce( + (state, [datasourceId, datasourceState]) => ({ + ...state, + [datasourceId]: { + ...datasourceState, + isLoading: false, + }, + }), + {} + ), + isLoading: false, + annotationGroups, + }) + ); + + if (autoApplyDisabled) { + store.dispatch(disableAutoApply()); + } +} + +async function loadFromEmptyState( + store: MiddlewareAPI, + emptyState: PreloadedState, + loaderSharedArgs: LoaderSharedArgs, + { data }: LensStoreDeps['lensServices'], + activeDatasourceId: string | undefined, + autoApplyDisabled: boolean +) { + const { lens } = store.getState(); + const { datasourceStates, indexPatterns, indexPatternRefs } = await initializeSources( + { + visualizationState: lens.visualization, + datasourceStates: lens.datasourceStates, + adHocDataViews: lens.persistedDoc?.state.adHocDataViews, + ...loaderSharedArgs, + }, + { + isFullEditor: true, + } + ); + + store.dispatch( + initEmpty({ + newState: { + ...emptyState, + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), + searchSessionId: data.search.session.getSessionId() || data.search.session.start(), + ...(activeDatasourceId && { activeDatasourceId }), + datasourceStates: Object.entries(datasourceStates).reduce( + (state, [datasourceId, datasourceState]) => ({ + ...state, + [datasourceId]: { + ...datasourceState, + isLoading: false, + }, + }), + {} + ), + isLoading: false, + }, + initialContext: loaderSharedArgs.initialContext, + }) + ); + if (autoApplyDisabled) { + store.dispatch(disableAutoApply()); + } +} + +async function loadFromSavedObject( + store: MiddlewareAPI, + savedObjectId: string | undefined, + persisted: PersistedDoc, + loaderSharedArgs: LoaderSharedArgs, + { data, chrome }: LensStoreDeps['lensServices'], + autoApplyDisabled: boolean, + inlineEditing?: boolean +) { + const { doc, sharingSavedObjectProps, managed } = persisted; + if (savedObjectId) { + chrome.recentlyAccessed.add(getFullPath(savedObjectId), doc.title, savedObjectId); + } + + const docDatasourceStates = Object.entries(doc.state.datasourceStates).reduce( + (stateMap, [datasourceId, datasourceState]) => ({ + ...stateMap, + [datasourceId]: { + isLoading: true, + state: datasourceState, + }, + }), + {} + ); + + // when the embeddable is initialized from the dashboard we don't want to inject the filters + // as this will replace the parent application filters (such as a dashboard) + if (!inlineEditing) { + const filters = data.query.filterManager.inject(doc.state.filters, doc.references); + // Don't overwrite any pinned filters + data.query.filterManager.setAppFilters(filters); + } + + const docVisualizationState = { + activeId: doc.visualizationType, + state: doc.state.visualization, + }; + const { + datasourceStates, + visualizationState, + indexPatterns, + indexPatternRefs, + annotationGroups, + } = await initializeSources( + { + visualizationState: docVisualizationState, + datasourceStates: docDatasourceStates, + references: [...doc.references, ...(doc.state.internalReferences || [])], + adHocDataViews: doc.state.adHocDataViews, + ...loaderSharedArgs, + }, + { isFullEditor: true } + ); + const currentSessionId = data.search.session.getSessionId(); + store.dispatch( + initExisting({ + isSaveable: true, + sharingSavedObjectProps, + filters: data.query.filterManager.getFilters(), + query: doc.state.query, + searchSessionId: + !savedObjectId && currentSessionId + ? currentSessionId + : !inlineEditing + ? data.search.session.start() + : undefined, + persistedDoc: doc, + activeDatasourceId: getInitialDatasourceId(loaderSharedArgs.datasourceMap, doc), + visualization: { + activeId: doc.visualizationType, + state: visualizationState, + }, + dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), + datasourceStates: Object.entries(datasourceStates).reduce( + (state, [datasourceId, datasourceState]) => ({ + ...state, + [datasourceId]: { + ...datasourceState, + isLoading: false, + }, + }), + {} + ), + isLoading: false, + annotationGroups, + managed, + }) + ); + + if (autoApplyDisabled) { + store.dispatch(disableAutoApply()); + } +} + +export async function loadInitial( store: MiddlewareAPI, storeDeps: LensStoreDeps, - { - redirectCallback, - initialInput, - history, - inlineEditing, - }: { - redirectCallback?: (savedObjectId?: string) => void; - initialInput?: LensEmbeddableInput; - history?: History<unknown>; - inlineEditing?: boolean; - }, + { redirectCallback, initialInput, history, inlineEditing }: InitialAppState, autoApplyDisabled: boolean ) { const { lensServices, datasourceMap, initialContext, initialStateFromLocator, visualizationMap } = storeDeps; const { resolvedDateRange, searchSessionId, isLinkedToOriginatingApp, ...emptyState } = getPreloadedState(storeDeps); - const { attributeService, notifications, data } = lensServices; + const { notifications, data } = lensServices; const { lens } = store.getState(); - const loaderSharedArgs = { + const loaderSharedArgs: LoaderSharedArgs = { + visualizationMap, + initialContext, + datasourceMap, dataViews: lensServices.dataViews, storage: lensServices.storage, eventAnnotationService: lensServices.eventAnnotationService, @@ -144,79 +360,27 @@ export function loadInitial( // URL Reporting is using the locator params but also passing the savedObjectId // so be sure to not go here as there's no full snapshot URL if (!initialInput) { - const locatorReferences = - 'references' in initialStateFromLocator ? initialStateFromLocator.references : undefined; - - return initializeSources( - { - datasourceMap, - visualizationMap, - visualizationState: emptyState.visualization, - datasourceStates: emptyState.datasourceStates, - initialContext, - adHocDataViews: - lens.persistedDoc?.state.adHocDataViews || initialStateFromLocator.dataViewSpecs, - references: locatorReferences, - ...loaderSharedArgs, - }, - { - isFullEditor: true, - } - ) - .then( - ({ - datasourceStates, - visualizationState, - indexPatterns, - indexPatternRefs, - annotationGroups, - }) => { - const currentSessionId = - initialStateFromLocator?.searchSessionId || data.search.session.getSessionId(); - store.dispatch( - initExisting({ - isSaveable: true, - filters: initialStateFromLocator.filters || data.query.filterManager.getFilters(), - query: initialStateFromLocator.query || emptyState.query, - searchSessionId: currentSessionId, - activeDatasourceId: emptyState.activeDatasourceId, - visualization: { - activeId: emptyState.visualization.activeId, - state: visualizationState, - }, - dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), - datasourceStates: Object.entries(datasourceStates).reduce( - (state, [datasourceId, datasourceState]) => ({ - ...state, - [datasourceId]: { - ...datasourceState, - isLoading: false, - }, - }), - {} - ), - isLoading: false, - annotationGroups, - }) - ); - - if (autoApplyDisabled) { - store.dispatch(disableAutoApply()); - } - } - ) - .catch((e: { message: string }) => { - notifications.toasts.addDanger({ - title: e.message, - }); + try { + return loadFromLocatorState( + store, + initialStateFromLocator, + loaderSharedArgs, + lensServices, + emptyState, + autoApplyDisabled + ); + } catch ({ message }) { + notifications.toasts.addDanger({ + title: message, }); + return; + } } } if ( !initialInput || - (attributeService.inputIsRefType(initialInput) && - initialInput.savedObjectId === lens.persistedDoc?.savedObjectId) + (initialInput.savedObjectId && initialInput.savedObjectId === lens.persistedDoc?.savedObjectId) ) { const newFilters = initialContext && 'searchFilters' in initialContext && initialContext.searchFilters @@ -226,179 +390,57 @@ export function loadInitial( if (newFilters) { data.query.filterManager.setAppFilters(newFilters); } - - return initializeSources( - { - datasourceMap, - visualizationMap, - visualizationState: lens.visualization, - datasourceStates: lens.datasourceStates, - initialContext, - adHocDataViews: lens.persistedDoc?.state.adHocDataViews, - ...loaderSharedArgs, - }, - { - isFullEditor: true, - } - ) - .then(({ datasourceStates, indexPatterns, indexPatternRefs }) => { - store.dispatch( - initEmpty({ - newState: { - ...emptyState, - dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), - searchSessionId: data.search.session.getSessionId() || data.search.session.start(), - ...(activeDatasourceId && { activeDatasourceId }), - datasourceStates: Object.entries(datasourceStates).reduce( - (state, [datasourceId, datasourceState]) => ({ - ...state, - [datasourceId]: { - ...datasourceState, - isLoading: false, - }, - }), - {} - ), - isLoading: false, - }, - initialContext, - }) - ); - if (autoApplyDisabled) { - store.dispatch(disableAutoApply()); - } - }) - .catch((e: { message: string }) => { - notifications.toasts.addDanger({ - title: e.message, - }); - redirectCallback?.(); + try { + return loadFromEmptyState( + store, + emptyState, + loaderSharedArgs, + lensServices, + activeDatasourceId, + autoApplyDisabled + ); + } catch ({ message }) { + notifications.toasts.addDanger({ + title: message, }); + return redirectCallback?.(); + } } - return getPersisted({ initialInput, lensServices, history }) - .then( - (persisted) => { - if (persisted) { - const { doc, sharingSavedObjectProps, managed } = persisted; - if (attributeService.inputIsRefType(initialInput)) { - lensServices.chrome.recentlyAccessed.add( - getFullPath(initialInput.savedObjectId), - doc.title, - initialInput.savedObjectId - ); - } - - const docDatasourceStates = Object.entries(doc.state.datasourceStates).reduce( - (stateMap, [datasourceId, datasourceState]) => ({ - ...stateMap, - [datasourceId]: { - isLoading: true, - state: datasourceState, - }, - }), - {} - ); - - // when the embeddable is initialized from the dashboard we don't want to inject the filters - // as this will replace the parent application filters (such as a dashboard) - if (!Boolean(inlineEditing)) { - const filters = data.query.filterManager.inject(doc.state.filters, doc.references); - // Don't overwrite any pinned filters - data.query.filterManager.setAppFilters(filters); - } - - const docVisualizationState = { - activeId: doc.visualizationType, - state: doc.state.visualization, - }; - return initializeSources( - { - datasourceMap, - visualizationMap, - visualizationState: docVisualizationState, - datasourceStates: docDatasourceStates, - references: [...doc.references, ...(doc.state.internalReferences || [])], - initialContext, - dataViews: lensServices.dataViews, - eventAnnotationService: lensServices.eventAnnotationService, - storage: lensServices.storage, - adHocDataViews: doc.state.adHocDataViews, - defaultIndexPatternId: lensServices.uiSettings.get('defaultIndex'), - }, - { isFullEditor: true } - ) - .then( - ({ - datasourceStates, - visualizationState, - indexPatterns, - indexPatternRefs, - annotationGroups, - }) => { - const currentSessionId = data.search.session.getSessionId(); - store.dispatch( - initExisting({ - isSaveable: true, - sharingSavedObjectProps, - filters: data.query.filterManager.getFilters(), - query: doc.state.query, - searchSessionId: - !(initialInput as LensByReferenceInput)?.savedObjectId && currentSessionId - ? currentSessionId - : !inlineEditing - ? data.search.session.start() - : undefined, - persistedDoc: doc, - activeDatasourceId: getInitialDatasourceId(datasourceMap, doc), - visualization: { - activeId: doc.visualizationType, - state: visualizationState, - }, - dataViews: getInitialDataViewsObject(indexPatterns, indexPatternRefs), - datasourceStates: Object.entries(datasourceStates).reduce( - (state, [datasourceId, datasourceState]) => ({ - ...state, - [datasourceId]: { - ...datasourceState, - isLoading: false, - }, - }), - {} - ), - isLoading: false, - annotationGroups, - managed, - }) - ); - - if (autoApplyDisabled) { - store.dispatch(disableAutoApply()); - } - } - ) - .catch((e: { message: string }) => - notifications.toasts.addDanger({ - title: e.message, - }) - ); - } else { - redirectCallback?.(); - } - }, - () => { - store.dispatch( - setState({ - isLoading: false, - }) + try { + const persisted = await getFromPreloaded({ initialInput, lensServices, history }); + if (persisted) { + try { + return loadFromSavedObject( + store, + initialInput.savedObjectId, + persisted, + loaderSharedArgs, + lensServices, + autoApplyDisabled, + inlineEditing ); - redirectCallback?.(); + } catch ({ message }) { + notifications.toasts.addDanger({ + title: message, + }); } - ) - .catch((e: { message: string }) => { + } else { + return redirectCallback?.(); + } + } catch (e) { + try { + store.dispatch( + setState({ + isLoading: false, + }) + ); + redirectCallback?.(); + } catch ({ message }) { notifications.toasts.addDanger({ - title: e.message, + title: message, }); redirectCallback?.(); - }); + } + } } diff --git a/x-pack/plugins/lens/public/state_management/lens_slice.ts b/x-pack/plugins/lens/public/state_management/lens_slice.ts index 20c727734aa9..b2a9beb0fb0a 100644 --- a/x-pack/plugins/lens/public/state_management/lens_slice.ts +++ b/x-pack/plugins/lens/public/state_management/lens_slice.ts @@ -14,7 +14,6 @@ import { LayerTypes } from '@kbn/expression-xy-plugin/public'; import { EventAnnotationGroupConfig } from '@kbn/event-annotation-common'; import { DragDropIdentifier, DropType } from '@kbn/dom-drag-drop'; import { SeriesType } from '@kbn/visualizations-plugin/common'; -import { LensEmbeddableInput } from '..'; import { TableInspectorAdapter } from '../editor_frame_service/types'; import type { VisualizeEditorContext, @@ -34,6 +33,7 @@ import type { FramePublicAPI, LensEditContextMapping, LensEditEvent } from '../t import { selectDataViews, selectFramePublicAPI } from './selectors'; import { onDropForVisualization } from '../editor_frame_service/editor_frame/config_panel/buttons/drop_targets_utils'; import type { LensAppServices } from '../app_plugin/types'; +import type { LensSerializedState } from '../react_embeddable/types'; const getQueryFromContext = ( context: VisualizeFieldContext | VisualizeEditorContext, @@ -149,6 +149,13 @@ export interface SetExecutionContextPayload { resolvedDateRange?: DateRange; } +export interface InitialAppState { + initialInput?: LensSerializedState; + redirectCallback?: (savedObjectId?: string) => void; + history?: History<unknown>; + inlineEditing?: boolean; +} + export const setState = createAction<Partial<LensAppState>>('lens/setState'); export const setExecutionContext = createAction<SetExecutionContextPayload>( 'lens/setExecutionContext' @@ -201,12 +208,7 @@ export const switchAndCleanDatasource = createAction<{ currentIndexPatternId?: string; }>('lens/switchAndCleanDatasource'); export const navigateAway = createAction<void>('lens/navigateAway'); -export const loadInitial = createAction<{ - initialInput?: LensEmbeddableInput; - redirectCallback?: (savedObjectId?: string) => void; - history?: History<unknown>; - inlineEditing?: boolean; -}>('lens/loadInitial'); +export const loadInitial = createAction<InitialAppState>('lens/loadInitial'); export const initEmpty = createAction( 'initEmpty', function prepare({ diff --git a/x-pack/plugins/lens/public/state_management/load_initial.test.tsx b/x-pack/plugins/lens/public/state_management/load_initial.test.tsx index a70b713787ce..1514a508b878 100644 --- a/x-pack/plugins/lens/public/state_management/load_initial.test.tsx +++ b/x-pack/plugins/lens/public/state_management/load_initial.test.tsx @@ -15,10 +15,10 @@ import { } from '../mocks'; import { Location, History } from 'history'; import { act } from 'react-dom/test-utils'; -import { LensEmbeddableInput } from '../embeddable'; -import { loadInitial } from './lens_slice'; +import { InitialAppState, loadInitial } from './lens_slice'; import { Filter } from '@kbn/es-query'; import faker from 'faker'; +import { DOC_TYPE } from '../../common/constants'; const history = { location: { @@ -35,26 +35,37 @@ const preloadedState = { }, }; -const defaultProps = { +const defaultProps: InitialAppState = { redirectCallback: jest.fn(), - initialInput: { savedObjectId: defaultSavedObjectId } as unknown as LensEmbeddableInput, + initialInput: { savedObjectId: defaultSavedObjectId }, history, }; +/** + * This is just a convenience wrapper around act & dispatch + * The loadInitial action is hijacked by a custom middleware which returns a Promise + * therefore we need to await before proceeding with all the checks + * The intent of this wrapper is to avoid confusion with this specific action + */ +async function loadInitialAppState( + store: ReturnType<typeof makeLensStore>['store'], + initialState: InitialAppState +) { + await act(async () => { + await store.dispatch(loadInitial(initialState)); + }); +} + describe('Initializing the store', () => { it('should initialize initial datasource', async () => { - const { store, deps } = await makeLensStore({ preloadedState }); - await act(async () => { - await store.dispatch(loadInitial(defaultProps)); - }); + const { store, deps } = makeLensStore({ preloadedState }); + await loadInitialAppState(store, defaultProps); expect(deps.datasourceMap.testDatasource.initialize).toHaveBeenCalled(); }); it('should have initialized the initial datasource and visualization', async () => { - const { store, deps } = await makeLensStore({ preloadedState }); - await act(async () => { - await store.dispatch(loadInitial({ ...defaultProps, initialInput: undefined })); - }); + const { store, deps } = makeLensStore({ preloadedState }); + await loadInitialAppState(store, { ...defaultProps, initialInput: undefined }); expect(deps.datasourceMap.testDatasource.initialize).toHaveBeenCalled(); expect(deps.datasourceMap.testDatasource2.initialize).not.toHaveBeenCalled(); expect(deps.visualizationMap.testVis.initialize).toHaveBeenCalled(); @@ -65,7 +76,7 @@ describe('Initializing the store', () => { const datasource1State = { datasource1: '' }; const datasource2State = { datasource2: '' }; const services = makeDefaultServices(); - services.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ + services.attributeService.loadFromLibrary = jest.fn().mockResolvedValue({ attributes: { exactMatchDoc, visualizationType: 'testVis', @@ -107,16 +118,13 @@ describe('Initializing the store', () => { }, }); - const { store, deps } = await makeLensStore({ + const { store, deps } = makeLensStore({ storeDeps, preloadedState, }); - await act(async () => { - await store.dispatch(loadInitial(defaultProps)); - }); + await loadInitialAppState(store, defaultProps); const { datasourceMap } = deps; - expect(datasourceMap.testDatasource.initialize).toHaveBeenCalled(); expect(datasourceMap.testDatasource.initialize).toHaveBeenCalledWith( datasource1State, @@ -139,22 +147,17 @@ describe('Initializing the store', () => { describe('loadInitial', () => { it('does not load a document if there is no initial input', async () => { const { deps, store } = makeLensStore({ preloadedState }); - await act(async () => { - await store.dispatch( - loadInitial({ - ...defaultProps, - initialInput: undefined, - }) - ); + await loadInitialAppState(store, { + ...defaultProps, + initialInput: undefined, }); - expect(deps.lensServices.attributeService.unwrapAttributes).not.toHaveBeenCalled(); + + expect(deps.lensServices.attributeService.loadFromLibrary).not.toHaveBeenCalled(); }); it('starts new searchSessionId', async () => { - const { store } = await makeLensStore({ preloadedState }); - await act(async () => { - await store.dispatch(loadInitial({ ...defaultProps, initialInput: undefined })); - }); + const { store } = makeLensStore({ preloadedState }); + await loadInitialAppState(store, { ...defaultProps, initialInput: undefined }); expect(store.getState()).toEqual({ lens: expect.objectContaining({ searchSessionId: 'sessionId-1', @@ -163,7 +166,7 @@ describe('Initializing the store', () => { }); it('cleans datasource and visualization state properly when reloading', async () => { - const { store, deps } = await makeLensStore({ + const { store, deps } = makeLensStore({ preloadedState: { ...preloadedState, visualization: { @@ -187,13 +190,9 @@ describe('Initializing the store', () => { }), }); - await act(async () => { - await store.dispatch( - loadInitial({ - ...defaultProps, - initialInput: undefined, - }) - ); + await loadInitialAppState(store, { + ...defaultProps, + initialInput: undefined, }); expect(deps.visualizationMap.testVis.initialize).toHaveBeenCalled(); @@ -217,19 +216,17 @@ describe('Initializing the store', () => { it('loads a document and uses query and filters if initial input is provided', async () => { const { store, deps } = makeLensStore({ preloadedState }); - const mockFilters = 'some filters from the filter manager' as unknown as Filter[]; + const mockFilters = faker.lorem.words(3).split(' ') as unknown as Filter[]; jest .spyOn(deps.lensServices.data.query.filterManager, 'getFilters') .mockReturnValue(mockFilters); - await act(async () => { - store.dispatch(loadInitial(defaultProps)); - }); + await loadInitialAppState(store, defaultProps); - expect(deps.lensServices.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); + expect(deps.lensServices.attributeService.loadFromLibrary).toHaveBeenCalledWith( + defaultSavedObjectId + ); expect(deps.lensServices.data.query.filterManager.setAppFilters).toHaveBeenCalledWith([ { query: { match_phrase: { src: 'test' } }, meta: { index: 'injected!' } }, @@ -237,8 +234,8 @@ describe('Initializing the store', () => { expect(store.getState()).toEqual({ lens: expect.objectContaining({ - persistedDoc: { ...defaultDoc, type: 'lens' }, - query: 'kuery', + persistedDoc: { ...defaultDoc, type: DOC_TYPE }, + query: defaultDoc.state.query, isLoading: false, activeDatasourceId: 'testDatasource', filters: mockFilters, @@ -249,68 +246,54 @@ describe('Initializing the store', () => { it('does not load documents on sequential renders unless the id changes', async () => { const { store, deps } = makeLensStore({ preloadedState }); - await act(async () => { - await store.dispatch(loadInitial(defaultProps)); - }); + await loadInitialAppState(store, defaultProps); - await act(async () => { - await store.dispatch(loadInitial(defaultProps)); - }); + await loadInitialAppState(store, defaultProps); - expect(deps.lensServices.attributeService.unwrapAttributes).toHaveBeenCalledTimes(1); + expect(deps.lensServices.attributeService.loadFromLibrary).toHaveBeenCalledTimes(1); - await act(async () => { - await store.dispatch( - loadInitial({ - ...defaultProps, - initialInput: { savedObjectId: '5678' } as unknown as LensEmbeddableInput, - }) - ); + await loadInitialAppState(store, { + ...defaultProps, + initialInput: { savedObjectId: '5678' }, }); - expect(deps.lensServices.attributeService.unwrapAttributes).toHaveBeenCalledTimes(2); + expect(deps.lensServices.attributeService.loadFromLibrary).toHaveBeenCalledTimes(2); }); it('handles document load errors', async () => { const { store, deps } = makeLensStore({ preloadedState }); - deps.lensServices.attributeService.unwrapAttributes = jest + deps.lensServices.attributeService.loadFromLibrary = jest .fn() .mockRejectedValue('failed to load'); const redirectCallback = jest.fn(); - await act(async () => { - await store.dispatch(loadInitial({ ...defaultProps, redirectCallback })); - }); + await loadInitialAppState(store, { ...defaultProps, redirectCallback }); - expect(deps.lensServices.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); + expect(deps.lensServices.attributeService.loadFromLibrary).toHaveBeenCalledWith( + defaultSavedObjectId + ); expect(deps.lensServices.notifications.toasts.addDanger).toHaveBeenCalled(); expect(redirectCallback).toHaveBeenCalled(); }); it('redirects if saved object is an aliasMatch', async () => { const { store, deps } = makeLensStore({ preloadedState }); - deps.lensServices.attributeService.unwrapAttributes = jest.fn().mockResolvedValue({ + deps.lensServices.attributeService.loadFromLibrary = jest.fn().mockResolvedValue({ attributes: { ...defaultDoc, }, - metaInfo: { - sharingSavedObjectProps: { - outcome: 'aliasMatch', - aliasTargetId: 'id2', - aliasPurpose: 'savedObjectConversion', - }, + sharingSavedObjectProps: { + outcome: 'aliasMatch', + aliasTargetId: 'id2', + aliasPurpose: 'savedObjectConversion', }, }); - await act(async () => { - await store.dispatch(loadInitial(defaultProps)); - }); + await loadInitialAppState(store, defaultProps); - expect(deps.lensServices.attributeService.unwrapAttributes).toHaveBeenCalledWith({ - savedObjectId: defaultSavedObjectId, - }); + expect(deps.lensServices.attributeService.loadFromLibrary).toHaveBeenCalledWith( + defaultSavedObjectId + ); expect(deps.lensServices.spaces?.ui.redirectLegacyUrl).toHaveBeenCalledWith({ path: '#/edit/id2?search', aliasPurpose: 'savedObjectConversion', @@ -320,9 +303,7 @@ describe('Initializing the store', () => { it('adds to the recently accessed list on load', async () => { const { store, deps } = makeLensStore({ preloadedState }); - await act(async () => { - await store.dispatch(loadInitial(defaultProps)); - }); + await loadInitialAppState(store, defaultProps); expect(deps.lensServices.chrome.recentlyAccessed.add).toHaveBeenCalledWith( '/app/lens#/edit/1234', diff --git a/x-pack/plugins/lens/public/state_management/selectors.ts b/x-pack/plugins/lens/public/state_management/selectors.ts index 2187302ae02e..594b1b9632d6 100644 --- a/x-pack/plugins/lens/public/state_management/selectors.ts +++ b/x-pack/plugins/lens/public/state_management/selectors.ts @@ -7,11 +7,11 @@ import { createSelector } from '@reduxjs/toolkit'; import { FilterManager } from '@kbn/data-plugin/public'; -import { SavedObjectReference } from '@kbn/core/public'; -import { DataViewPersistableStateService } from '@kbn/data-views-plugin/common'; +import { isOfAggregateQueryType } from '@kbn/es-query'; import { LensState } from './types'; -import { Datasource, DatasourceMap, VisualizationMap } from '../types'; +import { DatasourceMap, VisualizationMap } from '../types'; import { getDatasourceLayers } from './utils'; +import { mergeToNewDoc } from './shared_logic'; export const selectPersistedDoc = (state: LensState) => state.lens.persistedDoc; export const selectQuery = (state: LensState) => state.lens.query; @@ -60,7 +60,7 @@ export const selectExecutionContext = createSelector( export const selectExecutionContextSearch = createSelector(selectExecutionContext, (res) => ({ now: res.now, - query: res.query, + query: isOfAggregateQueryType(res.query) ? undefined : res.query, timeRange: { from: res.dateRange.fromDate, to: res.dateRange.toDate, @@ -89,107 +89,7 @@ export const selectSavedObjectFormat = createSelector( extractFilterReferences: FilterManager['extract']; }>, ], - ( - persistedDoc, - visualization, - datasourceStates, - query, - filters, - activeDatasourceId, - adHocDataViews, - { datasourceMap, visualizationMap, extractFilterReferences } - ) => { - const activeVisualization = - visualization.state && visualization.activeId - ? visualizationMap[visualization.activeId] - : null; - const activeDatasource = - datasourceStates && activeDatasourceId && !datasourceStates[activeDatasourceId].isLoading - ? datasourceMap[activeDatasourceId] - : undefined; - - if (!activeDatasource || !activeVisualization) { - return; - } - - const activeDatasources: Record<string, Datasource> = Object.keys(datasourceStates).reduce( - (acc, datasourceId) => ({ - ...acc, - [datasourceId]: datasourceMap[datasourceId], - }), - {} - ); - - const persistibleDatasourceStates: Record<string, unknown> = {}; - const references: SavedObjectReference[] = []; - const internalReferences: SavedObjectReference[] = []; - Object.entries(activeDatasources).forEach(([id, datasource]) => { - const { state: persistableState, savedObjectReferences } = datasource.getPersistableState( - datasourceStates[id].state - ); - persistibleDatasourceStates[id] = persistableState; - savedObjectReferences.forEach((r) => { - if (r.type === 'index-pattern' && adHocDataViews[r.id]) { - internalReferences.push(r); - } else { - references.push(r); - } - }); - }); - - let persistibleVisualizationState = visualization.state; - if (activeVisualization.getPersistableState) { - const { state: persistableState, savedObjectReferences } = - activeVisualization.getPersistableState(visualization.state); - persistibleVisualizationState = persistableState; - savedObjectReferences.forEach((r) => { - if (r.type === 'index-pattern' && adHocDataViews[r.id]) { - internalReferences.push(r); - } else { - references.push(r); - } - }); - } - - const persistableAdHocDataViews = Object.fromEntries( - Object.entries(adHocDataViews).map(([id, dataView]) => { - const { references: dataViewReferences, state } = - DataViewPersistableStateService.extract(dataView); - references.push(...dataViewReferences); - return [id, state]; - }) - ); - - const adHocFilters = filters - .filter((f) => !references.some((r) => r.type === 'index-pattern' && r.id === f.meta.index)) - .map((f) => ({ ...f, meta: { ...f.meta, value: undefined } })); - - const referencedFilters = filters.filter((f) => - references.some((r) => r.type === 'index-pattern' && r.id === f.meta.index) - ); - - const { state: persistableFilters, references: filterReferences } = - extractFilterReferences(referencedFilters); - - references.push(...filterReferences); - - return { - savedObjectId: persistedDoc?.savedObjectId, - title: persistedDoc?.title || '', - description: persistedDoc?.description, - visualizationType: visualization.activeId, - type: 'lens', - references, - state: { - visualization: persistibleVisualizationState, - query, - filters: [...persistableFilters, ...adHocFilters], - datasourceStates: persistibleDatasourceStates, - internalReferences, - adHocDataViews: persistableAdHocDataViews, - }, - }; - } + mergeToNewDoc ); export const selectCurrentVisualization = createSelector( diff --git a/x-pack/plugins/lens/public/state_management/shared_logic.ts b/x-pack/plugins/lens/public/state_management/shared_logic.ts new file mode 100644 index 000000000000..4e24d9f3fdaa --- /dev/null +++ b/x-pack/plugins/lens/public/state_management/shared_logic.ts @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { SavedObjectReference } from '@kbn/core-saved-objects-api-server'; +import { DataViewSpec, DataViewPersistableStateService } from '@kbn/data-views-plugin/common'; +import { AggregateQuery, Query, Filter } from '@kbn/es-query'; +import { FilterManager } from '@kbn/data-plugin/public'; +import { DOC_TYPE, INDEX_PATTERN_TYPE } from '../../common/constants'; +import { VisualizationState, DatasourceStates } from '.'; +import { LensDocument } from '../persistence'; +import { DatasourceMap, VisualizationMap, Datasource } from '../types'; + +// This piece of logic is shared between the main editor code base and the inline editor one within the embeddable +export function mergeToNewDoc( + persistedDoc: LensDocument | undefined, + visualization: VisualizationState, + datasourceStates: DatasourceStates, + query: AggregateQuery | Query, + filters: Filter[], + activeDatasourceId: string | null, + adHocDataViews: Record<string, DataViewSpec>, + { + datasourceMap, + visualizationMap, + extractFilterReferences, + }: { + datasourceMap: DatasourceMap; + visualizationMap: VisualizationMap; + extractFilterReferences: FilterManager['extract']; + } +) { + const activeVisualization = + visualization.state && visualization.activeId ? visualizationMap[visualization.activeId] : null; + const activeDatasource = + datasourceStates && activeDatasourceId && !datasourceStates[activeDatasourceId].isLoading + ? datasourceMap[activeDatasourceId] + : undefined; + + if (!activeDatasource || !activeVisualization) { + return; + } + + const activeDatasources: Record<string, Datasource> = Object.keys(datasourceStates).reduce( + (acc, datasourceId) => ({ + ...acc, + [datasourceId]: datasourceMap[datasourceId], + }), + {} + ); + + const persistibleDatasourceStates: Record<string, unknown> = {}; + const references: SavedObjectReference[] = []; + const internalReferences: SavedObjectReference[] = []; + Object.entries(activeDatasources).forEach(([id, datasource]) => { + const { state: persistableState, savedObjectReferences } = datasource.getPersistableState( + datasourceStates[id].state + ); + persistibleDatasourceStates[id] = persistableState; + savedObjectReferences.forEach((r) => { + if (r.type === INDEX_PATTERN_TYPE && adHocDataViews[r.id]) { + internalReferences.push(r); + } else { + references.push(r); + } + }); + }); + + let persistibleVisualizationState = visualization.state; + if (activeVisualization.getPersistableState) { + const { state: persistableState, savedObjectReferences } = + activeVisualization.getPersistableState(visualization.state); + persistibleVisualizationState = persistableState; + savedObjectReferences.forEach((r) => { + if (r.type === INDEX_PATTERN_TYPE && adHocDataViews[r.id]) { + internalReferences.push(r); + } else { + references.push(r); + } + }); + } + + const persistableAdHocDataViews = Object.fromEntries( + Object.entries(adHocDataViews).map(([id, dataView]) => { + const { references: dataViewReferences, state } = + DataViewPersistableStateService.extract(dataView); + references.push(...dataViewReferences); + return [id, state]; + }) + ); + + const adHocFilters = filters + .filter((f) => !references.some((r) => r.type === INDEX_PATTERN_TYPE && r.id === f.meta.index)) + .map((f) => ({ ...f, meta: { ...f.meta, value: undefined } })); + + const referencedFilters = filters.filter((f) => + references.some((r) => r.type === INDEX_PATTERN_TYPE && r.id === f.meta.index) + ); + + const { state: persistableFilters, references: filterReferences } = + extractFilterReferences(referencedFilters); + + references.push(...filterReferences); + + return { + savedObjectId: persistedDoc?.savedObjectId, + title: persistedDoc?.title || '', + description: persistedDoc?.description, + visualizationType: visualization.activeId!, + type: DOC_TYPE, + references, + state: { + visualization: persistibleVisualizationState, + query, + filters: [...persistableFilters, ...adHocFilters], + datasourceStates: persistibleDatasourceStates, + internalReferences, + adHocDataViews: persistableAdHocDataViews, + }, + }; +} diff --git a/x-pack/plugins/lens/public/state_management/types.ts b/x-pack/plugins/lens/public/state_management/types.ts index 1d683b655b58..cc8f76118cf2 100644 --- a/x-pack/plugins/lens/public/state_management/types.ts +++ b/x-pack/plugins/lens/public/state_management/types.ts @@ -7,10 +7,10 @@ import type { VisualizeFieldContext } from '@kbn/ui-actions-plugin/public'; import type { EmbeddableEditorState } from '@kbn/embeddable-plugin/public'; -import type { Filter, Query } from '@kbn/es-query'; +import type { AggregateQuery, Filter, Query } from '@kbn/es-query'; import type { SavedQuery } from '@kbn/data-plugin/public'; import type { MainHistoryLocationState } from '../../common/locator/locator'; -import type { Document } from '../persistence'; +import type { LensDocument } from '../persistence'; import type { TableInspectorAdapter } from '../editor_frame_service/types'; import type { DateRange } from '../../common/types'; @@ -54,14 +54,14 @@ export interface EditorFrameState extends PreviewState { isFullscreenDatasource?: boolean; } export interface LensAppState extends EditorFrameState { - persistedDoc?: Document; + persistedDoc?: LensDocument; // Determines whether the lens editor shows the 'save and return' button, and the originating app breadcrumb. isLinkedToOriginatingApp?: boolean; isSaveable: boolean; isLoading: boolean; - query: Query; + query: Query | AggregateQuery; filters: Filter[]; savedQuery?: SavedQuery; searchSessionId: string; diff --git a/x-pack/plugins/lens/public/trigger_actions/convert_to_lens_action.ts b/x-pack/plugins/lens/public/trigger_actions/convert_to_lens_action.ts new file mode 100644 index 000000000000..017cb64f9dd4 --- /dev/null +++ b/x-pack/plugins/lens/public/trigger_actions/convert_to_lens_action.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createAction } from '@kbn/ui-actions-plugin/public'; +import { ACTION_CONVERT_TO_LENS } from '@kbn/visualizations-plugin/public'; +import type { ApplicationStart } from '@kbn/core/public'; +import { APP_ID } from '../../common/constants'; +import type { VisualizeEditorContext } from '../types'; + +export const convertToLensActionFactory = + (id: string, displayName: string, originatingApp: string) => (application: ApplicationStart) => + createAction<{ [key: string]: VisualizeEditorContext }>({ + type: ACTION_CONVERT_TO_LENS, + id, + getDisplayName: () => displayName, + isCompatible: async () => !!application.capabilities.visualize.show, + execute: async (context: { [key: string]: VisualizeEditorContext }) => { + const table = Object.values(context.layers); + const payload = { + ...context, + layers: table, + isVisualizeAction: true, + }; + application.navigateToApp(APP_ID, { + state: { + type: ACTION_CONVERT_TO_LENS, + payload, + originatingApp, + }, + }); + }, + }); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.test.ts b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.test.ts index fd1ef4f746c4..c74486abfe8d 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.test.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.test.ts @@ -8,30 +8,12 @@ import { DataViewsService } from '@kbn/data-views-plugin/public'; import { type EmbeddableApiContext } from '@kbn/presentation-publishing'; import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import { BehaviorSubject } from 'rxjs'; -import { DOC_TYPE } from '../../common/constants'; import { createOpenInDiscoverAction } from './open_in_discover_action'; import type { DiscoverAppLocator } from './open_in_discover_helpers'; +import { getLensApiMock } from '../react_embeddable/mocks'; describe('open in discover action', () => { - const compatibleEmbeddableApi = { - type: DOC_TYPE, - panelTitle: 'some title', - hidePanelTitle: false, - filters$: new BehaviorSubject([]), - query$: new BehaviorSubject({ query: 'test', language: 'kuery' }), - timeRange$: new BehaviorSubject({ from: 'now-15m', to: 'now' }), - getSavedVis: jest.fn(() => undefined), - canViewUnderlyingData$: new BehaviorSubject(true), - getFullAttributes: jest.fn(() => undefined), - getViewUnderlyingDataArgs: jest.fn(() => ({ - dataViewSpec: { id: 'index-pattern-id' }, - timeRange: { from: 'now-7d', to: 'now' }, - filters: [], - query: undefined, - columns: [], - })), - }; + const compatibleEmbeddableApi = getLensApiMock(); describe('compatibility check', () => { it('is incompatible with non-lens embeddables', async () => { @@ -49,6 +31,10 @@ describe('open in discover action', () => { }); it('is incompatible if user cant access Discover app', async () => { // setup + const lensApi = { + ...compatibleEmbeddableApi, + canViewUnderlyingData$: { getValue: jest.fn(() => true) }, + }; let hasDiscoverAccess = true; // make sure it would work if we had access to Discover @@ -58,7 +44,7 @@ describe('open in discover action', () => { {} as DataViewsService, hasDiscoverAccess ).isCompatible({ - embeddable: compatibleEmbeddableApi, + embeddable: lensApi, } as ActionExecutionContext<EmbeddableApiContext>) ).toBeTruthy(); @@ -70,7 +56,7 @@ describe('open in discover action', () => { {} as DataViewsService, hasDiscoverAccess ).isCompatible({ - embeddable: compatibleEmbeddableApi, + embeddable: lensApi, } as ActionExecutionContext<EmbeddableApiContext>) ).toBeFalsy(); }); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.ts b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.ts index d9dccab616d5..fa67aa74f9de 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_action.ts @@ -10,7 +10,7 @@ import { Action, createAction, IncompatibleActionError } from '@kbn/ui-actions-p import { EmbeddableApiContext } from '@kbn/presentation-publishing'; import type { DataViewsService } from '@kbn/data-views-plugin/public'; import type { DiscoverAppLocator } from './open_in_discover_helpers'; -import { LensApi } from '../embeddable'; +import { LensApi } from '../react_embeddable/types'; const ACTION_OPEN_IN_DISCOVER = 'ACTION_OPEN_IN_DISCOVER'; @@ -41,7 +41,7 @@ export const createOpenInDiscoverAction = ( }, isCompatible: async (context: EmbeddableApiContext) => { const { isCompatible } = await getDiscoverHelpersAsync(); - return isCompatible({ + return await isCompatible({ hasDiscoverAccess, locator, dataViews, diff --git a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.test.tsx b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.test.tsx index d9b8b93e28d0..199700af157d 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.test.tsx +++ b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.test.tsx @@ -17,10 +17,10 @@ import { OpenInDiscoverDrilldown, } from './open_in_discover_drilldown'; import { DataViewsService } from '@kbn/data-views-plugin/public'; -import { LensApi } from '../embeddable'; +import { getLensApiMock } from '../react_embeddable/mocks'; jest.mock('./open_in_discover_helpers', () => ({ - isCompatible: jest.fn(() => true), + isCompatible: jest.fn().mockReturnValue(true), getHref: jest.fn(), })); @@ -63,19 +63,13 @@ describe('open in discover drilldown', () => { it('calls through to isCompatible helper', async () => { const filters: Filter[] = [{ meta: { disabled: false } }]; - await drilldown.isCompatible( - { openInNewTab: true }, - { embeddable: { type: 'lens' } as LensApi, filters } - ); + await drilldown.isCompatible({ openInNewTab: true }, { embeddable: getLensApiMock(), filters }); expect(isCompatible).toHaveBeenCalledWith(expect.objectContaining({ filters })); }); it('calls through to getHref helper', async () => { const filters: Filter[] = [{ meta: { disabled: false } }]; - await drilldown.execute( - { openInNewTab: true }, - { embeddable: { type: 'lens' } as LensApi, filters } - ); + await drilldown.execute({ openInNewTab: true }, { embeddable: getLensApiMock(), filters }); expect(getHref).toHaveBeenCalledWith(expect.objectContaining({ filters })); }); }); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.tsx b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.tsx index 6602dc4acb69..0a8f7cb3bf5e 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.tsx +++ b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_drilldown.tsx @@ -21,7 +21,7 @@ import type { DataViewsService } from '@kbn/data-views-plugin/public'; import { apiIsOfType } from '@kbn/presentation-publishing'; import { DOC_TYPE } from '../../common/constants'; import type { DiscoverAppLocator } from './open_in_discover_helpers'; -import { LensApi } from '../embeddable'; +import { LensApi } from '../react_embeddable/types'; export const getDiscoverHelpersAsync = async () => await import('../async_services'); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_helpers.ts index 0a52ea6b4711..3ad62f212e49 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_in_discover_helpers.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_in_discover_helpers.ts @@ -10,7 +10,7 @@ import type { DataViewsService } from '@kbn/data-views-plugin/public'; import type { LocatorPublic } from '@kbn/share-plugin/public'; import type { SerializableRecord } from '@kbn/utility-types'; import { EmbeddableApiContext } from '@kbn/presentation-publishing'; -import { isLensApi } from '../embeddable'; +import { isLensApi } from '../react_embeddable/type_guards'; interface DiscoverAppLocatorParams extends SerializableRecord { timeRange?: TimeRange; diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts index 96cd0ab6877e..6f875e49f160 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/create_action_helpers.ts @@ -20,9 +20,8 @@ import type { Datasource, Visualization } from '../../types'; import type { LensPluginStartDependencies } from '../../plugin'; import { suggestionsApi } from '../../lens_suggestions_api'; import { generateId } from '../../id_generator'; -import { executeEditAction } from './edit_action_helpers'; -import { Embeddable } from '../../embeddable'; import type { EditorFrameService } from '../../editor_frame_service'; +import { LensApi } from '../..'; // datasourceMap and visualizationMap setters/getters export const [getVisualizationMap, setVisualizationMap] = createGetterSetter< @@ -117,29 +116,21 @@ export async function executeCreateAction({ const attrs = getLensAttributesFromSuggestion({ filters: [], query: defaultEsqlQuery, - suggestion: firstSuggestion, + suggestion: { + ...firstSuggestion, + title: '', // when creating a new panel, we don't want to use the title from the suggestion + }, dataView, }); - const embeddable = await api.addNewPanel<object, Embeddable>({ + const embeddable = await api.addNewPanel<object, LensApi>({ panelType: 'lens', initialState: { attributes: attrs, id: generateId(), + isNewPanel: true, }, }); // open the flyout if embeddable has been created successfully - if (embeddable) { - const deletePanel = () => { - api.removePanel(embeddable.id); - }; - - executeEditAction({ - embeddable, - startDependencies: deps, - isNewPanel: true, - deletePanel, - ...core, - }); - } + embeddable?.onEdit?.(); } diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action.test.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action.test.tsx deleted file mode 100644 index e9daa06b9ac0..000000000000 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action.test.tsx +++ /dev/null @@ -1,119 +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 { coreMock } from '@kbn/core/public/mocks'; -import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; -import type { LensPluginStartDependencies } from '../../plugin'; -import { createMockStartDependencies } from '../../editor_frame_service/mocks'; -import { DOC_TYPE } from '../../../common/constants'; -import { ConfigureInLensPanelAction } from './edit_action'; - -describe('open config panel action', () => { - const coreStart = coreMock.createStart(); - const mockStartDependencies = - createMockStartDependencies() as unknown as LensPluginStartDependencies; - describe('compatibility check', () => { - it('is incompatible with non-lens embeddables', async () => { - const embeddable = { - type: 'NOT_LENS', - isTextBasedLanguage: () => true, - getInput: () => { - return { - viewMode: 'edit', - }; - }, - } as unknown as IEmbeddable; - const configurablePanelAction = new ConfigureInLensPanelAction( - mockStartDependencies, - coreStart - ); - - const isCompatible = await configurablePanelAction.isCompatible({ - embeddable, - } as ActionExecutionContext<{ embeddable: IEmbeddable }>); - - expect(isCompatible).toBeFalsy(); - }); - - it('is incompatible with input view mode', async () => { - const embeddable = { - type: 'NOT_LENS', - getInput: () => { - return { - viewMode: 'view', - }; - }, - } as unknown as IEmbeddable; - const configurablePanelAction = new ConfigureInLensPanelAction( - mockStartDependencies, - coreStart - ); - - const isCompatible = await configurablePanelAction.isCompatible({ - embeddable, - } as ActionExecutionContext<{ embeddable: IEmbeddable }>); - - expect(isCompatible).toBeFalsy(); - }); - - it('is compatible with text based language embeddable', async () => { - const embeddable = { - type: DOC_TYPE, - isTextBasedLanguage: () => true, - getInput: () => { - return { - viewMode: 'edit', - }; - }, - getIsEditable: () => true, - } as unknown as IEmbeddable; - const configurablePanelAction = new ConfigureInLensPanelAction( - mockStartDependencies, - coreStart - ); - - const isCompatible = await configurablePanelAction.isCompatible({ - embeddable, - } as ActionExecutionContext<{ embeddable: IEmbeddable }>); - - expect(isCompatible).toBeTruthy(); - }); - }); - describe('execution', () => { - it('opens flyout when executed', async () => { - const embeddable = { - type: DOC_TYPE, - isTextBasedLanguage: () => true, - getInput: () => { - return { - viewMode: 'edit', - }; - }, - getIsEditable: () => true, - openConfigPanel: jest.fn().mockResolvedValue(<span>Lens Config Panel Component</span>), - getRoot: () => { - return { - openOverlay: jest.fn(), - clearOverlays: jest.fn(), - }; - }, - } as unknown as IEmbeddable; - const configurablePanelAction = new ConfigureInLensPanelAction( - mockStartDependencies, - coreStart - ); - const spy = jest.spyOn(coreStart.overlays, 'openFlyout'); - - await configurablePanelAction.execute({ - embeddable, - } as ActionExecutionContext<{ embeddable: IEmbeddable }>); - - expect(spy).toHaveBeenCalled(); - }); - }); -}); diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action.tsx deleted file mode 100644 index 4ad23bc953d2..000000000000 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { i18n } from '@kbn/i18n'; -import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { Action } from '@kbn/ui-actions-plugin/public'; -import type { LensPluginStartDependencies } from '../../plugin'; -import { isLensEmbeddable } from '../utils'; -import type { StartServices } from '../../types'; - -const ACTION_CONFIGURE_IN_LENS = 'ACTION_CONFIGURE_IN_LENS'; - -interface Context { - embeddable: IEmbeddable; -} - -export const getConfigureLensHelpersAsync = async () => await import('../../async_services'); - -export class ConfigureInLensPanelAction implements Action<Context> { - public type = ACTION_CONFIGURE_IN_LENS; - public id = ACTION_CONFIGURE_IN_LENS; - public order = 50; - - constructor( - protected readonly startDependencies: LensPluginStartDependencies, - protected readonly startServices: StartServices - ) {} - - public getDisplayName({ embeddable }: Context): string { - const language = isLensEmbeddable(embeddable) ? embeddable.getTextBasedLanguage() : undefined; - return i18n.translate('xpack.lens.app.editVisualizationLabel', { - defaultMessage: 'Edit {lang} visualization', - values: { lang: language }, - }); - } - - public getIconType() { - return 'pencil'; - } - - public async isCompatible({ embeddable }: Context) { - const { isEditActionCompatible } = await getConfigureLensHelpersAsync(); - return isEditActionCompatible(embeddable); - } - - public async execute({ embeddable }: Context) { - const { executeEditAction } = await getConfigureLensHelpersAsync(); - return executeEditAction({ - embeddable, - startDependencies: this.startDependencies, - ...this.startServices, - }); - } -} diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action_helpers.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action_helpers.ts deleted file mode 100644 index 7ec70e687efe..000000000000 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/edit_action_helpers.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import './helpers.scss'; -import { toMountPoint } from '@kbn/react-kibana-mount'; -import { tracksOverlays } from '@kbn/presentation-containers'; -import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { ViewMode } from '@kbn/embeddable-plugin/common'; -import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; -import { isLensEmbeddable } from '../utils'; -import type { LensPluginStartDependencies } from '../../plugin'; -import { StartServices } from '../../types'; - -interface Context extends StartServices { - embeddable: IEmbeddable; - startDependencies: LensPluginStartDependencies; - isNewPanel?: boolean; - deletePanel?: () => void; -} - -export async function isEditActionCompatible(embeddable: IEmbeddable) { - if (!embeddable?.getInput) return false; - // display the action only if dashboard is on editable mode - const inDashboardEditMode = embeddable.getInput().viewMode === ViewMode.EDIT; - return Boolean(isLensEmbeddable(embeddable) && embeddable.getIsEditable() && inDashboardEditMode); -} - -type PanelConfigElement<T = {}> = React.ReactElement<T & { closeFlyout: () => void }>; - -const openInlineLensConfigEditor = ( - startServices: StartServices, - embeddable: IEmbeddable, - EmbeddableInlineConfigEditor: PanelConfigElement -) => { - const rootEmbeddable = embeddable.getRoot(); - const overlayTracker = tracksOverlays(rootEmbeddable) ? rootEmbeddable : undefined; - - const handle = startServices.overlays.openFlyout( - toMountPoint( - React.createElement(function InlineLensConfigEditor() { - React.useEffect(() => { - document.body.style.overflowY = 'hidden'; - - return () => { - document.body.style.overflowY = 'initial'; - }; - }, []); - - return React.cloneElement(EmbeddableInlineConfigEditor, { - closeFlyout: () => { - overlayTracker?.clearOverlays(); - handle.close(); - }, - }); - }), - startServices - ), - { - size: 's', - type: 'push', - paddingSize: 'm', - 'data-test-subj': 'customizeLens', - className: 'lnsConfigPanel__overlay', - hideCloseButton: true, - isResizable: true, - onClose: (overlayRef) => { - overlayTracker?.clearOverlays(); - overlayRef.close(); - }, - outsideClickCloses: true, - } - ); - - overlayTracker?.openOverlay(handle, { - focusedPanelId: embeddable.id, - }); -}; - -export async function executeEditAction({ - embeddable, - startDependencies, - isNewPanel, - deletePanel, - ...startServices -}: Context) { - const isCompatibleAction = await isEditActionCompatible(embeddable); - if (!isCompatibleAction || !isLensEmbeddable(embeddable)) { - throw new IncompatibleActionError(); - } - - const ConfigPanel = await embeddable.openConfigPanel(startDependencies, isNewPanel, deletePanel); - - if (ConfigPanel) { - openInlineLensConfigEditor(startServices, embeddable, ConfigPanel); - } -} diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx index 7525f491e697..1e1ab4cacff2 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.test.tsx @@ -8,13 +8,17 @@ import type { CoreStart } from '@kbn/core/public'; import { coreMock } from '@kbn/core/public/mocks'; import type { LensPluginStartDependencies } from '../../../plugin'; import { createMockStartDependencies } from '../../../editor_frame_service/mocks'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; import { EditLensEmbeddableAction } from './in_app_embeddable_edit_action'; +import { TypedLensSerializedState } from '../../../react_embeddable/types'; +import { BehaviorSubject } from 'rxjs'; describe('inapp editing of Lens embeddable', () => { const core = coreMock.createStart(); const mockStartDependencies = createMockStartDependencies() as unknown as LensPluginStartDependencies; + + const renderComplete$ = new BehaviorSubject(false); + describe('compatibility check', () => { const attributes = { title: 'An extremely cool default document!', @@ -29,7 +33,7 @@ describe('inapp editing of Lens embeddable', () => { visualization: {}, }, references: [{ type: 'index-pattern', id: '1', name: 'index-pattern-0' }], - } as unknown as TypedLensByValueInput['attributes']; + } as TypedLensSerializedState['attributes']; it('is incompatible for ESQL charts and if ui setting for ES|QL is off', async () => { const inAppEditAction = new EditLensEmbeddableAction(mockStartDependencies, core); const context = { @@ -37,6 +41,7 @@ describe('inapp editing of Lens embeddable', () => { lensEvent: { adapters: {}, embeddableOutput$: undefined, + renderComplete$, }, onUpdate: jest.fn(), }; @@ -61,6 +66,7 @@ describe('inapp editing of Lens embeddable', () => { lensEvent: { adapters: {}, embeddableOutput$: undefined, + renderComplete$, }, onUpdate: jest.fn(), }; @@ -86,6 +92,7 @@ describe('inapp editing of Lens embeddable', () => { lensEvent: { adapters: {}, embeddableOutput$: undefined, + renderComplete$, }, onUpdate: jest.fn(), }; diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx index c132b5e88c6c..74ffac32605b 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action.tsx @@ -12,8 +12,6 @@ import type { InlineEditLensEmbeddableContext } from './types'; const ACTION_EDIT_LENS_EMBEDDABLE = 'ACTION_EDIT_LENS_EMBEDDABLE'; -export const getAsyncHelpers = async () => await import('../../../async_services'); - export class EditLensEmbeddableAction implements Action<InlineEditLensEmbeddableContext> { public type = ACTION_EDIT_LENS_EMBEDDABLE; public id = ACTION_EDIT_LENS_EMBEDDABLE; @@ -35,7 +33,7 @@ export class EditLensEmbeddableAction implements Action<InlineEditLensEmbeddable } public async isCompatible({ attributes }: InlineEditLensEmbeddableContext) { - const { isEmbeddableEditActionCompatible } = await getAsyncHelpers(); + const { isEmbeddableEditActionCompatible } = await import('../../../async_services'); return isEmbeddableEditActionCompatible(this.core, attributes); } @@ -47,7 +45,7 @@ export class EditLensEmbeddableAction implements Action<InlineEditLensEmbeddable onApply, onCancel, }: InlineEditLensEmbeddableContext) { - const { executeEditEmbeddableAction } = await getAsyncHelpers(); + const { executeEditEmbeddableAction } = await import('../../../async_services'); if (attributes) { executeEditEmbeddableAction({ deps: this.startDependencies, diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx index 0a3dc8feebe0..5eeaf01d2034 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/in_app_embeddable_edit_action_helpers.tsx @@ -4,18 +4,23 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React from 'react'; -import ReactDOM from 'react-dom'; -import type { CoreStart } from '@kbn/core/public'; +import type { CoreStart, OverlayRef } from '@kbn/core/public'; import { isOfAggregateQueryType } from '@kbn/es-query'; import { ENABLE_ESQL } from '@kbn/esql-utils'; -import { toMountPoint } from '@kbn/react-kibana-mount'; import { IncompatibleActionError } from '@kbn/ui-actions-plugin/public'; +import { BehaviorSubject } from 'rxjs'; +import '../helpers.scss'; +import { PublishingSubject } from '@kbn/presentation-publishing'; +import { generateId } from '../../../id_generator'; +import { setupPanelManagement } from '../../../react_embeddable/inline_editing/panel_management'; +import { prepareInlineEditPanel } from '../../../react_embeddable/inline_editing/setup_inline_editing'; +import { mountInlineEditPanel } from '../../../react_embeddable/inline_editing/mount'; +import type { TypedLensByValueInput, LensRuntimeState } from '../../../react_embeddable/types'; import type { LensPluginStartDependencies } from '../../../plugin'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; -import { extractReferencesFromState } from '../../../utils'; import type { LensChartLoadEvent } from './types'; +const asyncNoop = async () => {}; + export function isEmbeddableEditActionCompatible( core: CoreStart, attributes: TypedLensByValueInput['attributes'] @@ -49,106 +54,41 @@ export async function executeEditEmbeddableAction({ throw new IncompatibleActionError(); } - const { getEditLensConfiguration, getVisualizationMap, getDatasourceMap } = await import( - '../../../async_services' - ); - const visualizationMap = getVisualizationMap(); - const datasourceMap = getDatasourceMap(); - const query = attributes.state.query; - const activeDatasourceId = isOfAggregateQueryType(query) ? 'textBased' : 'formBased'; - - const onUpdatePanelState = ( - datasourceState: unknown, - visualizationState: unknown, - visualizationType?: string - ) => { - if (attributes.state) { - const datasourceStates = { - ...attributes.state.datasourceStates, - [activeDatasourceId]: datasourceState, - }; - - const references = extractReferencesFromState({ - activeDatasources: Object.keys(datasourceStates).reduce( - (acc, datasourceId) => ({ - ...acc, - [datasourceId]: datasourceMap[datasourceId], - }), - {} - ), - datasourceStates: Object.fromEntries( - Object.entries(datasourceStates).map(([id, state]) => [id, { isLoading: false, state }]) - ), - visualizationState, - activeVisualization: visualizationType ? visualizationMap[visualizationType] : undefined, - }); - - const attrs = { - ...attributes, - state: { - ...attributes.state, - visualization: visualizationState, - datasourceStates, - }, - references, - visualizationType: visualizationType ?? attributes.visualizationType, - } as TypedLensByValueInput['attributes']; - - onUpdate(attrs); - } - }; - - const onUpdateSuggestion = (attrs: TypedLensByValueInput['attributes']) => { - const newAttributes = { - ...attributes, - ...attrs, - }; - onUpdate(newAttributes); - }; - - const Component = await getEditLensConfiguration(core, deps, visualizationMap, datasourceMap); - const ConfigPanel = ( - <Component - attributes={attributes} - updatePanelState={onUpdatePanelState} - lensAdapters={lensEvent?.adapters} - output$={lensEvent?.embeddableOutput$} - displayFlyoutHeader - datasourceId={activeDatasourceId} - onApplyCb={onApply} - onCancelCb={onCancel} - canEditTextBasedQuery={activeDatasourceId === 'textBased'} - updateSuggestion={onUpdateSuggestion} - hideTimeFilterInfo={true} - /> + const uuid = generateId(); + const isNewlyCreated$ = new BehaviorSubject<boolean>(false); + const panelManagementApi = setupPanelManagement(uuid, container, { + isNewlyCreated$, + setAsCreated: () => isNewlyCreated$.next(false), + }); + const openInlineEditor = prepareInlineEditPanel( + { attributes }, + () => ({ attributes }), + (newState: LensRuntimeState) => + onUpdate(newState.attributes as TypedLensByValueInput['attributes']), + { + dataLoading$: + lensEvent?.dataLoading$ ?? + (new BehaviorSubject(undefined) as PublishingSubject<boolean | undefined>), + isNewlyCreated$, + }, + panelManagementApi, + { + getInspectorAdapters: () => lensEvent?.adapters, + inspect(): OverlayRef { + return { close: asyncNoop, onClose: Promise.resolve() }; + }, + closeInspector: asyncNoop, + adapters$: new BehaviorSubject(lensEvent?.adapters), + }, + { coreStart: core, ...deps } ); - // in case an element is given render the component in the container, - // otherwise a flyout will open - if (container) { - ReactDOM.render(ConfigPanel, container); - } else { - const handle = core.overlays.openFlyout( - toMountPoint( - React.cloneElement(ConfigPanel, { - closeFlyout: () => { - handle.close(); - }, - }), - core - ), - { - className: 'lnsConfigPanel__overlay', - size: 's', - 'data-test-subj': 'customizeLens', - type: 'push', - paddingSize: 'm', - hideCloseButton: true, - onClose: (overlayRef) => { - overlayRef.close(); - }, - outsideClickCloses: true, - } - ); + const ConfigPanel = await openInlineEditor({ + onApply, + onCancel, + }); + if (ConfigPanel) { + // no need to pass the uuid in this use case + mountInlineEditPanel(ConfigPanel, core, undefined, undefined, container); } } diff --git a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts index d86f05d4156e..0176ef4ee9e8 100644 --- a/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts +++ b/x-pack/plugins/lens/public/trigger_actions/open_lens_config/in_app_embeddable_edit/types.ts @@ -5,9 +5,8 @@ * 2.0. */ import type { DefaultInspectorAdapters } from '@kbn/expressions-plugin/common'; -import type { EmbeddableOutput } from '@kbn/embeddable-plugin/public'; -import type { Observable } from 'rxjs'; -import type { TypedLensByValueInput } from '../../../embeddable/embeddable_component'; +import { PublishingSubject } from '@kbn/presentation-publishing'; +import type { TypedLensByValueInput } from '../../../react_embeddable/types'; export interface LensChartLoadEvent { /** @@ -15,9 +14,9 @@ export interface LensChartLoadEvent { */ adapters: Partial<DefaultInspectorAdapters>; /** - * Observable of the lens embeddable output + * Observable to track embeddable loading state */ - embeddableOutput$?: Observable<EmbeddableOutput>; + dataLoading$?: PublishingSubject<boolean | undefined>; } export interface InlineEditLensEmbeddableContext { diff --git a/x-pack/plugins/lens/public/trigger_actions/utils.ts b/x-pack/plugins/lens/public/trigger_actions/utils.ts deleted file mode 100644 index 527f1adcf762..000000000000 --- a/x-pack/plugins/lens/public/trigger_actions/utils.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. - */ -import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import type { Embeddable } from '../embeddable'; -import { DOC_TYPE } from '../../common/constants'; - -export function isLensEmbeddable(embeddable: IEmbeddable): embeddable is Embeddable { - return embeddable.type === DOC_TYPE; -} diff --git a/x-pack/plugins/lens/public/types.ts b/x-pack/plugins/lens/public/types.ts index 5b5e33564cc7..d6dbccc492a6 100644 --- a/x-pack/plugins/lens/public/types.ts +++ b/x-pack/plugins/lens/public/types.ts @@ -10,7 +10,7 @@ import type { CoreStart, SavedObjectReference, ResolvedSimpleSavedObject } from import type { ColorMapping, PaletteOutput } from '@kbn/coloring'; import type { TopNavMenuData } from '@kbn/navigation-plugin/public'; import type { MutableRefObject, ReactElement } from 'react'; -import type { Filter, TimeRange } from '@kbn/es-query'; +import type { Query, AggregateQuery, Filter, TimeRange } from '@kbn/es-query'; import type { ExpressionAstExpression, IInterpreterRenderHandlers, @@ -22,7 +22,6 @@ import type { NavigateToLensContext, SeriesType, } from '@kbn/visualizations-plugin/common'; -import type { Query } from '@kbn/es-query'; import type { UiActionsStart, RowClickContext, @@ -63,7 +62,7 @@ import { import type { LensInspector } from './lens_inspector_service'; import type { DataViewsState } from './state_management/types'; import type { IndexPatternServiceAPI } from './data_views_service/service'; -import type { Document } from './persistence/saved_object_store'; +import type { LensDocument } from './persistence/saved_object_store'; import { TableInspectorAdapter } from './editor_frame_service/types'; export type StartServices = Pick< @@ -140,8 +139,8 @@ export interface EditorFrameInstance { export interface EditorFrameSetup { // generic type on the API functions to pull the "unknown vs. specific type" error into the implementation - registerDatasource: <T, P>( - datasource: Datasource<T, P> | (() => Promise<Datasource<T, P>>) + registerDatasource: <T, P, Q>( + datasource: Datasource<T, P, Q> | (() => Promise<Datasource<T, P, Q>>) ) => void; registerVisualization: <T, P, ExtraAppendLayerArg>( visualization: @@ -322,8 +321,11 @@ export type AddUserMessages = (messages: UserMessage[]) => () => void; /** * Interface for the datasource registry + * T type: runtime Lens state + * P type: persisted Lens state + * Q type: Query type (useful to filter form vs text based queries) */ -export interface Datasource<T = unknown, P = unknown> { +export interface Datasource<T = unknown, P = unknown, Q = Query | AggregateQuery> { id: string; alias?: string[]; @@ -382,7 +384,7 @@ export interface Datasource<T = unknown, P = unknown> { LayerSettingsComponent?: ( props: DatasourceLayerSettingsProps<T> ) => React.ReactElement<DatasourceLayerSettingsProps<T>> | null; - DataPanelComponent: (props: DatasourceDataPanelProps<T>) => JSX.Element | null; + DataPanelComponent: (props: DatasourceDataPanelProps<T, Q>) => JSX.Element | null; DimensionTriggerComponent: (props: DatasourceDimensionTriggerProps<T>) => JSX.Element | null; DimensionEditorComponent: ( props: DatasourceDimensionEditorProps<T> @@ -579,7 +581,7 @@ export interface DatasourceLayerSettingsProps<T = unknown> { setState: StateSetter<T>; } -export interface DatasourceDataPanelProps<T = unknown> { +export interface DatasourceDataPanelProps<T = unknown, Q = Query | AggregateQuery> { state: T; setState: StateSetter<T, { applyImmediately?: boolean }>; showNoDataPopover: () => void; @@ -587,7 +589,7 @@ export interface DatasourceDataPanelProps<T = unknown> { CoreStart, 'http' | 'notifications' | 'uiSettings' | 'overlays' | 'theme' | 'application' | 'docLinks' >; - query: Query; + query: Q; dateRange: DateRange; filters: Filter[]; dropOntoWorkspace: (field: DragDropIdentifier) => void; @@ -946,7 +948,7 @@ export interface VisualizationSuggestion<T = unknown> { export type DatasourceLayers = Partial<Record<string, DatasourcePublicAPI>>; export interface FramePublicAPI { - query: Query; + query: Query | AggregateQuery; filters: Filter[]; datasourceLayers: DatasourceLayers; dateRange: DateRange; @@ -1456,10 +1458,10 @@ export type LensTopNavMenuEntryGenerator = (props: { visualizationId: string; datasourceStates: Record<string, { state: unknown }>; visualizationState: unknown; - query: Query; + query: Query | AggregateQuery; filters: Filter[]; initialContext?: VisualizeFieldContext | VisualizeEditorContext; - currentDoc: Document | undefined; + currentDoc: LensDocument | undefined; }) => undefined | TopNavMenuData; export interface LensCellValueAction { @@ -1473,3 +1475,5 @@ export interface LensCellValueAction { export type GetCompatibleCellValueActions = ( data: CellValueContext['data'] ) => Promise<LensCellValueAction[]>; + +export type Simplify<T> = { [KeyType in keyof T]: T[KeyType] } & {}; diff --git a/x-pack/plugins/lens/public/user_messages_ids.ts b/x-pack/plugins/lens/public/user_messages_ids.ts index a57e5f871cbf..1bd15a642ba3 100644 --- a/x-pack/plugins/lens/public/user_messages_ids.ts +++ b/x-pack/plugins/lens/public/user_messages_ids.ts @@ -95,3 +95,6 @@ export const GAUGE_METRIC_GT_MAX = 'gauge_metric_gt_max'; export const GAUGE_GOAL_GT_MAX = 'gauge_goal_gt_max'; export const TEXT_BASED_LANGUAGE_ERROR = 'text_based_lang_error'; + +export const URL_CONFLICT = 'url-conflict'; +export const MISSING_TIME_RANGE_ON_EMBEDDABLE = 'missing-time-range-on-embeddable'; diff --git a/x-pack/plugins/lens/public/utils.ts b/x-pack/plugins/lens/public/utils.ts index 43129161adde..0b0c7037d076 100644 --- a/x-pack/plugins/lens/public/utils.ts +++ b/x-pack/plugins/lens/public/utils.ts @@ -20,7 +20,7 @@ import { ISearchStart } from '@kbn/data-plugin/public'; import type { DraggingIdentifier, DropType } from '@kbn/dom-drag-drop'; import { getAbsoluteTimeRange } from '@kbn/data-plugin/common'; import { DateRange } from '../common/types'; -import type { Document } from './persistence/saved_object_store'; +import type { LensDocument } from './persistence/saved_object_store'; import { Datasource, DatasourceMap, @@ -100,7 +100,7 @@ export function getTimeZone(uiSettings: IUiSettingsClient) { return configuredTimeZone; } -export function getActiveDatasourceIdFromDoc(doc?: Document) { +export function getActiveDatasourceIdFromDoc(doc?: LensDocument) { if (!doc) { return null; } @@ -109,14 +109,14 @@ export function getActiveDatasourceIdFromDoc(doc?: Document) { return firstDatasourceFromDoc || null; } -export function getActiveVisualizationIdFromDoc(doc?: Document) { +export function getActiveVisualizationIdFromDoc(doc?: LensDocument) { if (!doc) { return null; } return doc.visualizationType || null; } -export const getInitialDatasourceId = (datasourceMap: DatasourceMap, doc?: Document) => { +export const getInitialDatasourceId = (datasourceMap: DatasourceMap, doc?: LensDocument) => { return (doc && getActiveDatasourceIdFromDoc(doc)) || Object.keys(datasourceMap)[0] || null; }; diff --git a/x-pack/plugins/lens/public/vis_type_alias.ts b/x-pack/plugins/lens/public/vis_type_alias.ts index 5f08ce1b9ced..74e5a2a0d7ac 100644 --- a/x-pack/plugins/lens/public/vis_type_alias.ts +++ b/x-pack/plugins/lens/public/vis_type_alias.ts @@ -7,15 +7,22 @@ import { i18n } from '@kbn/i18n'; import type { VisTypeAlias } from '@kbn/visualizations-plugin/public'; -import { getBasePath, getEditPath } from '../common/constants'; +import { + APP_ID, + getBasePath, + getEditPath, + LENS_EMBEDDABLE_TYPE, + LENS_ICON, + STAGE_ID, +} from '../common/constants'; import { getLensClient } from './persistence/lens_client'; export const getLensAliasConfig = (): VisTypeAlias => ({ alias: { path: getBasePath(), - app: 'lens', + app: APP_ID, }, - name: 'lens', + name: APP_ID, promotion: true, title: i18n.translate('xpack.lens.visTypeAlias.title', { defaultMessage: 'Lens', @@ -25,11 +32,11 @@ export const getLensAliasConfig = (): VisTypeAlias => ({ 'Create visualizations using an intuitive drag-and-drop interface. Smart suggestions help you follow best practices and find the chart types that best match your data.', }), order: 60, - icon: 'lensApp', - stage: 'production', + icon: LENS_ICON, + stage: STAGE_ID, appExtensions: { visualizations: { - docTypes: ['lens'], + docTypes: [LENS_EMBEDDABLE_TYPE], searchFields: ['title^3'], clientOptions: { update: { overwrite: true } }, client: getLensClient, @@ -43,10 +50,10 @@ export const getLensAliasConfig = (): VisTypeAlias => ({ updatedAt, managed, editor: { editUrl: getEditPath(id), editApp: 'lens' }, - icon: 'lensApp', - stage: 'production', + icon: LENS_ICON, + stage: STAGE_ID, savedObjectType: type, - type: 'lens', + type: LENS_EMBEDDABLE_TYPE, typeTitle: i18n.translate('xpack.lens.visTypeAlias.type', { defaultMessage: 'Lens' }), }; }, diff --git a/x-pack/plugins/lens/public/visualization_container.scss b/x-pack/plugins/lens/public/visualization_container.scss index 3eb4061f8b93..488b138cb069 100644 --- a/x-pack/plugins/lens/public/visualization_container.scss +++ b/x-pack/plugins/lens/public/visualization_container.scss @@ -27,7 +27,7 @@ } // Make the visualization modifiers icon appear only on panel hover -.embPanel__content:hover .lnsEmbeddablePanelFeatureList_button { +.embPanel__content:hover .lnsPanelFeatureList_button { color: $euiTextColor; background: $euiColorEmptyShade; transition: color $euiAnimSpeedSlow, background $euiAnimSpeedSlow; diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.scss b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.scss index 0f0ed53a1002..117c6797c362 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.scss +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.scss @@ -1,5 +1,10 @@ .lnsDataTableContainer { height: 100%; + + // EUI issue to make background transparent https://github.com/elastic/eui/issues/8136 + .euiDataGrid__content { + background: transparent; + } } .lnsTableCell--multiline { diff --git a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx index 0633c13b8097..f30686a44a6a 100644 --- a/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx +++ b/x-pack/plugins/lens/public/visualizations/datatable/components/table_basic.tsx @@ -70,7 +70,8 @@ export const DataContext = React.createContext<DataContextType>({}); const gridStyle: EuiDataGridStyle = { border: 'horizontal', - header: 'underline', + header: 'shade', + footer: 'shade', }; export const DEFAULT_PAGE_SIZE = 10; diff --git a/x-pack/plugins/lens/tsconfig.json b/x-pack/plugins/lens/tsconfig.json index db249f19f361..39ec69385644 100644 --- a/x-pack/plugins/lens/tsconfig.json +++ b/x-pack/plugins/lens/tsconfig.json @@ -88,7 +88,6 @@ "@kbn/core-plugins-server", "@kbn/esql", "@kbn/field-utils", - "@kbn/panel-loader", "@kbn/shared-ux-button-toolbar", "@kbn/cell-actions", "@kbn/presentation-containers", @@ -111,9 +110,14 @@ "@kbn/licensing-plugin", "@kbn/react-kibana-context-render", "@kbn/react-kibana-mount", + "@kbn/embeddable-enhanced-plugin", "@kbn/es-types", "@kbn/esql-datagrid", "@kbn/transpose-utils", + "@kbn/core-application-browser", + "@kbn/core-chrome-browser", + "@kbn/core-capabilities-common", + "@kbn/presentation-panel-plugin", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/licensing/server/license_fetcher.test.ts b/x-pack/plugins/licensing/server/license_fetcher.test.ts index a8a64d300e9f..195c70c7c7c4 100644 --- a/x-pack/plugins/licensing/server/license_fetcher.test.ts +++ b/x-pack/plugins/licensing/server/license_fetcher.test.ts @@ -12,7 +12,8 @@ import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; type EsLicense = estypes.XpackInfoMinimalLicenseInformation; -const delay = (ms: number) => new Promise((res) => setTimeout(res, ms)); +const maxRetryDelay = 30 * 1000; +const sumOfRetryTimes = (1 + 2 + 4 + 8 + 16) * 1000; function buildRawLicense(options: Partial<EsLicense> = {}): EsLicense { return { @@ -33,6 +34,9 @@ describe('LicenseFetcher', () => { logger = loggerMock.create(); clusterClient = elasticsearchServiceMock.createClusterClient(); }); + afterEach(() => { + jest.useRealTimers(); + }); it('returns the license for successful calls', async () => { clusterClient.asInternalUser.xpack.info.mockResponse({ @@ -46,6 +50,7 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); const license = await fetcher(); @@ -71,6 +76,7 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); let license = await fetcher(); @@ -81,6 +87,7 @@ describe('LicenseFetcher', () => { }); it('returns an error license in case of error', async () => { + jest.useFakeTimers(); clusterClient.asInternalUser.xpack.info.mockResponseImplementation(() => { throw new Error('woups'); }); @@ -89,13 +96,20 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); - const license = await fetcher(); + const licensePromise = fetcher(); + await jest.advanceTimersByTimeAsync(sumOfRetryTimes); + const license = await licensePromise; + expect(license.error).toEqual('woups'); + // should be called once to start and then in the retries after 1s, 2s, 4s, 8s and 16s + expect(clusterClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(6); }); it('returns a license successfully fetched after an error', async () => { + jest.useFakeTimers(); clusterClient.asInternalUser.xpack.info .mockResponseImplementationOnce(() => { throw new Error('woups'); @@ -111,15 +125,20 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); - let license = await fetcher(); - expect(license.error).toEqual('woups'); - license = await fetcher(); + const licensePromise = fetcher(); + // wait one minute since we mocked only one error + await jest.advanceTimersByTimeAsync(1000); + const license = await licensePromise; + expect(license.uid).toEqual('license-1'); + expect(clusterClient.asInternalUser.xpack.info).toBeCalledTimes(2); }); it('returns the latest fetched license after an error within the cache duration period', async () => { + jest.useFakeTimers(); clusterClient.asInternalUser.xpack.info .mockResponseOnce({ license: buildRawLicense({ @@ -127,7 +146,7 @@ describe('LicenseFetcher', () => { }), features: {}, } as any) - .mockResponseImplementationOnce(() => { + .mockResponseImplementation(() => { throw new Error('woups'); }); @@ -135,15 +154,24 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); let license = await fetcher(); expect(license.uid).toEqual('license-1'); - license = await fetcher(); + expect(clusterClient.asInternalUser.xpack.info).toBeCalledTimes(1); + + const licensePromise = fetcher(); + await jest.advanceTimersByTimeAsync(sumOfRetryTimes); + license = await licensePromise; expect(license.uid).toEqual('license-1'); + // should be called once in the successful mock, once in the error mock + // and then in the retries after 1s, 2s, 4s, 8s and 16s + expect(clusterClient.asInternalUser.xpack.info).toBeCalledTimes(7); }); it('returns an error license after an error exceeding the cache duration period', async () => { + jest.useFakeTimers(); clusterClient.asInternalUser.xpack.info .mockResponseOnce({ license: buildRawLicense({ @@ -151,7 +179,7 @@ describe('LicenseFetcher', () => { }), features: {}, } as any) - .mockResponseImplementationOnce(() => { + .mockResponseImplementation(() => { throw new Error('woups'); }); @@ -159,14 +187,15 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 1, + maxRetryDelay, }); let license = await fetcher(); expect(license.uid).toEqual('license-1'); - await delay(50); - - license = await fetcher(); + const licensePromise = fetcher(); + await jest.advanceTimersByTimeAsync(sumOfRetryTimes); + license = await licensePromise; expect(license.error).toEqual('woups'); }); @@ -180,6 +209,7 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); const license = await fetcher(); @@ -203,6 +233,7 @@ describe('LicenseFetcher', () => { logger, clusterClient, cacheDurationMs: 50_000, + maxRetryDelay, }); const license = await fetcher(); @@ -213,4 +244,27 @@ describe('LicenseFetcher', () => { ] `); }); + + it('testing the fetcher retry with a different maxRetryDelay using only errors', async () => { + jest.useFakeTimers(); + clusterClient.asInternalUser.xpack.info.mockResponseImplementation(() => { + throw new Error('woups'); + }); + + const fetcher = getLicenseFetcher({ + logger, + clusterClient, + cacheDurationMs: 50_000, + maxRetryDelay: 10 * 1000, + }); + const sumOfRetryTimesUntilTen = (1 + 2 + 4 + 8) * 1000; + + const licensePromise = fetcher(); + await jest.advanceTimersByTimeAsync(sumOfRetryTimesUntilTen); + const license = await licensePromise; + + expect(license.error).toEqual('woups'); + // should be called once to start and then in the retries after 1s, 2s, 4s and 8s + expect(clusterClient.asInternalUser.xpack.info).toHaveBeenCalledTimes(5); + }); }); diff --git a/x-pack/plugins/licensing/server/license_fetcher.ts b/x-pack/plugins/licensing/server/license_fetcher.ts index 56a89fe221c9..278142e5c39b 100644 --- a/x-pack/plugins/licensing/server/license_fetcher.ts +++ b/x-pack/plugins/licensing/server/license_fetcher.ts @@ -7,6 +7,7 @@ import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { createHash } from 'crypto'; +import pRetry from 'p-retry'; import stringify from 'json-stable-stringify'; import type { MaybePromise } from '@kbn/utility-types'; import { isPromise } from '@kbn/std'; @@ -25,18 +26,23 @@ export const getLicenseFetcher = ({ clusterClient, logger, cacheDurationMs, + maxRetryDelay, }: { clusterClient: MaybePromise<IClusterClient>; logger: Logger; cacheDurationMs: number; + maxRetryDelay: number; }): LicenseFetcher => { let currentLicense: ILicense | undefined; let lastSuccessfulFetchTime: number | undefined; + const maxRetries = Math.floor(Math.log2(maxRetryDelay / 1000)) + 1; return async () => { const client = isPromise(clusterClient) ? await clusterClient : clusterClient; try { - const response = await client.asInternalUser.xpack.info(); + const response = await pRetry(() => client.asInternalUser.xpack.info(), { + retries: maxRetries, + }); const normalizedLicense = response.license && response.license.type !== 'missing' ? normalizeServerLicense(response.license) @@ -63,7 +69,9 @@ export const getLicenseFetcher = ({ lastSuccessfulFetchTime = Date.now(); return currentLicense; - } catch (error) { + } catch (err) { + const error = err.originalError ?? err; + logger.warn( `License information could not be obtained from Elasticsearch due to ${error} error` ); diff --git a/x-pack/plugins/licensing/server/plugin.ts b/x-pack/plugins/licensing/server/plugin.ts index 1f9cfaf20af7..77de999c4f95 100644 --- a/x-pack/plugins/licensing/server/plugin.ts +++ b/x-pack/plugins/licensing/server/plugin.ts @@ -125,6 +125,7 @@ export class LicensingPlugin implements Plugin<LicensingPluginSetup, LicensingPl clusterClient, logger: this.logger, cacheDurationMs: this.config.license_cache_duration.asMilliseconds(), + maxRetryDelay: pollingFrequency, }); const { license$, refreshManually } = createLicenseUpdate( diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx index 29b0f9080283..78e7c18fe43f 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/mvt_vector_layer/mvt_vector_layer.tsx @@ -426,6 +426,12 @@ export class MvtVectorLayer extends AbstractVectorLayer { this._setMbPointsProperties(mbMap, sourceData.tileSourceLayer); this._setMbLinePolygonProperties(mbMap, sourceData.tileSourceLayer); this._syncTooManyFeaturesProperties(mbMap); + (this.getSource() as IMvtVectorSource).syncSourceStyle?.(mbMap, () => + mbMap + .getStyle() + .layers.filter((mbLayer) => this.ownsMbLayerId(mbLayer.id)) + .map((layer) => layer.id) + ); } // TODO ES MVT specific - move to es_tiled_vector_layer implementation diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/mvt_vector_source.ts b/x-pack/plugins/maps/public/classes/sources/vector_source/mvt_vector_source.ts index 829afe5917cd..3f76befda67e 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/mvt_vector_source.ts +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/mvt_vector_source.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { Map as MbMap } from '@kbn/mapbox-gl'; import { VectorSourceRequestMeta } from '../../../../common/descriptor_types'; import { IVectorSource } from '.'; @@ -25,4 +26,9 @@ export interface IMvtVectorSource extends IVectorSource { * Use getTileSourceLayer to specify the displayed source layer. */ getTileSourceLayer(): string; + + /** + * Syncs source specific styling with mbMap this allows custom sources to further style the map layers/filters + */ + syncSourceStyle?(mbMap: MbMap, getLayerIds: () => string[]): void; } diff --git a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx index aeffc6f6c167..a3b2b494827b 100644 --- a/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx +++ b/x-pack/plugins/maps/public/classes/sources/vector_source/vector_source.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { ReactElement } from 'react'; import { FeatureCollection, GeoJsonProperties, @@ -22,6 +22,7 @@ import { Filter } from '@kbn/es-query'; import type { TimeRange } from '@kbn/es-query'; import { Adapters } from '@kbn/inspector-plugin/common/adapters'; import { ActionExecutionContext, Action } from '@kbn/ui-actions-plugin/public'; +import { IVectorStyle } from '../../styles/vector/vector_style'; import { GEO_JSON_TYPE, VECTOR_SHAPE_TYPE } from '../../../../common/constants'; import { TooltipFeatureAction } from '../../../../common/descriptor_types'; import { ITooltipProperty, TooltipProperty } from '../../tooltips/tooltip_property'; @@ -145,6 +146,15 @@ export interface IVectorSource extends ISource { * Provide unique ids for managing source requests in Inspector */ getInspectorRequestIds(): string[]; + + /** + * specifies if a source provides its own legend details or if the default vector_style is used if the source has this method it must also implement renderLegendDetails + */ + hasLegendDetails?(): Promise<boolean>; + /** + * specifies if a source provides its own legend details or if the default vector_style is used + */ + renderLegendDetails?(vectorStyle: IVectorStyle): ReactElement<any> | null; } export class AbstractVectorSource extends AbstractSource implements IVectorSource { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/style_error.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/style_error.tsx new file mode 100644 index 000000000000..06811f79517a --- /dev/null +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/style_error.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect, useState } from 'react'; +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiText, EuiToolTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { DynamicStyleProperty } from '../../properties/dynamic_style_property'; + +interface Props { + error: Error; + style: DynamicStyleProperty<object>; +} + +export const StyleError = ({ error, style }: Props) => { + const [label, setLabel] = useState(''); + const styleName = style.getDisplayStyleName(); + + useEffect(() => { + let canceled = false; + const getLabel = async () => { + const field = style.getField(); + if (!field) { + return; + } + + const fieldLabel = await field.getLabel(); + + if (canceled) { + return; + } + + setLabel(fieldLabel); + }; + + getLabel(); + + return () => { + canceled = true; + }; + }, [style]); + + return ( + <div> + <EuiFlexGroup gutterSize="xs" justifyContent="spaceBetween"> + <EuiFlexItem grow={false}> + <EuiToolTip position="top" title={styleName} content={label}> + <EuiText className="eui-textTruncate" size="xs" style={{ maxWidth: '180px' }}> + <small> + <strong>{label}</strong> + </small> + </EuiText> + </EuiToolTip> + </EuiFlexItem> + </EuiFlexGroup> + <EuiFlexGroup direction="column" gutterSize="none"> + <EuiCallOut + title={i18n.translate('xpack.maps.vectorStyleLegend.fetchStyleMetaDataError', { + defaultMessage: 'Unable to fetch style meta data', + })} + color="warning" + iconType="warning" + > + <p>{error.message}</p> + </EuiCallOut> + </EuiFlexGroup> + </div> + ); +}; diff --git a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/vector_style_legend.tsx b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/vector_style_legend.tsx index 60bcd05c9f73..afe1bbe19463 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/components/legend/vector_style_legend.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/components/legend/vector_style_legend.tsx @@ -8,6 +8,11 @@ import React from 'react'; import { EuiText } from '@elastic/eui'; import { euiThemeVars } from '@kbn/ui-theme'; +import { StyleError } from './style_error'; +import { + DynamicStyleProperty, + IDynamicStyleProperty, +} from '../../properties/dynamic_style_property'; import { FIELD_ORIGIN } from '../../../../../../common/constants'; import { Mask } from '../../../../layers/vector_layer/mask'; import { IStyleProperty } from '../../properties/style_property'; @@ -33,12 +38,22 @@ export function VectorStyleLegend({ const legendRows = []; for (let i = 0; i < styles.length; i++) { - const row = styles[i].renderLegendDetailRow({ - isLinesOnly, - isPointsOnly, - symbolId, - svg, - }); + const styleMetaDataRequest = styles[i].isDynamic() + ? (styles[i] as IDynamicStyleProperty<object>).getStyleMetaDataRequest() + : undefined; + + const error = styleMetaDataRequest?.getError(); + + const row = error ? ( + <StyleError error={error} style={styles[i] as DynamicStyleProperty<object>} /> + ) : ( + styles[i].renderLegendDetailRow({ + isLinesOnly, + isPointsOnly, + symbolId, + svg, + }) + ); legendRows.push( <div key={i} className="vectorStyleLegendSpacer"> diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx index e3751d9424dd..7790ebb0956b 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_style_property.tsx @@ -9,6 +9,7 @@ import _ from 'lodash'; import React from 'react'; import { FeatureCollection } from 'geojson'; import type { FeatureIdentifier, Map as MbMap } from '@kbn/mapbox-gl'; +import { DataRequest } from '../../../util/data_request'; import { AbstractStyleProperty, IStyleProperty } from './style_property'; import { DEFAULT_SIGMA } from '../vector_style_defaults'; import { @@ -97,6 +98,7 @@ export interface IDynamicStyleProperty<T> extends IStyleProperty<T> { mbMap: MbMap, mbSourceId: string ): boolean; + getStyleMetaDataRequest(): DataRequest | undefined; } export class DynamicStyleProperty<T extends object> @@ -122,6 +124,11 @@ export class DynamicStyleProperty<T extends object> this._getFieldFormatter = getFieldFormatter; } + getStyleMetaDataRequest() { + const dataRequestId = this._getStyleMetaDataRequestId(this.getFieldName()); + return dataRequestId ? this._layer.getDataRequest(dataRequestId) : undefined; + } + getValueSuggestions = async (query: string) => { return this._field === null ? [] @@ -147,12 +154,7 @@ export class DynamicStyleProperty<T extends object> } _getRangeFieldMetaFromStyleMetaRequest(): RangeFieldMeta | null { - const dataRequestId = this._getStyleMetaDataRequestId(this.getFieldName()); - if (!dataRequestId) { - return null; - } - - const styleMetaDataRequest = this._layer.getDataRequest(dataRequestId); + const styleMetaDataRequest = this.getStyleMetaDataRequest(); if (!styleMetaDataRequest || !styleMetaDataRequest.hasData()) { return null; } @@ -177,12 +179,7 @@ export class DynamicStyleProperty<T extends object> return null; } - const dataRequestId = this._getStyleMetaDataRequestId(this.getFieldName()); - if (!dataRequestId) { - return null; - } - - const styleMetaDataRequest = this._layer.getDataRequest(dataRequestId); + const styleMetaDataRequest = this.getStyleMetaDataRequest(); if (!styleMetaDataRequest || !styleMetaDataRequest.hasData()) { return null; } @@ -202,12 +199,7 @@ export class DynamicStyleProperty<T extends object> } _getCategoryFieldMetaFromStyleMetaRequest() { - const dataRequestId = this._getStyleMetaDataRequestId(this.getFieldName()); - if (!dataRequestId) { - return []; - } - - const styleMetaDataRequest = this._layer.getDataRequest(dataRequestId); + const styleMetaDataRequest = this.getStyleMetaDataRequest(); if (!styleMetaDataRequest || !styleMetaDataRequest.hasData()) { return []; } diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index 31c06728d811..0ec1a21fe56f 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -110,7 +110,7 @@ export interface IVectorStyle extends IStyle { getIconSvg(symbolId: string): string | undefined; isUsingCustomIcon(symbolId: string): boolean; hasLegendDetails: () => Promise<boolean>; - renderLegendDetails: () => ReactElement; + renderLegendDetails: () => ReactElement | null; clearFeatureState: (featureCollection: FeatureCollection, mbMap: MbMap, sourceId: string) => void; setFeatureStateAndStyleProps: ( featureCollection: FeatureCollection, @@ -721,14 +721,18 @@ export class VectorStyle implements IVectorStyle { }; async hasLegendDetails() { - return this._getLegendDetailStyleProperties().length > 0; + return this._source.hasLegendDetails && this._source.renderLegendDetails + ? await this._source.hasLegendDetails() + : this._getLegendDetailStyleProperties().length > 0; } renderLegendDetails() { const symbolId = this._getSymbolId(); const svg = symbolId ? this.getIconSvg(symbolId) : undefined; - return ( + return this._source.renderLegendDetails ? ( + this._source.renderLegendDetails(this) + ) : ( <VectorStyleLegend masks={this._layer.getMasks()} styles={this._getLegendDetailStyleProperties()} diff --git a/x-pack/plugins/maps/public/classes/util/data_request.tsx b/x-pack/plugins/maps/public/classes/util/data_request.tsx index 4554761ac0f4..12b9e6a66045 100644 --- a/x-pack/plugins/maps/public/classes/util/data_request.tsx +++ b/x-pack/plugins/maps/public/classes/util/data_request.tsx @@ -54,6 +54,10 @@ export class DataRequest { return this._descriptor.dataRequestToken; } + getError(): Error | undefined { + return this._descriptor.error; + } + renderError(): ReactNode { if (!this._descriptor.error) { return null; diff --git a/x-pack/plugins/ml/common/constants/alerts.ts b/x-pack/plugins/ml/common/constants/alerts.ts index 009345d23542..8ed9d61b418f 100644 --- a/x-pack/plugins/ml/common/constants/alerts.ts +++ b/x-pack/plugins/ml/common/constants/alerts.ts @@ -12,6 +12,7 @@ import { ALERT_RULE_NAME, ALERT_START, ALERT_STATUS, + AlertConsumers, ML_ANOMALY_DETECTION_RULE_TYPE_ID, } from '@kbn/rule-data-utils'; import type { JobsHealthTests } from '../types/alerts'; @@ -21,6 +22,9 @@ export const ML_ALERT_TYPES = { AD_JOBS_HEALTH: 'xpack.ml.anomaly_detection_jobs_health', } as const; +export const ML_RULE_TYPE_IDS = Object.values(ML_ALERT_TYPES); +export const ML_VALID_CONSUMERS = [AlertConsumers.ML, AlertConsumers.ALERTS]; + export type MlAlertType = (typeof ML_ALERT_TYPES)[keyof typeof ML_ALERT_TYPES]; export const ALERT_PREVIEW_SAMPLE_SIZE = 5; diff --git a/x-pack/plugins/ml/common/index.ts b/x-pack/plugins/ml/common/index.ts index bc53fc4247f2..dbb6c1a54ca1 100644 --- a/x-pack/plugins/ml/common/index.ts +++ b/x-pack/plugins/ml/common/index.ts @@ -8,5 +8,5 @@ export { getDefaultCapabilities as getDefaultMlCapabilities } from './types/capabilities'; export { DATAFEED_STATE, JOB_STATE } from './constants/states'; export type { MlSummaryJob, SummaryJobState } from './types/anomaly_detection_jobs'; -export { ML_ALERT_TYPES } from './constants/alerts'; +export { ML_ALERT_TYPES, ML_RULE_TYPE_IDS } from './constants/alerts'; export type { Job, Datafeed } from './types/anomaly_detection_jobs'; diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index e7a097fae7dc..b598a3bfd4d2 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -6,6 +6,7 @@ */ import type { KibanaRequest } from '@kbn/core/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { PLUGIN_ID } from '../constants/app'; import { ML_JOB_SAVED_OBJECT_TYPE, @@ -109,6 +110,11 @@ export function getDefaultCapabilities(): MlCapabilities { }; } +const alertingFeatures = Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN_ID, ALERTING_FEATURE_ID], +})); + export function getPluginPrivileges() { const apmUserMlCapabilitiesKeys = Object.keys(apmUserMlCapabilities); const userMlCapabilitiesKeys = Object.keys(userMlCapabilities); @@ -150,10 +156,10 @@ export function getPluginPrivileges() { }, alerting: { rule: { - all: Object.values(ML_ALERT_TYPES), + all: alertingFeatures, }, alert: { - all: Object.values(ML_ALERT_TYPES), + all: alertingFeatures, }, }, }, @@ -172,10 +178,10 @@ export function getPluginPrivileges() { }, alerting: { rule: { - read: Object.values(ML_ALERT_TYPES), + read: alertingFeatures, }, alert: { - read: Object.values(ML_ALERT_TYPES), + read: alertingFeatures, }, }, }, diff --git a/x-pack/plugins/ml/common/types/trained_models.ts b/x-pack/plugins/ml/common/types/trained_models.ts index 794d3123eee7..f4ed52ff21f5 100644 --- a/x-pack/plugins/ml/common/types/trained_models.ts +++ b/x-pack/plugins/ml/common/types/trained_models.ts @@ -193,6 +193,7 @@ export interface AllocatedModel { */ model_id?: string; state: string; + reason?: string; model_size_bytes: number; required_native_memory_bytes: number; node: { diff --git a/x-pack/plugins/ml/kibana.jsonc b/x-pack/plugins/ml/kibana.jsonc index 274a92c57a2c..5c4961de54e9 100644 --- a/x-pack/plugins/ml/kibana.jsonc +++ b/x-pack/plugins/ml/kibana.jsonc @@ -63,7 +63,8 @@ "lens", "maps", "savedObjectsFinder", - "usageCollection" + "usageCollection", + "alerting" ], "extraPublicDirs": [ "common" diff --git a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx index d06c46cc6f71..01f4d2d7be74 100644 --- a/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx +++ b/x-pack/plugins/ml/public/application/aiops/log_rate_analysis.tsx @@ -60,6 +60,7 @@ export const LogRateAnalysisPage: FC = () => { 'unifiedSearch', 'observabilityAIAssistant', 'embeddable', + 'cases', ]), }} /> diff --git a/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx b/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx index b9b680a9fbac..338c5a2a2b3c 100644 --- a/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx +++ b/x-pack/plugins/ml/public/application/explorer/alerts/alerts_panel.tsx @@ -15,9 +15,12 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ALERT_STATUS_ACTIVE, AlertConsumers, type AlertStatus } from '@kbn/rule-data-utils'; +import { ALERT_STATUS_ACTIVE, type AlertStatus } from '@kbn/rule-data-utils'; +import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; import React, { type FC, useState } from 'react'; import useObservable from 'react-use/lib/useObservable'; +import { ML_VALID_CONSUMERS } from '../../../../common/constants/alerts'; +import { ML_RULE_TYPE_IDS } from '../../../../common'; import { ML_ALERTS_CONFIG_ID } from '../../../alerting/anomaly_detection_alerts_table/register_alerts_table_configuration'; import { CollapsiblePanel } from '../../components/collapsible_panel'; import { useMlKibana } from '../../contexts/kibana'; @@ -42,13 +45,13 @@ export const AlertsPanel: FC = () => { const alertsQuery = useObservable(anomalyDetectionAlertsStateService.alertsQuery$, {}); const isLoading = useObservable(anomalyDetectionAlertsStateService.isLoading$, true); - const alertStateProps = { + const alertStateProps: AlertsTableStateProps = { alertsTableConfigurationRegistry: triggersActionsUi!.alertsTableConfigurationRegistry, configurationId: ML_ALERTS_CONFIG_ID, id: `ml-details-alerts`, - featureIds: [AlertConsumers.ML], + ruleTypeIds: ML_RULE_TYPE_IDS, + consumers: ML_VALID_CONSUMERS, query: alertsQuery, - showExpandToDetails: true, showAlertStatusWithFlapping: true, cellContext: { fieldFormats, diff --git a/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts b/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts index d02e9baf91c9..82bd60a4802a 100644 --- a/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts +++ b/x-pack/plugins/ml/public/application/explorer/alerts/anomaly_detection_alerts_state_service.ts @@ -21,7 +21,6 @@ import { ALERT_START, ALERT_STATUS, ALERT_UUID, - AlertConsumers, } from '@kbn/rule-data-utils'; import { isDefined } from '@kbn/ml-is-defined'; import { getSeverityColor } from '@kbn/ml-anomaly-utils'; @@ -30,6 +29,8 @@ import { ALERT_ANOMALY_SCORE, ALERT_ANOMALY_TIMESTAMP, ML_ALERT_TYPES, + ML_RULE_TYPE_IDS, + ML_VALID_CONSUMERS, } from '../../../../common/constants/alerts'; import { StateService } from '../../services/state_service'; import type { AnomalyTimelineStateService } from '../anomaly_timeline_state_service'; @@ -175,7 +176,8 @@ export class AnomalyDetectionAlertsStateService extends StateService { return this.data.search .search<RuleRegistrySearchRequest, RuleRegistrySearchResponse>( { - featureIds: [AlertConsumers.ML], + ruleTypeIds: ML_RULE_TYPE_IDS, + consumers: ML_VALID_CONSUMERS, query, }, { strategy: 'privateRuleRegistryAlertsSearchStrategy' } diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/__snapshots__/explorer_chart_label.test.js.snap b/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/__snapshots__/explorer_chart_label.test.js.snap index a02a73a20e00..3e30127f6eb9 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/__snapshots__/explorer_chart_label.test.js.snap +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/__snapshots__/explorer_chart_label.test.js.snap @@ -20,6 +20,7 @@ exports[`ExplorerChartLabelBadge Render the chart label in one line. 1`] = ` } } /> +   <span className="ml-explorer-chart-info-icon" @@ -97,6 +98,7 @@ exports[`ExplorerChartLabelBadge Render the chart label in two lines. 1`] = ` } } /> +   </span> </Fragment> `; diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/explorer_chart_label.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/explorer_chart_label.js index a83b1a5a472a..e1788be7ff76 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/explorer_chart_label.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/components/explorer_chart_label/explorer_chart_label.js @@ -22,6 +22,7 @@ export function ExplorerChartLabel({ isEmbeddable, wrapLabel = false, onSelectEntity, + showFilterIcons, }) { // Depending on whether we wrap the entityField badges to a new line, we render this differently: // @@ -51,13 +52,15 @@ export function ExplorerChartLabel({ return ( <Fragment key={`badge-wrapper-${key}`}> <ExplorerChartLabelBadge entity={entity} /> - {onSelectEntity !== undefined && ( + {onSelectEntity !== undefined && showFilterIcons === true ? ( <EntityFilter isEmbeddable={isEmbeddable} onFilter={applyFilter} influencerFieldName={entity.fieldName} influencerFieldValue={entity.fieldValue} /> + ) : ( + <> </> )} </Fragment> ); diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx index 17b867ff008a..97b30b66ff15 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_anomalies_container.tsx @@ -39,6 +39,7 @@ interface ExplorerAnomaliesContainerProps { showSelectedInterval?: boolean; chartsService: ChartsPluginStart; timeRange: { from: string; to: string } | undefined; + showFilterIcons: boolean; } const tooManyBucketsCalloutMsg = i18n.translate( @@ -63,6 +64,7 @@ export const ExplorerAnomaliesContainer: FC<ExplorerAnomaliesContainerProps> = ( showSelectedInterval, chartsService, timeRange, + showFilterIcons, }) => { return ( // TODO: Remove data-shared-item and data-rendering-count as part of https://github.com/elastic/kibana/issues/179376 @@ -102,6 +104,7 @@ export const ExplorerAnomaliesContainer: FC<ExplorerAnomaliesContainerProps> = ( showSelectedInterval, chartsService, id, + showFilterIcons, }} /> )} diff --git a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js index 360d7e821217..9bc1317a9aa5 100644 --- a/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js +++ b/x-pack/plugins/ml/public/application/explorer/explorer_charts/explorer_charts_container.js @@ -100,6 +100,7 @@ function ExplorerChartContainer({ tooManyBucketsCalloutMsg, showSelectedInterval, chartsService, + showFilterIcons, }) { const [explorerSeriesLink, setExplorerSeriesLink] = useState(''); const [mapsLink, setMapsLink] = useState(''); @@ -258,6 +259,7 @@ function ExplorerChartContainer({ infoTooltip={{ ...series.infoTooltip, chartType }} wrapLabel={wrapLabel} onSelectEntity={onSelectEntity} + showFilterIcons={showFilterIcons} /> </EuiFlexItem> <EuiFlexItem grow={false}> @@ -394,6 +396,7 @@ export const ExplorerChartsContainerUI = ({ tooManyBucketsCalloutMsg, showSelectedInterval, chartsService, + showFilterIcons = true, }) => { const { services: { embeddable: embeddablePlugin, maps: mapsPlugin }, @@ -460,6 +463,7 @@ export const ExplorerChartsContainerUI = ({ tooManyBucketsCalloutMsg={tooManyBucketsCalloutMsg} showSelectedInterval={showSelectedInterval} chartsService={chartsService} + showFilterIcons={showFilterIcons} /> </EuiFlexItem> ); diff --git a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts index 99e605fd5086..cda0e842f2c9 100644 --- a/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts +++ b/x-pack/plugins/ml/public/application/jobs/new_job/job_from_lens/quick_create_job.ts @@ -14,7 +14,7 @@ import type { import type { IUiSettingsClient } from '@kbn/core/public'; import type { TimefilterContract } from '@kbn/data-plugin/public'; import type { DataViewsContract } from '@kbn/data-views-plugin/public'; -import type { Filter, Query } from '@kbn/es-query'; +import { isOfAggregateQueryType, type Filter, type Query } from '@kbn/es-query'; import type { DashboardStart } from '@kbn/dashboard-plugin/public'; import type { LensApi } from '@kbn/lens-plugin/public'; import type { JobCreatorType } from '../common/job_creator'; @@ -198,6 +198,10 @@ export class QuickLensJobCreator extends QuickJobCreatorBase { bucketSpan: string, layerIndex?: number ) { + // @TODO: ask ML team to check if ES|QL query here is ok + if (isOfAggregateQueryType(chartInfo.query)) { + throw new Error('Cannot create job, query is of aggregate type'); + } const compatibleLayers = chartInfo.layers.filter(isCompatibleLayer); const selectedLayer = diff --git a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx index 4dd04780e2e9..cc9beceff555 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/nodes_overview/allocated_models.tsx @@ -57,15 +57,17 @@ export const AllocatedModels: FC<AllocatedModelsProps> = ({ { width: '8%', name: i18n.translate('xpack.ml.trainedModels.nodesList.modelsList.modelRoutingStateHeader', { - defaultMessage: 'Routing state', + defaultMessage: 'State', }), 'data-test-subj': 'mlAllocatedModelsTableRoutingState', render: (v: AllocatedModel) => { const { routing_state: routingState, reason } = v.node.routing_state; + const isFailed = routingState === 'failed'; + return ( <EuiToolTip content={reason ? reason : ''}> - <EuiBadge color={reason ? 'danger' : 'hollow'}>{routingState}</EuiBadge> + <EuiBadge color={isFailed ? 'danger' : 'hollow'}>{routingState}</EuiBadge> </EuiToolTip> ); }, @@ -252,7 +254,7 @@ export const AllocatedModels: FC<AllocatedModelsProps> = ({ }), 'data-test-subj': 'mlAllocatedModelsTableStartedTime', render: (v: AllocatedModel) => { - return dateFormatter(v.node.start_time); + return v.node.start_time ? dateFormatter(v.node.start_time) : '-'; }, }, { diff --git a/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.test.ts b/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.test.ts index 34875b893a86..4193251d76f3 100644 --- a/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.test.ts +++ b/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.test.ts @@ -627,6 +627,297 @@ describe('DeploymentParamsMapper', () => { }, }); }); + + describe('mapApiToUiDeploymentParams', () => { + it('should map API params to UI correctly', () => { + // Optimized for search + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + number_of_allocations: 2, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'medium', + }); + + // Lower value + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + number_of_allocations: 1, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'medium', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 8, + number_of_allocations: 2, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'medium', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 2, + number_of_allocations: 1, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'low', + }); + + // Exact match + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + number_of_allocations: 8, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'high', + }); + + // Higher value + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + number_of_allocations: 12, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'high', + }); + + // Lower value + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + number_of_allocations: 5, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'high', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + number_of_allocations: 6, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: false, + vCPUUsage: 'high', + }); + + // Optimized for ingest + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 1, + number_of_allocations: 1, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForIngest', + adaptiveResources: false, + vCPUUsage: 'low', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 1, + number_of_allocations: 2, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForIngest', + adaptiveResources: false, + vCPUUsage: 'low', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 1, + number_of_allocations: 6, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForIngest', + adaptiveResources: false, + vCPUUsage: 'medium', + }); + }); + + it('should map API params to UI correctly with adaptive resources', () => { + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 8, + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 2, + max_number_of_allocations: 2, + }, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: true, + vCPUUsage: 'medium', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 2, + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 2, + max_number_of_allocations: 2, + }, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: true, + vCPUUsage: 'medium', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 1, + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 1, + max_number_of_allocations: 1, + }, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForIngest', + adaptiveResources: true, + vCPUUsage: 'low', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 2, + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 0, + max_number_of_allocations: 1, + }, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: true, + vCPUUsage: 'low', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 1, + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 0, + max_number_of_allocations: 64, + }, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForIngest', + adaptiveResources: true, + vCPUUsage: 'high', + }); + + expect( + mapper.mapApiToUiDeploymentParams({ + model_id: modelId, + deployment_id: 'test-deployment', + priority: 'normal', + threads_per_allocation: 16, + adaptive_allocations: { + enabled: true, + min_number_of_allocations: 0, + max_number_of_allocations: 12, + }, + } as unknown as MlTrainedModelAssignmentTaskParametersAdaptive) + ).toEqual({ + deploymentId: 'test-deployment', + optimized: 'optimizedForSearch', + adaptiveResources: true, + vCPUUsage: 'high', + }); + }); + }); }); }); }); diff --git a/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.ts b/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.ts index ecb8a06198b1..96ba5f0755ca 100644 --- a/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.ts +++ b/x-pack/plugins/ml/public/application/model_management/deployment_params_mapper.ts @@ -25,7 +25,7 @@ type VCPUBreakpoints = Record< max: number; /** * Static value is used for the number of vCPUs when the adaptive resources are disabled. - * Not allowed in certain environments. + * Not allowed in certain environments, Obs and Security serverless projects. */ static?: number; } @@ -89,6 +89,7 @@ export class DeploymentParamsMapper { ) { /** * Initial value can be different for serverless and ESS with autoscaling. + * Also not available with 0 ML active nodes. */ const maxSingleMlNodeProcessors = this.mlServerLimits.max_single_ml_node_processors; @@ -236,18 +237,25 @@ export class DeploymentParamsMapper { ? input.adaptive_allocations!.max_number_of_allocations! : input.number_of_allocations); + // The deployment can be created via API with a number of allocations that do not exactly match our vCPU ranges. + // In this case, we should find the closest vCPU range that does not exceed the max or static value of the range. const [vCPUUsage] = Object.entries(this.vCpuBreakpoints) - .reverse() - .find(([key, val]) => vCPUs >= val.min) as [ - DeploymentParamsUI['vCPUUsage'], - { min: number; max: number } - ]; + .filter(([, range]) => vCPUs <= (adaptiveResources ? range.max : range.static!)) + .reduce( + (prev, curr) => { + const prevValue = adaptiveResources ? prev[1].max : prev[1].static!; + const currValue = adaptiveResources ? curr[1].max : curr[1].static!; + return Math.abs(vCPUs - prevValue) <= Math.abs(vCPUs - currValue) ? prev : curr; + }, + // in case allocation params exceed the max value of the high range + ['high', this.vCpuBreakpoints.high] + ); return { deploymentId: input.deployment_id, optimized, adaptiveResources, - vCPUUsage, + vCPUUsage: vCPUUsage as DeploymentParamsUI['vCPUUsage'], }; } } diff --git a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx index f7e95e3eda52..f44dc55dab2d 100644 --- a/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx +++ b/x-pack/plugins/ml/public/application/model_management/expanded_row.tsx @@ -169,13 +169,40 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { license_level, ]); - const deploymentStatItems: AllocatedModel[] = useMemo<AllocatedModel[]>(() => { + const deploymentStatItems = useMemo<AllocatedModel[]>(() => { const deploymentStats = stats.deployment_stats; const modelSizeStats = stats.model_size_stats; if (!deploymentStats || !modelSizeStats) return []; - const items: AllocatedModel[] = deploymentStats.flatMap((perDeploymentStat) => { + return deploymentStats.flatMap((perDeploymentStat) => { + // A deployment can be in a starting state and not allocated to any node yet. + if (perDeploymentStat.nodes.length < 1) { + return [ + { + key: `${perDeploymentStat.deployment_id}_no_node`, + ...perDeploymentStat, + ...modelSizeStats, + node: { + name: '-', + average_inference_time_ms: 0, + inference_count: 0, + routing_state: { + routing_state: perDeploymentStat.state, + reason: perDeploymentStat.reason, + }, + last_access: 0, + number_of_pending_requests: 0, + start_time: 0, + throughput_last_minute: 0, + number_of_allocations: 0, + threads_per_allocation: 0, + error_count: 0, + }, + }, + ]; + } + return perDeploymentStat.nodes.map((n) => { const nodeName = Object.values(n.node)[0].name; return { @@ -201,8 +228,6 @@ export const ExpandedRow: FC<ExpandedRowProps> = ({ item }) => { }; }); }); - - return items; }, [stats]); const hideColumns = useMemo(() => { diff --git a/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx b/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx index ebebb25671f5..cee2a92f03ad 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/trained_models/models_list.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import type { FC } from 'react'; +import { type FC, useCallback } from 'react'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -19,6 +19,7 @@ import { useRouteResolver } from '../../use_resolver'; import { basicResolvers } from '../../resolvers'; import { getBreadcrumbWithUrlForApp } from '../../breadcrumbs'; import { MlPageHeader } from '../../../components/page_header'; +import { useSavedObjectsApiService } from '../../../services/ml_api_service/saved_objects'; const ModelsList = dynamic(async () => ({ default: (await import('../../../model_management/models_list')).ModelsList, @@ -48,7 +49,20 @@ export const modelsListRouteFactory = ( }); const PageWrapper: FC = () => { - const { context } = useRouteResolver('full', ['canGetTrainedModels'], basicResolvers()); + const { initSavedObjects } = useSavedObjectsApiService(); + + const initSavedObjectsWrapper = useCallback(async () => { + try { + await initSavedObjects(); + } catch (error) { + // ignore error as user may not have permission to sync + } + }, [initSavedObjects]); + + const { context } = useRouteResolver('full', ['canGetTrainedModels'], { + ...basicResolvers(), + initSavedObjectsWrapper, + }); return ( <PageLoader context={context}> diff --git a/x-pack/plugins/ml/public/cases/anomaly_charts_attachments.tsx b/x-pack/plugins/ml/public/cases/anomaly_charts_attachments.tsx index 71b854100bd4..716078512e88 100644 --- a/x-pack/plugins/ml/public/cases/anomaly_charts_attachments.tsx +++ b/x-pack/plugins/ml/public/cases/anomaly_charts_attachments.tsx @@ -80,6 +80,7 @@ const AnomalyChartsCaseAttachment = ({ onRenderComplete={api.onRenderComplete} onError={api.onError} timeRange$={api.parentApi.timeRange$} + showFilterIcons={false} /> </KibanaContextProvider> </KibanaRenderContextProvider> diff --git a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_react_container.tsx b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_react_container.tsx index aefdac533f85..8f64ec88411c 100644 --- a/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_react_container.tsx +++ b/x-pack/plugins/ml/public/embeddables/anomaly_charts/anomaly_charts_react_container.tsx @@ -51,6 +51,7 @@ export interface AnomalyChartsContainerProps onRenderComplete: () => void; onLoading: (v: boolean) => void; onError: (error: Error) => void; + showFilterIcons?: boolean; } const AnomalyChartsContainer: FC<AnomalyChartsContainerProps> = ({ @@ -62,6 +63,7 @@ const AnomalyChartsContainer: FC<AnomalyChartsContainerProps> = ({ onError, onLoading, api, + showFilterIcons = true, }) => { const isMounted = useMountedState(); @@ -284,6 +286,7 @@ const AnomalyChartsContainer: FC<AnomalyChartsContainerProps> = ({ showSelectedInterval={false} chartsService={chartsService} timeRange={timeRange} + showFilterIcons={showFilterIcons} /> ) : null} </div> diff --git a/x-pack/plugins/ml/server/lib/node_utils.ts b/x-pack/plugins/ml/server/lib/node_utils.ts index d8098e3c43f4..9c5c0348f03d 100644 --- a/x-pack/plugins/ml/server/lib/node_utils.ts +++ b/x-pack/plugins/ml/server/lib/node_utils.ts @@ -33,7 +33,7 @@ export async function getMlNodeCount(client: IScopedClusterClient): Promise<MlNo return { count, lazyNodeCount }; } -export async function getLazyMlNodeCount(client: IScopedClusterClient) { +export async function getLazyMlNodeCount(client: IScopedClusterClient): Promise<number> { const body = await client.asInternalUser.cluster.getSettings( { include_defaults: true, diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/logo.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/logo.json new file mode 100644 index 000000000000..862f970b7405 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/logo.json @@ -0,0 +1,3 @@ +{ + "icon": "logoSecurity" +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/manifest.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/manifest.json new file mode 100644 index 000000000000..46d35c3761b6 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/manifest.json @@ -0,0 +1,60 @@ +{ + "id": "security_host", + "title": "Security: Host", + "description": "Detect anomalous activity in your ECS-compatible host-based logs.", + "type": "Host data", + "logoFile": "logo.json", + "defaultIndexPattern": "auditbeat-*,logs-*,filebeat-*,winlogbeat-*", + "query": { + "bool": { + "filter": [ + { + "exists": { + "field": "event.category" + } + }, + { + "exists": { + "field": "host.name" + } + }, + { + "exists": { + "field": "event.dataset" + } + }, + { + "term": { + "event.outcome": "success" + } + } + ], + "must_not": { "terms": { "_tier": ["data_frozen", "data_cold"] } } + } + }, + "jobs": [ + { + "id": "high_count_events_for_a_host_name", + "file": "high_count_events_for_a_host_name.json" + }, + { + "id": "low_count_events_for_a_host_name", + "file": "low_count_events_for_a_host_name.json" + } + ], + "datafeeds": [ + { + "id": "datafeed-high_count_events_for_a_host_name", + "file": "datafeed_high_count_events_for_a_host_name.json", + "job_id": "high_count_events_for_a_host_name" + }, + { + "id": "datafeed-low_count_events_for_a_host_name", + "file": "datafeed_low_count_events_for_a_host_name.json", + "job_id": "low_count_events_for_a_host_name" + } + ], + "tags": [ + "security" + ] +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/datafeed_high_count_events_for_a_host_name.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/datafeed_high_count_events_for_a_host_name.json new file mode 100644 index 000000000000..2e6792469a2c --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/datafeed_high_count_events_for_a_host_name.json @@ -0,0 +1,33 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [ + { + "exists": { + "field": "event.category" + } + }, + { + "exists": { + "field": "host.name" + } + }, + { + "exists": { + "field": "event.dataset" + } + }, + { + "term": { + "event.outcome": "success" + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/datafeed_low_count_events_for_a_host_name.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/datafeed_low_count_events_for_a_host_name.json new file mode 100644 index 000000000000..2e6792469a2c --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/datafeed_low_count_events_for_a_host_name.json @@ -0,0 +1,33 @@ +{ + "job_id": "JOB_ID", + "indices": [ + "INDEX_PATTERN_NAME" + ], + "max_empty_searches": 10, + "query": { + "bool": { + "filter": [ + { + "exists": { + "field": "event.category" + } + }, + { + "exists": { + "field": "host.name" + } + }, + { + "exists": { + "field": "event.dataset" + } + }, + { + "term": { + "event.outcome": "success" + } + } + ] + } + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/high_count_events_for_a_host_name.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/high_count_events_for_a_host_name.json new file mode 100644 index 000000000000..f103d2b34c5a --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/high_count_events_for_a_host_name.json @@ -0,0 +1,29 @@ +{ + "description": "Security: Host - Looks for a sudden spike in host based traffic. This can be due to a range of security issues, such as a compromised system, DDoS attacks, malware infections, privilege escalation, or data exfiltration.", + "groups": ["security", "host"], + "analysis_config": { + "bucket_span": "3h", + "detectors": [ + { + "detector_description": "high count of host based events", + "function": "high_count", + "partition_field_name": "host.name", + "detector_index": 0 + } + ], + "influencers": ["host.name", "host.ip", "event.dataset", "event.action", "event.category"] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "128mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-security-host", + "security_app_display_name": "Spike in the Host Traffic", + "managed": true, + "job_revision": 1 + } +} diff --git a/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/low_count_events_for_a_host_name.json b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/low_count_events_for_a_host_name.json new file mode 100644 index 000000000000..ae8bfd163826 --- /dev/null +++ b/x-pack/plugins/ml/server/models/data_recognizer/modules/security_host/ml/low_count_events_for_a_host_name.json @@ -0,0 +1,29 @@ +{ + "description": "Security: Host - Looks for a sudden drop in host based traffic. This can be due to a range of security issues, such as a compromised system, a failed service, or a network misconfiguration.", + "groups": ["security", "host"], + "analysis_config": { + "bucket_span": "3h", + "detectors": [ + { + "detector_description": "low count of host based events", + "function": "low_count", + "partition_field_name": "host.name", + "detector_index": 0 + } + ], + "influencers": ["host.name", "host.ip", "event.dataset", "event.action", "event.category"] + }, + "allow_lazy_open": true, + "analysis_limits": { + "model_memory_limit": "128mb" + }, + "data_description": { + "time_field": "@timestamp" + }, + "custom_settings": { + "created_by": "ml-module-security-host", + "security_app_display_name": "Decrease in the Host Traffic", + "managed": true, + "job_revision": 1 + } +} diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 01f3ec7e5d13..ba6c5387a93c 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -26,6 +26,7 @@ import type { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import type { CasesServerSetup } from '@kbn/cases-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import type { PluginsSetup, PluginsStart, RouteInitialization } from './types'; import type { MlCapabilities } from '../common/types/capabilities'; @@ -142,7 +143,10 @@ export class MlServerPlugin management: { insightsAndAlerting: ['jobsListLink', 'triggersActions'], }, - alerting: Object.values(ML_ALERT_TYPES), + alerting: Object.values(ML_ALERT_TYPES).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN_ID, ALERTING_FEATURE_ID], + })), privileges: { all: admin, read: user, diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 3814d36bc3a6..8c9f90db3818 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -135,7 +135,7 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response, context }) => { try { const alerting = await context.alerting; - const rulesClient = alerting?.getRulesClient(); + const rulesClient = await alerting?.getRulesClient(); const { deleteJobs } = jobServiceProvider(client, mlClient, rulesClient); const { jobIds, deleteUserAnnotations, deleteAlertingRules } = request.body; @@ -283,7 +283,8 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response, context }) => { try { const alerting = await context.alerting; - const { jobsSummary } = jobServiceProvider(client, mlClient, alerting?.getRulesClient()); + const rulesClient = await alerting?.getRulesClient(); + const { jobsSummary } = jobServiceProvider(client, mlClient, rulesClient); const { jobIds } = request.body; const resp = await jobsSummary(jobIds); @@ -317,11 +318,8 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, response, context }) => { try { const alerting = await context.alerting; - const { getJobIdsWithGeo } = jobServiceProvider( - client, - mlClient, - alerting?.getRulesClient() - ); + const rulesClient = await alerting?.getRulesClient(); + const { getJobIdsWithGeo } = jobServiceProvider(client, mlClient, rulesClient); const resp = await getJobIdsWithGeo(); @@ -425,11 +423,9 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { routeGuard.fullLicenseAPIGuard(async ({ client, mlClient, request, response, context }) => { try { const alerting = await context.alerting; - const { createFullJobsList } = jobServiceProvider( - client, - mlClient, - alerting?.getRulesClient() - ); + const rulesClient = await alerting?.getRulesClient(); + + const { createFullJobsList } = jobServiceProvider(client, mlClient, rulesClient); const { jobIds } = request.body; const resp = await createFullJobsList(jobIds); diff --git a/x-pack/plugins/ml/server/routes/system.ts b/x-pack/plugins/ml/server/routes/system.ts index d4127a742839..150fc3c75a10 100644 --- a/x-pack/plugins/ml/server/routes/system.ts +++ b/x-pack/plugins/ml/server/routes/system.ts @@ -14,7 +14,7 @@ import { mlLog } from '../lib/log'; import { capabilitiesProvider } from '../lib/capabilities'; import { spacesUtilsProvider } from '../lib/spaces_utils'; import type { RouteInitialization, SystemRouteDeps } from '../types'; -import { getMlNodeCount } from '../lib/node_utils'; +import { getLazyMlNodeCount, getMlNodeCount } from '../lib/node_utils'; /** * System routes @@ -187,10 +187,15 @@ export function systemRoutes( let isMlAutoscalingEnabled = false; try { - await client.asInternalUser.autoscaling.getAutoscalingPolicy({ name: 'ml' }); + // kibana_system user does not have the manage_autoscaling cluster privilege. + // perform this check as a current user. + await client.asCurrentUser.autoscaling.getAutoscalingPolicy({ name: 'ml' }); isMlAutoscalingEnabled = true; } catch (e) { - // If doesn't exist, then keep the false + // If ml autoscaling policy doesn't exist or the user does not have privileges to fetch it, + // check the number of lazy ml nodes to determine if autoscaling is enabled. + const lazyMlNodeCount = await getLazyMlNodeCount(client); + isMlAutoscalingEnabled = lazyMlNodeCount > 0; } return response.ok({ diff --git a/x-pack/plugins/monitoring/common/constants.ts b/x-pack/plugins/monitoring/common/constants.ts index 25b22722a33b..89dcba563778 100644 --- a/x-pack/plugins/monitoring/common/constants.ts +++ b/x-pack/plugins/monitoring/common/constants.ts @@ -151,11 +151,6 @@ export const METRICBEAT_INDEX_NAME_UNIQUE_TOKEN = '-mb-'; // We use this for metricbeat migration to identify specific products that we do not have constants for export const ELASTICSEARCH_SYSTEM_ID = 'elasticsearch'; -/** - * The id of the infra source owned by the monitoring plugin. - */ -export const INFRA_SOURCE_ID = 'internal-stack-monitoring'; - /* * These constants represent code paths within `getClustersFromRequest` * that an api call wants to invoke. This is meant as an optimization to diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts b/x-pack/plugins/monitoring/common/get_index_patterns.test.ts similarity index 98% rename from x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts rename to x-pack/plugins/monitoring/common/get_index_patterns.test.ts index c13217ab0abc..7727d5e04916 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.test.ts +++ b/x-pack/plugins/monitoring/common/get_index_patterns.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { DS_INDEX_PATTERN_TYPES } from '../../../common/constants'; -import { MonitoringConfig } from '../..'; +import { DS_INDEX_PATTERN_TYPES } from './constants'; +import { MonitoringConfig } from '../server'; import { getElasticsearchDataset, getKibanaDataset, diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts b/x-pack/plugins/monitoring/common/get_index_patterns.ts similarity index 96% rename from x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts rename to x-pack/plugins/monitoring/common/get_index_patterns.ts index 4f293baf613b..d0f19e622eed 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_index_patterns.ts +++ b/x-pack/plugins/monitoring/common/get_index_patterns.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { prefixIndexPatternWithCcs } from '../../../common/ccs_utils'; +import { prefixIndexPatternWithCcs } from './ccs_utils'; import { INDEX_PATTERN_ELASTICSEARCH, INDEX_PATTERN_ELASTICSEARCH_ECS, @@ -16,8 +16,8 @@ import { DS_INDEX_PATTERN_METRICS, INDEX_PATTERN_TYPES, INDEX_PATTERN_ENTERPRISE_SEARCH, -} from '../../../common/constants'; -import { MonitoringConfig } from '../../config'; +} from './constants'; +import type { MonitoringConfig } from '../server/config'; interface CommonIndexPatternArgs { config: MonitoringConfig; diff --git a/x-pack/plugins/monitoring/kibana.jsonc b/x-pack/plugins/monitoring/kibana.jsonc index 5b9b2853357b..334ffd05890b 100644 --- a/x-pack/plugins/monitoring/kibana.jsonc +++ b/x-pack/plugins/monitoring/kibana.jsonc @@ -26,7 +26,6 @@ ], "optionalPlugins": [ "infra", - "logsShared", "usageCollection", "home", "cloud", @@ -41,7 +40,6 @@ "kibanaUtils", "alerting", "kibanaReact", - "logsShared" ] } } \ No newline at end of file diff --git a/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx b/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx index 2cca4638876c..f1e84753820f 100644 --- a/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx +++ b/x-pack/plugins/monitoring/public/alerts/alert_form.test.tsx @@ -270,6 +270,7 @@ describe('alert_form', () => { actionTypeRegistry={actionTypeRegistry} featureId="alerting" producerId="alerting" + ruleTypeId=".es-query" /> </KibanaReactContext.Provider> </I18nProvider> diff --git a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap index a3d5e96d6ef2..91b3dea5ab04 100644 --- a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap @@ -12,10 +12,8 @@ exports[`Logs should render a link to filter by cluster uuid 1`] = ` id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": <EuiLink - href="" - > - Logs + "link": <EuiLink> + Discover </EuiLink>, } } @@ -36,10 +34,8 @@ exports[`Logs should render a link to filter by cluster uuid and index uuid 1`] id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": <EuiLink - href="" - > - Logs + "link": <EuiLink> + Discover </EuiLink>, } } @@ -60,10 +56,8 @@ exports[`Logs should render a link to filter by cluster uuid and node uuid 1`] = id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": <EuiLink - href="" - > - Logs + "link": <EuiLink> + Discover </EuiLink>, } } @@ -290,10 +284,8 @@ exports[`Logs should render normally 1`] = ` id="xpack.monitoring.logs.listing.linkText" values={ Object { - "link": <EuiLink - href="" - > - Logs + "link": <EuiLink> + Discover </EuiLink>, } } diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.js b/x-pack/plugins/monitoring/public/components/logs/logs.js index 3da4bc9dc13f..82fdac6ea1f0 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.js @@ -5,7 +5,7 @@ * 2.0. */ -import React, { PureComponent } from 'react'; +import React, { PureComponent, useContext } from 'react'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { upperFirst } from 'lodash'; import { Legacy } from '../../legacy_shims'; @@ -15,7 +15,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { Reason } from './reason'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; +import { ExternalConfigContext } from '../../application/contexts/external_config_context'; const getFormattedDateTimeLocal = (timestamp) => { const timezone = Legacy.shims.uiSettings?.get('dateFormat:tz'); @@ -111,7 +111,7 @@ const clusterColumns = [ }, ]; -function getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin) { +function getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndices) { const params = []; if (clusterUuid) { params.push(`elasticsearch.cluster.uuid:${clusterUuid}`); @@ -124,10 +124,17 @@ function getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin) { } const filter = params.join(' and '); - const { logsLocator } = getLogsLocatorsFromUrlService(sharePlugin.url); + const discoverLocator = sharePlugin.url.locators.get('DISCOVER_APP_LOCATOR'); - const base = logsLocator.getRedirectUrl({ - filter, + const base = discoverLocator.getRedirectUrl({ + dataViewSpec: { + id: logsIndices, + title: logsIndices, + }, + query: { + language: 'kuery', + query: filter, + }, }); return base; @@ -137,7 +144,8 @@ export const Logs = (props) => { const { services: { share }, } = useKibana(); - return <LogsContent sharePlugin={share} {...props} />; + const externalConfig = useContext(ExternalConfigContext); + return <LogsContent sharePlugin={share} logsIndices={externalConfig.logsIndices} {...props} />; }; export class LogsContent extends PureComponent { renderLogs() { @@ -168,13 +176,15 @@ export class LogsContent extends PureComponent { renderCallout() { const { capabilities: uiCapabilities, infra, kibanaServices } = Legacy.shims; - const show = uiCapabilities.logs && uiCapabilities.logs.show; + const show = uiCapabilities.discover && uiCapabilities.discover.show; + const { logs: { enabled }, nodeId, clusterUuid, indexUuid, sharePlugin, + logsIndices, } = this.props; if (!enabled || !show) { @@ -195,9 +205,11 @@ export class LogsContent extends PureComponent { defaultMessage="Visit {link} to dive deeper." values={{ link: ( - <EuiLink href={getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin)}> + <EuiLink + href={getLogsUiLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndices)} + > {i18n.translate('xpack.monitoring.logs.listing.calloutLinkText', { - defaultMessage: 'Logs', + defaultMessage: 'Discover', })} </EuiLink> ), diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.test.js b/x-pack/plugins/monitoring/public/components/logs/logs.test.js index 1117a484a294..9d3f68c85450 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.test.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.test.js @@ -10,32 +10,26 @@ import { shallow } from 'enzyme'; import { LogsContent } from './logs'; import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; -const sharePlugin = sharePluginMock.createStartContract(); - -jest.mock('@kbn/logs-shared-plugin/common', () => { - return { - getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({ - logsLocator: { getRedirectUrl: jest.fn(() => '') }, - }), - }; -}); - jest.mock('../../legacy_shims', () => ({ Legacy: { shims: { getBasePath: () => '', - capabilities: { logs: { show: true } }, - infra: { - locators: { - logsLocator: { - getRedirectUrl: () => '', - }, - }, - }, + capabilities: { discover: { show: true } }, + infra: {}, }, }, })); +const sharePlugin = { + url: { + locators: { + get: () => { + return sharePluginMock.createLocator(); + }, + }, + }, +}; + const logs = { enabled: true, limit: 10, @@ -134,39 +128,69 @@ const logs = { describe('Logs', () => { it('should render normally', () => { - const component = shallow(<LogsContent sharePlugin={sharePlugin} logs={logs} />); + const component = shallow( + <LogsContent sharePlugin={sharePlugin} logsIndices={'logs-*,*:logs-*'} logs={logs} /> + ); expect(component).toMatchSnapshot(); }); it('should render fewer columns for node or index view', () => { - const component = shallow(<LogsContent sharePlugin={sharePlugin} logs={logs} nodeId="12345" />); + const component = shallow( + <LogsContent + sharePlugin={sharePlugin} + logsIndices={'logs-*,*:logs-*'} + logs={logs} + nodeId="12345" + /> + ); expect(component.find('EuiBasicTable').prop('columns')).toMatchSnapshot(); }); it('should render a link to filter by cluster uuid', () => { const component = shallow( - <LogsContent sharePlugin={sharePlugin} logs={logs} clusterUuid="12345" /> + <LogsContent + sharePlugin={sharePlugin} + logsIndices={'logs-*,*:logs-*'} + logs={logs} + clusterUuid="12345" + /> ); expect(component.find('EuiCallOut')).toMatchSnapshot(); }); it('should render a link to filter by cluster uuid and node uuid', () => { const component = shallow( - <LogsContent sharePlugin={sharePlugin} logs={logs} clusterUuid="12345" nodeId="6789" /> + <LogsContent + sharePlugin={sharePlugin} + logsIndices={'logs-*,*:logs-*'} + logs={logs} + clusterUuid="12345" + nodeId="6789" + /> ); expect(component.find('EuiCallOut')).toMatchSnapshot(); }); it('should render a link to filter by cluster uuid and index uuid', () => { const component = shallow( - <LogsContent sharePlugin={sharePlugin} logs={logs} clusterUuid="12345" indexUuid="6789" /> + <LogsContent + sharePlugin={sharePlugin} + logsIndices={'logs-*,*:logs-*'} + logs={logs} + clusterUuid="12345" + indexUuid="6789" + /> ); expect(component.find('EuiCallOut')).toMatchSnapshot(); }); it('should render a reason if the logs are disabled', () => { const component = shallow( - <LogsContent sharePlugin={sharePlugin} logs={{ enabled: false, limit: 15, reason: {} }} /> + <LogsContent + sharePlugin={sharePlugin} + logsIndices={'logs-*,*:logs-*'} + logs={{ enabled: false, limit: 15, reason: {} }} + /> ); expect(component).toMatchSnapshot(); }); diff --git a/x-pack/plugins/monitoring/public/plugin.ts b/x-pack/plugins/monitoring/public/plugin.ts index e29faa9ca5d8..02033d839e1a 100644 --- a/x-pack/plugins/monitoring/public/plugin.ts +++ b/x-pack/plugins/monitoring/public/plugin.ts @@ -19,6 +19,7 @@ import type { HomePublicPluginSetup } from '@kbn/home-plugin/public'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public'; import { + CCS_REMOTE_PATTERN, RULE_DETAILS, RULE_THREAD_POOL_SEARCH_REJECTIONS, RULE_THREAD_POOL_WRITE_REJECTIONS, @@ -38,6 +39,7 @@ import { MonitoringStartPluginDependencies, LegacyMonitoringStartPluginDependencies, } from './types'; +import { getIndexPatterns } from '../common/get_index_patterns'; interface MonitoringSetupPluginDependencies { home?: HomePublicPluginSetup; @@ -154,6 +156,7 @@ export class MonitoringPlugin monitoring.ui.kibana.reporting.stale_status_threshold_seconds, ], ['isCcsEnabled', monitoring.ui.ccs.enabled], + ['logsIndices', getLogsIndices(monitoring)], ]; } @@ -188,3 +191,11 @@ export class MonitoringPlugin } } } + +const getLogsIndices = (config: MonitoringConfig) => { + return getIndexPatterns({ + config, + type: 'logs', + ccs: CCS_REMOTE_PATTERN, + }); +}; diff --git a/x-pack/plugins/monitoring/server/index.ts b/x-pack/plugins/monitoring/server/index.ts index f39af9fffe7d..24062f0b947a 100644 --- a/x-pack/plugins/monitoring/server/index.ts +++ b/x-pack/plugins/monitoring/server/index.ts @@ -35,6 +35,7 @@ export const config: PluginConfigDescriptor<TypeOf<typeof configSchema>> = { stale_status_threshold_seconds: true, }, }, + logs: true, }, kibana: true, }, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts index f7535c26f2e4..50cc76225f41 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_ccr_read_exceptions.ts @@ -10,7 +10,7 @@ import { get } from 'lodash'; import { isCCSRemoteIndexName } from '@kbn/es-query'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; import { CCRReadExceptionsStats } from '../../../common/types/alerts'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts index a4ef0b1321fa..1d35440d65ae 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cluster_health.ts @@ -10,7 +10,7 @@ import { AlertCluster, AlertClusterHealth } from '../../../common/types/alerts'; import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; export async function fetchClusterHealth( diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts index 80b1128ddf16..870d1dde9e4c 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_clusters.ts @@ -8,7 +8,7 @@ import { ElasticsearchClient } from '@kbn/core/server'; import { get } from 'lodash'; import { AlertCluster } from '../../../common/types/alerts'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts index b74b1b78b495..761d3087d8c7 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_cpu_usage_node_stats.ts @@ -11,7 +11,7 @@ import moment from 'moment'; import { NORMALIZED_DERIVATIVE_UNIT } from '../../../common/constants'; import { AlertCluster, AlertCpuUsageNodeStats } from '../../../common/types/alerts'; import { createDatasetFilter } from './create_dataset_query_filter'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts index 7bf405985e57..1c8f9808a04a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_disk_usage_node_stats.ts @@ -11,7 +11,7 @@ import { AlertCluster, AlertDiskUsageNodeStats } from '../../../common/types/ale import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchDiskUsageNodeStats( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts index 4c5f6b06d39e..a82cb77c047a 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_elasticsearch_versions.ts @@ -10,7 +10,7 @@ import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchElasticsearchVersions( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts index 5c32794cbf21..7b5affc78702 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_index_shard_size.ts @@ -12,7 +12,7 @@ import { ESGlobPatterns, RegExPatterns } from '../../../common/es_glob_patterns' import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; type TopHitType = ElasticsearchResponseHit & { _source: { index_stats?: Partial<ElasticsearchIndexStats> }; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts index bd6f7d3255ab..3f6282c049aa 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_kibana_versions.ts @@ -10,7 +10,7 @@ import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; interface ESAggResponse { key: string; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts index 30c1317696d7..b7216b259302 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_licenses.ts @@ -10,7 +10,7 @@ import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchLicenses( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts index 2d4223091051..5bbaf3244269 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_logstash_versions.ts @@ -10,7 +10,7 @@ import { AlertCluster, AlertVersions } from '../../../common/types/alerts'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; interface ESAggResponse { key: string; diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts index 4d05843c6703..da943945aebc 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_memory_usage_node_stats.ts @@ -11,7 +11,7 @@ import { AlertCluster, AlertMemoryUsageNodeStats } from '../../../common/types/a import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; export async function fetchMemoryUsageNodeStats( esClient: ElasticsearchClient, diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts index 35f37c14b98a..534360401171 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_missing_monitoring_data.ts @@ -10,7 +10,7 @@ import { get } from 'lodash'; import { AlertCluster, AlertMissingData } from '../../../common/types/alerts'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { createDatasetFilter } from './create_dataset_query_filter'; interface ClusterBucketESResponse { diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts index cb8f0e4e14b8..f4cf1f5cb4f7 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_nodes_from_cluster_stats.ts @@ -10,7 +10,7 @@ import { ElasticsearchSource } from '../../../common/types/es'; import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; function formatNode( nodes: NonNullable<NonNullable<ElasticsearchSource['cluster_state']>['nodes']> | undefined diff --git a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts index 0cf69df44a18..3e26d9eb7702 100644 --- a/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/alerts/fetch_thread_pool_rejections_stats.ts @@ -11,7 +11,7 @@ import { AlertCluster, AlertThreadPoolRejectionsStats } from '../../../common/ty import { createDatasetFilter } from './create_dataset_query_filter'; import { Globals } from '../../static_globals'; import { CCS_REMOTE_PATTERN } from '../../../common/constants'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; const invalidNumberValue = (value: number) => { return isNaN(value) || value === undefined || value === null; diff --git a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts index 85958eccfe2d..1929f5c69531 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/create_apm_query.ts @@ -7,7 +7,7 @@ import { ApmMetric, ApmMetricFields } from '../metrics'; import { createQuery } from '../create_query'; -import { getBeatDataset } from '../cluster/get_index_patterns'; +import { getBeatDataset } from '../../../common/get_index_patterns'; /** * {@code createQuery} for all APM instances. diff --git a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts index 072f296fc52a..5764d787142c 100644 --- a/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/apm/get_apms_for_clusters.ts @@ -11,7 +11,7 @@ import { ApmMetric } from '../metrics'; import { apmAggResponseHandler, apmUuidsAgg, apmAggFilterPath } from './_apm_stats'; import { getTimeOfLastEvent } from './_get_time_of_last_event'; import { ElasticsearchResponse } from '../../../common/types/es'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts index 9a59620a154e..cdb41945bd05 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/create_beats_query.ts @@ -7,7 +7,7 @@ import { BeatsMetric, BeatsMetricFields } from '../metrics'; import { createQuery } from '../create_query'; -import { getBeatDataset } from '../cluster/get_index_patterns'; +import { getBeatDataset } from '../../../common/get_index_patterns'; /** * {@code createQuery} for all Beats instances. diff --git a/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts index f1914d0bc9f2..8e0a6236a2fd 100644 --- a/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/beats/get_beats_for_clusters.ts @@ -10,7 +10,7 @@ import { createBeatsQuery } from './create_beats_query'; import { beatsAggFilterPath, beatsUuidsAgg, beatsAggResponseHandler } from './_beats_stats'; import type { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest, Cluster } from '../../types'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export function handleResponse(clusterUuid: string, response: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts index d4ea1363054f..f5ea6aa19c0f 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/flag_supported_clusters.ts @@ -10,7 +10,7 @@ import { TimeRange } from '../../../common/http_api/shared'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { Cluster, LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from './get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; export interface FindSupportClusterRequestPayload { timeRange: TimeRange; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts index b0144c3a8439..bc25cf328018 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_cluster_license.ts @@ -9,7 +9,7 @@ import { createQuery } from '../create_query'; import { ElasticsearchMetric } from '../metrics'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from './get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; // is this being used anywhere? not called within the app diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts index 6f082dcdb97a..b753388af7d5 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_from_request.ts @@ -41,7 +41,7 @@ import { LegacyRequest, Cluster } from '../../types'; import { RulesByType } from '../../../common/types/alerts'; import { getClusterRuleDataForClusters, getInstanceRuleDataForClusters } from '../kibana/rules'; import { Globals } from '../../static_globals'; -import { getIndexPatterns } from './get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; /** * Get all clusters or the cluster associated with {@code clusterUuid} when it is defined. @@ -123,25 +123,19 @@ export async function getClustersFromRequest( // update clusters with license check results const getSupportedClusters = flagSupportedClusters(req, CCS_REMOTE_PATTERN); clusters = await getSupportedClusters(clusters); + clusters = initializeClusters(clusters); // add alerts data if (isInCodePath(codePaths, [CODE_PATH_ALERTS])) { - const rulesClient = req.getRulesClient(); - const alertStatus = await fetchStatus( - rulesClient, - undefined, - clusters.map((cluster) => get(cluster, 'elasticsearch.cluster.id', cluster.cluster_uuid)) + const rulesClient = await req.getRulesClient(); + const clustersIds = clusters.map((cluster) => + get(cluster, 'elasticsearch.cluster.id', cluster.cluster_uuid) ); - for (const cluster of clusters) { - if (!rulesClient) { - cluster.alerts = { - list: {}, - alertsMeta: { - enabled: false, - }, - }; - } else { + if (rulesClient) { + const alertStatus = await fetchStatus(rulesClient, undefined, clustersIds); + + for (const cluster of clusters) { try { cluster.alerts = { list: Object.keys(alertStatus).reduce<RulesByType>((acc, ruleTypeName) => { @@ -163,12 +157,6 @@ export async function getClustersFromRequest( req.logger.warn( `Unable to fetch alert status because '${err.message}'. Alerts may not properly show up in the UI.` ); - cluster.alerts = { - list: {}, - alertsMeta: { - enabled: true, - }, - }; } } } @@ -284,3 +272,13 @@ export async function getClustersFromRequest( return getClustersSummary(req.server, clusters as EnhancedClusters[], kibanaUuid, isCcrEnabled); } + +const initializeClusters = (clusters: Cluster[]): Cluster[] => { + return clusters.map((cluster) => ({ + ...cluster, + list: {}, + alertsMeta: { + enabled: false, + }, + })); +}; diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts index 3415ac09dad2..4d6ca01e3e6e 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_state.ts @@ -8,7 +8,7 @@ import { find } from 'lodash'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns } from './get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /** diff --git a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts index 240607eb8a08..59a66b8b9ea4 100644 --- a/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/cluster/get_clusters_stats.ts @@ -11,7 +11,7 @@ import { parseCrossClusterPrefix } from '../../../common/ccs_utils'; import { getClustersState } from './get_clusters_state'; import { ElasticsearchResponse, ElasticsearchModifiedSource } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from './get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /** diff --git a/x-pack/plugins/monitoring/server/lib/details/get_series.ts b/x-pack/plugins/monitoring/server/lib/details/get_series.ts index 3b325864d803..854c5a67db30 100644 --- a/x-pack/plugins/monitoring/server/lib/details/get_series.ts +++ b/x-pack/plugins/monitoring/server/lib/details/get_series.ts @@ -22,7 +22,7 @@ import { DS_INDEX_PATTERN_METRICS, } from '../../../common/constants'; import { formatUTCTimestampForTimezone } from '../format_timezone'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; import type { Metric } from '../metrics/metrics'; diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts index 4dd568bc2f87..f809e6e358e7 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/ccr.ts @@ -10,7 +10,7 @@ import { ElasticsearchMetric } from '../metrics'; import { createQuery } from '../create_query'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export async function checkCcrEnabled(req: LegacyRequest, ccs: string) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts index 81262ddb3e3f..baaa06c1421a 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_last_recovery.ts @@ -16,7 +16,7 @@ import { ElasticsearchResponseHit, } from '../../../common/types/es'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /** diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts index f26d9df66201..ab724a2c49cf 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/get_ml_jobs.ts @@ -11,7 +11,7 @@ import { ElasticsearchMetric } from '../metrics'; import { ML_SUPPORTED_LICENSES } from '../../../common/constants'; import { ElasticsearchResponse } from '../../../common/types/es'; import { LegacyRequest, Cluster } from '../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; /* diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts index b2cffbcf3667..4da1099fd583 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_index_summary.ts @@ -11,7 +11,7 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { ElasticsearchResponse } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse(shardStats: any, indexUuid: string) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts index e11971ac4f8d..6b40c8480603 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/indices/get_indices.ts @@ -13,7 +13,7 @@ import { calculateRate } from '../../calculate_rate'; import { getUnassignedShards } from '../shards'; import { ElasticsearchResponse } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse( diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts index e210187ab7f9..c050f5fac52b 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_node_summary.ts @@ -17,7 +17,7 @@ import { ElasticsearchLegacySource, } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse( diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts index 27c458a4fbd2..968e5200d704 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_node_ids.ts @@ -10,7 +10,10 @@ import { get } from 'lodash'; import { ElasticsearchMetric } from '../../../metrics'; import { createQuery } from '../../../create_query'; import { LegacyRequest, Bucket } from '../../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../../cluster/get_index_patterns'; +import { + getIndexPatterns, + getElasticsearchDataset, +} from '../../../../../common/get_index_patterns'; import { Globals } from '../../../../static_globals'; export async function getNodeIds( diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts index 4308e60ed64a..66004202df26 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/nodes/get_nodes/get_nodes.ts @@ -14,7 +14,10 @@ import { handleResponse } from './handle_response'; import { LISTING_METRICS_NAMES, LISTING_METRICS_PATHS } from './nodes_listing_metrics'; import { LegacyRequest } from '../../../../types'; import { ElasticsearchModifiedSource } from '../../../../../common/types/es'; -import { getIndexPatterns, getElasticsearchDataset } from '../../../cluster/get_index_patterns'; +import { + getIndexPatterns, + getElasticsearchDataset, +} from '../../../../../common/get_index_patterns'; import { Globals } from '../../../../static_globals'; /* Run an aggregation on node_stats to get stat data for the selected time diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts index 2d30159a4cab..dd346cc27959 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_indices_unassigned_shard_stats.ts @@ -11,7 +11,7 @@ import { ElasticsearchMetric } from '../../metrics'; import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; import { LegacyRequest } from '../../../types'; import { ElasticsearchModifiedSource } from '../../../../common/types/es'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; async function getUnassignedShardData(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts index c0dd5c29b4f2..c5be72640374 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_nodes_shard_count.ts @@ -10,7 +10,7 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { LegacyRequest } from '../../../types'; import { ElasticsearchModifiedSource } from '../../../../common/types/es'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; async function getShardCountPerNode(req: LegacyRequest, cluster: ElasticsearchModifiedSource) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts index b4cb77f2a6c1..0aac81e202f0 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_allocation.ts @@ -9,7 +9,7 @@ import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { ElasticsearchResponse, ElasticsearchLegacySource } from '../../../../common/types/es'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; export function handleResponse(response: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts index d5af43e21683..717dc38814ae 100644 --- a/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/elasticsearch/shards/get_shard_stats.ts @@ -9,7 +9,7 @@ import { get } from 'lodash'; import { ElasticsearchModifiedSource, ElasticsearchResponse } from '../../../../common/types/es'; import { Globals } from '../../../static_globals'; import { LegacyRequest } from '../../../types'; -import { getIndexPatterns, getElasticsearchDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getElasticsearchDataset } from '../../../../common/get_index_patterns'; import { createQuery } from '../../create_query'; import { ElasticsearchMetric } from '../../metrics'; import { calculateIndicesTotals } from './calculate_shard_stat_indices_totals'; diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts index 4204166b4a38..ddda97decbdd 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/create_enterprise_search_query.ts @@ -8,7 +8,7 @@ import { EnterpriseSearchMetric, EnterpriseSearchMetricFields } from '../metrics'; import { createQuery } from '../create_query'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; -import { getEntsearchDataset } from '../cluster/get_index_patterns'; +import { getEntsearchDataset } from '../../../common/get_index_patterns'; /** * {@code createQuery} for all Enterprise Search instances. diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts index 0011c965c865..89af39c7b04e 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_enterprise_search_for_clusters.ts @@ -9,7 +9,7 @@ import { TimeRange } from '../../../common/http_api/shared'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { Cluster, LegacyRequest } from '../../types'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { EnterpriseSearchMetric } from '../metrics'; import { createEnterpriseSearchQuery } from './create_enterprise_search_query'; import { diff --git a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts index 526e7ec91940..63c09d388b5d 100644 --- a/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts +++ b/x-pack/plugins/monitoring/server/lib/enterprise_search/get_stats.ts @@ -10,7 +10,7 @@ import { TimeRange } from '../../../common/http_api/shared'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { createEnterpriseSearchQuery } from './create_enterprise_search_query'; import { entSearchAggFilterPath, diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts index 610a83d81428..4ab11001c899 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibana_info.ts @@ -9,7 +9,7 @@ import { merge } from 'lodash'; import { ElasticsearchResponse } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; import { MissingRequiredError } from '../error_missing_required'; import { buildKibanaInfo } from './build_kibana_info'; import { isKibanaStatusStale } from './is_kibana_status_stale'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts index 9f45b0125b93..4796a340aaa4 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas.ts @@ -9,7 +9,7 @@ import moment from 'moment'; import { ElasticsearchResponse, ElasticsearchResponseHit } from '../../../common/types/es'; import { Globals } from '../../static_globals'; import { LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { KibanaMetric } from '../metrics'; import { buildKibanaInfo, KibanaInfo } from './build_kibana_info'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts index f576fc4913f8..82da6c42c8f4 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/get_kibanas_for_clusters.ts @@ -8,7 +8,7 @@ import { chain, find } from 'lodash'; import { Globals } from '../../static_globals'; import { Bucket, Cluster, LegacyRequest } from '../../types'; -import { getIndexPatterns, getKibanaDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { KibanaClusterMetric } from '../metrics'; import { isKibanaStatusStale } from './is_kibana_status_stale'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts index 5151a44ad546..7c4ee32cde9a 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_cluster_rule_data_for_clusters.ts @@ -5,7 +5,7 @@ * 2.0. */ import { Cluster, LegacyRequest } from '../../../types'; -import { getIndexPatterns, getKibanaDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; import { createQuery } from '../../create_query'; import { KibanaClusterRuleMetric } from '../../metrics'; diff --git a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts index 0e986f5f3d7f..0de56533bf78 100644 --- a/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/kibana/rules/get_instance_rule_data_for_clusters.ts @@ -5,7 +5,7 @@ * 2.0. */ import { Cluster, LegacyRequest } from '../../../types'; -import { getIndexPatterns, getKibanaDataset } from '../../cluster/get_index_patterns'; +import { getIndexPatterns, getKibanaDataset } from '../../../../common/get_index_patterns'; import { Globals } from '../../../static_globals'; import { createQuery } from '../../create_query'; import { KibanaClusterRuleMetric } from '../../metrics'; diff --git a/x-pack/plugins/monitoring/server/lib/logs/init_log_view.ts b/x-pack/plugins/monitoring/server/lib/logs/init_log_view.ts deleted file mode 100644 index 52b0f4364738..000000000000 --- a/x-pack/plugins/monitoring/server/lib/logs/init_log_view.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { LogsSharedPluginSetup } from '@kbn/logs-shared-plugin/server'; -import { CCS_REMOTE_PATTERN, INFRA_SOURCE_ID } from '../../../common/constants'; -import { MonitoringConfig } from '../../config'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; - -export const initLogView = (config: MonitoringConfig, logsShared: LogsSharedPluginSetup) => { - if (logsShared) { - const logsIndexPattern = getIndexPatterns({ - config, - type: 'logs', - ccs: CCS_REMOTE_PATTERN, - }); - - logsShared.logViews.defineInternalLogView(INFRA_SOURCE_ID, { - name: 'Elastic Stack Logs', - logIndices: { - type: 'index_name', - indexName: logsIndexPattern, - }, - }); - } -}; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts index 7babdff3854b..295f78803e67 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_logstash_for_clusters.ts @@ -10,7 +10,7 @@ import { LegacyRequest, Cluster, Bucket } from '../../types'; import { LOGSTASH } from '../../../common/constants'; import { createQuery } from '../create_query'; import { LogstashClusterMetric } from '../metrics'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; const { MEMORY, PERSISTED } = LOGSTASH.QUEUE_TYPES; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts index ca54da09dce2..347085f162e7 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_node_info.ts @@ -12,7 +12,7 @@ import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../common/constants'; import { standaloneClusterFilter } from '../standalone_clusters/standalone_cluster_query_filter'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export function handleResponse(resp: ElasticsearchResponse) { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts index 0d10d87d961d..a153b43fb26c 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_nodes.ts @@ -11,7 +11,7 @@ import { calculateAvailability } from '../calculate_availability'; import { LogstashMetric } from '../metrics'; import { LegacyRequest } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; interface Logstash { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts index 38f716cb3586..88950a207b9a 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_paginated_pipelines.ts @@ -11,7 +11,7 @@ import { getLogstashPipelineIds } from './get_pipeline_ids'; import { sortPipelines } from './sort_pipelines'; import { paginate } from '../pagination/paginate'; import { getMetrics } from '../details/get_metrics'; -import { getLogstashDataset } from '../cluster/get_index_patterns'; +import { getLogstashDataset } from '../../../common/get_index_patterns'; import { LegacyRequest, Pipeline, diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts index 59473977dc94..348b1c1bb61c 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_ids.ts @@ -10,7 +10,7 @@ import { get } from 'lodash'; import { LegacyRequest, Bucket, Pipeline } from '../../types'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; -import { getIndexPatterns } from '../cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; interface GetLogstashPipelineIdsParams { diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts index be1612cfb4af..01aa42e79873 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_state_document.ts @@ -9,7 +9,7 @@ import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { LegacyRequest, PipelineVersion } from '../../types'; import { ElasticsearchResponse } from '../../../common/types/es'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; export async function getPipelineStateDocument({ diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts index 56785a4eee21..a76eb3b87031 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_stats_aggregation.ts @@ -10,7 +10,7 @@ import { PostLogstashPipelineRequestPayload, } from '../../../common/http_api/logstash'; import { LegacyRequest, PipelineVersion } from '../../types'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { Globals } from '../../static_globals'; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts index 2f464c050694..ceddc6ec4695 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_versions.ts @@ -8,7 +8,7 @@ import { get, orderBy } from 'lodash'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { Globals } from '../../static_globals'; import { LegacyRequest, PipelineVersion } from '../../types'; import { mergePipelineVersions } from './merge_pipeline_versions'; diff --git a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts index 52c738806c1e..6b2758392ac6 100644 --- a/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts +++ b/x-pack/plugins/monitoring/server/lib/logstash/get_pipeline_vertex_stats_aggregation.ts @@ -10,7 +10,7 @@ import { PostLogstashPipelineRequestPayload, } from '../../../common/http_api/logstash'; import { LegacyRequest, PipelineVersion } from '../../types'; -import { getIndexPatterns, getLogstashDataset } from '../cluster/get_index_patterns'; +import { getIndexPatterns, getLogstashDataset } from '../../../common/get_index_patterns'; import { createQuery } from '../create_query'; import { LogstashMetric } from '../metrics'; import { Globals } from '../../static_globals'; diff --git a/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap b/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap index 24d9d52224fa..242bfaeaffb6 100644 --- a/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap +++ b/x-pack/plugins/monitoring/server/lib/metrics/__snapshots__/metrics.test.js.snap @@ -5981,7 +5981,7 @@ Object { "isNotSupportedInInternalCollection": undefined, "label": "Pipeline Node Count", "legendFormat": undefined, - "mbField": undefined, + "mbField": "logstash.node.stats.logstash.uuid", "metricAgg": undefined, "periodsField": undefined, "quotaField": undefined, @@ -6437,7 +6437,7 @@ Object { "isNotSupportedInInternalCollection": undefined, "label": "Pipeline Node Count", "legendFormat": undefined, - "mbField": undefined, + "mbField": "logstash.node.stats.logstash.uuid", "metricAgg": undefined, "periodsField": undefined, "quotaField": undefined, diff --git a/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts b/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts index fd150864c6b2..b1240a2ca979 100644 --- a/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts +++ b/x-pack/plugins/monitoring/server/lib/metrics/logstash/classes.ts @@ -7,11 +7,11 @@ /* eslint-disable max-classes-per-file */ -import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { ClusterMetric, Metric, MetricOptions } from '../classes'; -import { LARGE_FLOAT } from '../../../../common/formatting'; +import _ from 'lodash'; import { NORMALIZED_DERIVATIVE_UNIT } from '../../../../common/constants'; +import { LARGE_FLOAT } from '../../../../common/formatting'; +import { ClusterMetric, Metric, MetricOptions } from '../classes'; const msTimeUnitLabel = i18n.translate('xpack.monitoring.metrics.logstash.msTimeUnitLabel', { defaultMessage: 'ms', @@ -411,7 +411,7 @@ export class LogstashPipelineThroughputMetric extends LogstashMetric { type LogstashPipelineNodeCountMetricOptions = Pick< MetricOptions, - 'field' | 'label' | 'description' | 'format' | 'units' + 'field' | 'label' | 'mbField' | 'description' | 'format' | 'units' > & Partial<Pick<MetricOptions, 'uuidField'>>; @@ -427,15 +427,10 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { }: { pageOfPipelines: Array<{ id: string }>; }) => { - const termAggExtras: { - include: string[]; - } = { - include: [], - }; + const include: string[] | undefined = pageOfPipelines?.length + ? pageOfPipelines.map((pipeline) => pipeline.id) + : undefined; - if (pageOfPipelines) { - termAggExtras.include = pageOfPipelines.map((pipeline) => pipeline.id); - } return { pipelines_nested: { nested: { @@ -446,7 +441,7 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { terms: { field: 'logstash_stats.pipelines.id', size: 1000, - ...termAggExtras, + include, }, aggs: { to_root: { @@ -472,7 +467,7 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { terms: { field: 'logstash.node.stats.pipelines.id', size: 1000, - ...termAggExtras, + include, }, aggs: { to_root: { @@ -480,7 +475,7 @@ export class LogstashPipelineNodeCountMetric extends LogstashMetric { aggs: { node_count: { cardinality: { - field: this.field, + field: this.mbField, }, }, }, diff --git a/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts b/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts index 97119289d213..73aa91ef6f5f 100644 --- a/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts +++ b/x-pack/plugins/monitoring/server/lib/metrics/logstash/metrics.ts @@ -6,23 +6,23 @@ */ import { i18n } from '@kbn/i18n'; +import { + LARGE_ABBREVIATED, + LARGE_BYTES, + LARGE_FLOAT, + SMALL_BYTES, +} from '../../../../common/formatting'; import { QuotaMetric } from '../classes'; import { - LogstashEventsRateClusterMetric, LogstashEventsLatencyClusterMetric, - LogstashEventsRateMetric, LogstashEventsLatencyMetric, + LogstashEventsRateClusterMetric, + LogstashEventsRateMetric, LogstashMetric, + LogstashPipelineNodeCountMetric, LogstashPipelineQueueSizeMetric, LogstashPipelineThroughputMetric, - LogstashPipelineNodeCountMetric, } from './classes'; -import { - LARGE_FLOAT, - LARGE_BYTES, - SMALL_BYTES, - LARGE_ABBREVIATED, -} from '../../../../common/formatting'; const instanceSystemLoadTitle = i18n.translate( 'xpack.monitoring.metrics.logstash.systemLoadTitle', @@ -451,6 +451,7 @@ export const metrics = { logstash_cluster_pipeline_nodes_count: new LogstashPipelineNodeCountMetric({ field: 'logstash_stats.logstash.uuid', label: pipelineNodeCountLabel, + mbField: 'logstash.node.stats.logstash.uuid', description: pipelineNodeCountDescription, format: LARGE_FLOAT, units: '', @@ -459,6 +460,7 @@ export const metrics = { uuidField: 'logstash_stats.logstash.uuid', // TODO: add comment explaining why field: 'logstash_stats.logstash.uuid', label: pipelineNodeCountLabel, + mbField: 'logstash.node.stats.logstash.uuid', description: pipelineNodeCountDescription, format: LARGE_FLOAT, units: '', diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts index e7ffe701fbd1..ce03cc5aecf3 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.test.ts @@ -7,7 +7,6 @@ import { featuresPluginMock } from '@kbn/features-plugin/server/mocks'; import { infraPluginMock } from '@kbn/infra-plugin/server/mocks'; -import { logsSharedPluginMock } from '@kbn/logs-shared-plugin/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; import { usageCollectionPluginMock } from '@kbn/usage-collection-plugin/server/mocks'; import { configSchema, createConfig } from '../../../config'; @@ -39,7 +38,6 @@ const mockReq = ( usageCollection: usageCollectionSetup, features: featuresPluginMock.createSetup(), infra: infraPluginMock.createSetupContract(), - logsShared: logsSharedPluginMock.createSetupContract(), }, }, }, @@ -96,7 +94,7 @@ const mockReq = ( headers: {}, getKibanaStatsCollector: () => null, getUiSettingsService: () => null, - getActionTypeRegistry: () => null, + getActionTypeRegistry: () => [], getRulesClient: () => null, getActionsClient: () => null, }; diff --git a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts index 6d800e83c2d7..41313bfb347a 100644 --- a/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts +++ b/x-pack/plugins/monitoring/server/lib/setup/collection/get_collection_status.ts @@ -14,7 +14,7 @@ import { } from '../../../../common/constants'; import { TimeRange } from '../../../../common/http_api/shared'; import { LegacyRequest } from '../../../types'; -import { getLegacyIndexPattern } from '../../cluster/get_index_patterns'; +import { getLegacyIndexPattern } from '../../../../common/get_index_patterns'; import { getLivesNodes } from '../../elasticsearch/nodes/get_nodes/get_live_nodes'; interface Bucket { diff --git a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts index 042340eb0669..d9ec794dd760 100644 --- a/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts +++ b/x-pack/plugins/monitoring/server/lib/standalone_clusters/has_standalone_clusters.ts @@ -14,7 +14,7 @@ import { getIndexPatterns, getLogstashDataset, getBeatDataset, -} from '../cluster/get_index_patterns'; +} from '../../../common/get_index_patterns'; export async function hasStandaloneClusters(req: LegacyRequest, ccs: string) { const lsIndexPatterns = getIndexPatterns({ diff --git a/x-pack/plugins/monitoring/server/plugin.ts b/x-pack/plugins/monitoring/server/plugin.ts index 72063805b338..dbf375aa2e05 100644 --- a/x-pack/plugins/monitoring/server/plugin.ts +++ b/x-pack/plugins/monitoring/server/plugin.ts @@ -23,7 +23,9 @@ import { import { get } from 'lodash'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { RouteMethod } from '@kbn/core/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; +import { AlertConsumers } from '@kbn/rule-data-utils'; import { KIBANA_MONITORING_LOGGING_TAG, KIBANA_STATS_TYPE_MONITORING, @@ -36,7 +38,6 @@ import { configSchema, createConfig, MonitoringConfig } from './config'; import { instantiateClient } from './es_client/instantiate_client'; import { initBulkUploader } from './kibana_monitoring'; import { registerCollectors } from './kibana_monitoring/collectors'; -import { initLogView } from './lib/logs/init_log_view'; import { LicenseService } from './license_service'; import { requireUIRoutes } from './routes'; import { EndpointTypes, Globals } from './static_globals'; @@ -203,7 +204,6 @@ export class MonitoringPlugin alerting: plugins.alerting, logger: this.log, }); - initLogView(config, plugins.logsShared); } } @@ -267,6 +267,11 @@ export class MonitoringPlugin } registerPluginInUI(plugins: PluginsSetup) { + const alertingFeatures = RULES.map((ruleTypeId) => ({ + ruleTypeId, + consumers: ['monitoring', ALERTING_FEATURE_ID, AlertConsumers.OBSERVABILITY], + })); + plugins.features.registerKibanaFeature({ id: 'monitoring', name: i18n.translate('xpack.monitoring.featureRegistry.monitoringFeatureName', { @@ -277,7 +282,7 @@ export class MonitoringPlugin app: ['monitoring', 'kibana'], catalogue: ['monitoring'], privileges: null, - alerting: RULES, + alerting: alertingFeatures, reserved: { description: i18n.translate('xpack.monitoring.feature.reserved.description', { defaultMessage: 'To grant users access, you should also assign the monitoring_user role.', @@ -294,10 +299,10 @@ export class MonitoringPlugin }, alerting: { rule: { - all: RULES, + all: alertingFeatures, }, alert: { - all: RULES, + all: alertingFeatures, }, }, ui: [], @@ -337,7 +342,7 @@ export class MonitoringPlugin payload: req.body, getKibanaStatsCollector: () => this.legacyShimDependencies.kibanaStatsCollector, getUiSettingsService: () => coreContext.uiSettings.client, - getActionTypeRegistry: () => actionContext?.listTypes(), + getActionTypeRegistry: () => actionContext?.listTypes() ?? [], getRulesClient: () => { try { return plugins.alerting.getRulesClientWithRequest(req); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts b/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts index 5ed5b85168ee..7b0c07fef8df 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/_health/index.ts @@ -8,7 +8,7 @@ import type { LegacyRequest, MonitoringCore } from '../../../../types'; import type { MonitoringConfig } from '../../../../config'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; -import { getIndexPatterns, getDsIndexPattern } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns, getDsIndexPattern } from '../../../../../common/get_index_patterns'; import { getHealthRequestQueryRT } from '../../../../../common/http_api/_health'; import type { TimeRange } from '../../../../../common/http_api/shared'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts b/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts index dac9d6b59ca1..0935b76e7fba 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/_health/monitored_clusters/monitored_clusters_query.ts @@ -12,7 +12,7 @@ import { getKibanaDataset, getLogstashDataset, getEntsearchDataset, -} from '../../../../../lib/cluster/get_index_patterns'; +} from '../../../../../../common/get_index_patterns'; const MAX_BUCKET_SIZE = 100; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts index 8b919fd1f86e..593f3c9b2b4a 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/enable.ts @@ -30,6 +30,7 @@ export function enableAlertsRoute(server: MonitoringCore, npRoute: RouteDependen const actionContext = await context.actions; const alerts = RulesFactory.getAll(); + if (alerts.length) { const { isSufficientlySecure, hasPermanentEncryptionKey } = npRoute.alerting ?.getSecurityHealth @@ -49,9 +50,10 @@ export function enableAlertsRoute(server: MonitoringCore, npRoute: RouteDependen } } - const rulesClient = alertingContext?.getRulesClient(); + const rulesClient = await alertingContext?.getRulesClient(); const actionsClient = actionContext?.getActionsClient(); const types = actionContext?.listTypes(); + if (!rulesClient || !actionsClient || !types) { return response.ok({ body: undefined }); } diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts index 64a0b7b92d85..a6c7d9b833ee 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/alerts/status.ts @@ -36,7 +36,7 @@ export function alertStatusRoute(npRoute: RouteDependencies) { try { const { clusterUuid } = request.params; const { alertTypeIds, filters } = request.body; - const rulesClient = (await context.alerting)?.getRulesClient(); + const rulesClient = await (await context.alerting)?.getRulesClient(); if (!rulesClient) { return response.ok({ body: undefined }); } diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts index 8c8d7e0ad2c6..3e4d903ec8af 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instance.ts @@ -14,7 +14,7 @@ import { getApmInfo } from '../../../../lib/apm'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; import { metricSet } from './metric_set_instance'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts index bb8086867ed0..1b19d4900779 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/apm/instances.ts @@ -13,7 +13,7 @@ import { import { getApms, getStats } from '../../../../lib/apm'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; export function apmInstancesRoute(server: MonitoringCore) { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts index 30ef661feb0f..a248df56f9e2 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beat_detail.ts @@ -14,7 +14,7 @@ import { getBeatSummary } from '../../../../lib/beats'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; import { metricSet } from './metric_set_detail'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts index b59cec289861..96433d756e8a 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/beats.ts @@ -13,7 +13,7 @@ import { import { getBeats, getStats } from '../../../../lib/beats'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; export function beatsListingRoute(server: MonitoringCore) { diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts index cbdc28ebf4f9..6c79a56a5741 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/beats/overview.ts @@ -14,7 +14,7 @@ import { getLatestStats, getStats } from '../../../../lib/beats'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { MonitoringCore } from '../../../../types'; import { metricSet } from './metric_set_overview'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts index 7c939407ef15..03f9fff6bc94 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr.ts @@ -9,7 +9,7 @@ import { get, groupBy } from 'lodash'; import { getIndexPatterns, getElasticsearchDataset, -} from '../../../../lib/cluster/get_index_patterns'; +} from '../../../../../common/get_index_patterns'; import { postElasticsearchCcrRequestParamsRT, postElasticsearchCcrRequestPayloadRT, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts index 3e215aaf67e3..b02ba1e455bc 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/ccr_shard.ts @@ -15,7 +15,7 @@ import { ElasticsearchResponse } from '../../../../../common/types/es'; import { getIndexPatterns, getElasticsearchDataset, -} from '../../../../lib/cluster/get_index_patterns'; +} from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { handleError } from '../../../../lib/errors/handle_error'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts index 9aed104920e8..e96fb9dbad62 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/index_detail.ts @@ -13,7 +13,7 @@ import { postElasticsearchIndexDetailResponsePayloadRT, } from '../../../../../common/http_api/elasticsearch'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getIndexSummary } from '../../../../lib/elasticsearch/indices'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts index 763f8005abc9..05406a2d001e 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/node_detail.ts @@ -14,7 +14,7 @@ import { postElasticsearchNodeDetailResponsePayloadRT, } from '../../../../../common/http_api/elasticsearch'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics, diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts index 0b97f9ea6336..269a924648a6 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/elasticsearch/overview.ts @@ -13,7 +13,7 @@ import { } from '../../../../../common/http_api/elasticsearch'; import { getClusterStats } from '../../../../lib/cluster/get_cluster_stats'; import { getClusterStatus } from '../../../../lib/cluster/get_cluster_status'; -import { getIndexPatterns } from '../../../../lib/cluster/get_index_patterns'; +import { getIndexPatterns } from '../../../../../common/get_index_patterns'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { getMetrics } from '../../../../lib/details/get_metrics'; import { getLastRecovery } from '../../../../lib/elasticsearch/get_last_recovery'; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts index f398a1bda59d..135fa58e3d28 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/kibana/overview.ts @@ -16,7 +16,7 @@ import { } from '../../../../../common/http_api/kibana'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; import { MonitoringCore } from '../../../../types'; -import { getKibanaDataset } from '../../../../lib/cluster/get_index_patterns'; +import { getKibanaDataset } from '../../../../../common/get_index_patterns'; export function kibanaOverviewRoute(server: MonitoringCore) { const validateParams = createValidationFunction(postKibanaOverviewRequestParamsRT); diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts index 5c7bbc36b168..e6b2034ca22c 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/node.ts @@ -19,7 +19,7 @@ import { import { metricSets } from './metric_set_node'; import { MonitoringCore } from '../../../../types'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; -import { getLogstashDataset } from '../../../../lib/cluster/get_index_patterns'; +import { getLogstashDataset } from '../../../../../common/get_index_patterns'; const { advanced: metricSetAdvanced, overview: metricSetOverview } = metricSets; diff --git a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts index 26d63693fd6d..15661a130055 100644 --- a/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts +++ b/x-pack/plugins/monitoring/server/routes/api/v1/logstash/overview.ts @@ -15,7 +15,7 @@ import { handleError } from '../../../../lib/errors'; import { metricSet } from './metric_set_overview'; import { MonitoringCore } from '../../../../types'; import { createValidationFunction } from '../../../../lib/create_route_validation_function'; -import { getLogstashDataset } from '../../../../lib/cluster/get_index_patterns'; +import { getLogstashDataset } from '../../../../../common/get_index_patterns'; export function logstashOverviewRoute(server: MonitoringCore) { const validateParams = createValidationFunction(postLogstashOverviewRequestParamsRT); diff --git a/x-pack/plugins/monitoring/server/types.ts b/x-pack/plugins/monitoring/server/types.ts index 06c796764b5f..14ef949b9394 100644 --- a/x-pack/plugins/monitoring/server/types.ts +++ b/x-pack/plugins/monitoring/server/types.ts @@ -24,18 +24,14 @@ import type { } from '@kbn/actions-plugin/server'; import type { AlertingApiRequestHandlerContext } from '@kbn/alerting-plugin/server'; import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server'; -import { - PluginStartContract as AlertingPluginStartContract, - PluginSetupContract as AlertingPluginSetupContract, -} from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { InfraPluginSetup, InfraRequestHandlerContext } from '@kbn/infra-plugin/server'; -import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; import { LicensingPluginStart } from '@kbn/licensing-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { RouteConfig, RouteMethod, Headers } from '@kbn/core/server'; -import { LogsSharedPluginSetup } from '@kbn/logs-shared-plugin/server'; +import { ActionTypeRegistry } from '@kbn/actions-plugin/server/action_type_registry'; import { ElasticsearchModifiedSource } from '../common/types/es'; import { RulesByType } from '../common/types/alerts'; import { configSchema, MonitoringConfig } from './config'; @@ -54,10 +50,9 @@ export interface PluginsSetup { encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; usageCollection?: UsageCollectionSetup; features: FeaturesPluginSetup; - alerting?: AlertingPluginSetupContract; + alerting?: AlertingServerSetup; infra: InfraPluginSetup; cloud?: CloudSetup; - logsShared: LogsSharedPluginSetup; } export type RequestHandlerContextMonitoringPlugin = CustomRequestHandlerContext<{ @@ -68,7 +63,7 @@ export type RequestHandlerContextMonitoringPlugin = CustomRequestHandlerContext< }>; export interface PluginsStart { - alerting: AlertingPluginStartContract; + alerting: AlertingServerStart; actions: ActionsPluginsStartContact; licensing: LicensingPluginStart; } @@ -78,7 +73,7 @@ export interface RouteDependencies { router: IRouter<RequestHandlerContextMonitoringPlugin>; licenseService: MonitoringLicenseService; encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; - alerting?: AlertingPluginSetup; + alerting?: AlertingServerSetup; logger: Logger; } @@ -129,9 +124,11 @@ export interface LegacyRequest<Params = any, Query = any, Body = any> { headers: Headers; getKibanaStatsCollector: () => any; getUiSettingsService: () => any; - getActionTypeRegistry: () => any; - getRulesClient: () => any; - getActionsClient: () => any; + getActionTypeRegistry: () => ReturnType<ActionTypeRegistry['list']>; + getRulesClient: () => ReturnType<AlertingServerStart['getRulesClientWithRequest']> | null; + getActionsClient: () => ReturnType< + ActionsPluginsStartContact['getActionsClientWithRequest'] + > | null; server: LegacyServer; } diff --git a/x-pack/plugins/monitoring/tsconfig.json b/x-pack/plugins/monitoring/tsconfig.json index 48b538a00c1e..6be14087cc11 100644 --- a/x-pack/plugins/monitoring/tsconfig.json +++ b/x-pack/plugins/monitoring/tsconfig.json @@ -40,7 +40,6 @@ "@kbn/shared-ux-router", "@kbn/observability-shared-plugin", "@kbn/shared-ux-link-redirect-app", - "@kbn/logs-shared-plugin", "@kbn/alerts-as-data-utils", "@kbn/rule-data-utils", "@kbn/react-kibana-mount", diff --git a/x-pack/plugins/observability_solution/apm/common/alerting/config/apm_alerting_feature_ids.ts b/x-pack/plugins/observability_solution/apm/common/alerting/config/apm_alerting_feature_ids.ts new file mode 100644 index 000000000000..784ab0b53425 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/common/alerting/config/apm_alerting_feature_ids.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + AlertConsumers, + OBSERVABILITY_RULE_TYPE_IDS, + type ValidFeatureId, +} from '@kbn/rule-data-utils'; + +export const apmAlertingConsumers: ValidFeatureId[] = [ + AlertConsumers.LOGS, + AlertConsumers.APM, + AlertConsumers.SLO, + AlertConsumers.OBSERVABILITY, + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.ALERTS, +]; + +export const apmAlertingRuleTypeIds: string[] = [...OBSERVABILITY_RULE_TYPE_IDS]; diff --git a/x-pack/plugins/observability_solution/apm/dev_docs/testing.md b/x-pack/plugins/observability_solution/apm/dev_docs/testing.md index 02ff43d37bf7..aeb9435a2e11 100644 --- a/x-pack/plugins/observability_solution/apm/dev_docs/testing.md +++ b/x-pack/plugins/observability_solution/apm/dev_docs/testing.md @@ -3,7 +3,9 @@ We've got three ways of testing our code: - Unit testing with Jest -- API testing +- Integration Tests + - Deployment specific (stateful or serverless) API testing + - Deployment-agnostic (both stateful and serverless) testing - End-to-end testing (with Cypress) API tests are usually preferred. They're stable and reasonably quick, and give a good approximation of real-world usage. @@ -73,7 +75,59 @@ node x-pack/plugins/observability_solution/apm/scripts/test/api --runner --basic #### API Test tips -- For data generation in API tests have a look at the [kbn-apm-synthtrace](../../../../packages/kbn-apm-synthtrace/README.md) package +- For data generation in API tests have a look at the [kbn-apm-synthtrace](../../../../../packages/kbn-apm-synthtrace/README.md) package +- For debugging access Elasticsearch on http://localhost:9220 and Kibana on http://localhost:5620 (`elastic` / `changeme`) + +--- + +## Deployment-agnostic Tests (dat) + +| Option | Description | +| ------------ | ----------------------------------------------- | +| --serverless | Loads serverless configuration | +| --stateful | Loads stateful configuration | +| --server | Only start ES and Kibana | +| --runner | Only run tests | +| --grep | Specify the specs to run | +| --grep-files | Specify the files to run | +| --inspect | Add --inspect-brk flag to the ftr for debugging | +| --times | Repeat the test n number of times | + +Deployment-agnostic tests are located in [`x-pack/test/deployment_agnostic/apis/observability/apm/index.ts`](../../../../test/api_integration/deployment_agnostic/apis/observability/apm/index.ts). + +#### Start server and run test (single process) + +``` +node x-pack/plugins/observability_solution/apm/scripts/test/dat [--serverless/--stateful] [--help] +``` + +The above command will start an ES instance on http://localhost:9220, a Kibana instance on http://localhost:5620 and run the api tests. +Once the tests finish, the instances will be terminated. + +#### Start server and run test (separate processes) + +```sh + +# start server +node x-pack/plugins/observability_solution/apm/scripts/test/dat --server --stateful + +# run tests +node x-pack/plugins/observability_solution/apm/scripts/test/dat --runner --stateful --grep-files=error_group_list +``` + +### Update snapshots (from Kibana root) + +To update snapshots append `--updateSnapshots` to the `--runner` command: + +``` +node x-pack/plugins/observability_solution/apm/scripts/test/dat --runner --stateful --updateSnapshots +``` + +(The test server needs to be running) + +#### API Test tips + +- For data generation in Deployment-agnostic tests have a look at the [kbn-apm-synthtrace](../../../../../packages/kbn-apm-synthtrace/README.md) package - For debugging access Elasticsearch on http://localhost:9220 and Kibana on http://localhost:5620 (`elastic` / `changeme`) --- diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress.config.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress.config.ts index feb0a630043d..8dad8724264e 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress.config.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress.config.ts @@ -31,5 +31,6 @@ export default defineCypressConfig({ baseUrl: 'http://localhost:5601', supportFile: './cypress/support/e2e.ts', specPattern: './cypress/e2e/**/*.cy.{js,jsx,ts,tsx}', + experimentalMemoryManagement: true, }, }); diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts index 32ff06d1b3c6..b220bd049300 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts @@ -5,70 +5,88 @@ * 2.0. */ -describe('APM deep links', () => { +describe('Applications deep links', () => { beforeEach(() => { cy.loginAsViewerUser(); }); - it('navigates to apm links on search elastic', () => { + + it('navigates to Application links on "application" search', () => { cy.visitKibana('/'); + navigatesToApmLinks('applications'); + }); + + it('navigates to Application links on "apm" search', () => { + cy.visitKibana('/'); + navigatesToApmLinks('apm'); + }); + + function navigatesToApmLinks(keyword: string) { + // Wait until the page content is fully loaded + // otherwise, the search results may disappear before all checks are completed, making this test flaky + cy.waitUntilPageContentIsLoaded(); cy.getByTestSubj('nav-search-input') .should('be.visible') - .type('APM', { force: true, delay: 100 }) + .type(keyword, { force: true }) .focus(); - cy.contains('APM'); - cy.contains('APM / Service Inventory'); - cy.contains('APM / Service groups'); - cy.contains('APM / Traces'); - cy.contains('APM / Service Map'); - cy.contains('APM / Dependencies'); - cy.contains('APM / Settings'); + cy.contains('Applications'); + cy.contains('Applications / Service Inventory'); + cy.contains('Applications / Service groups'); + cy.contains('Applications / Traces'); + cy.contains('Applications / Service Map'); + // scroll to the bottom because results are not rendering otherwise + scrollToBottomResults(); + cy.contains('Applications / Dependencies'); + cy.contains('Applications / Settings'); // navigates to home page // Force click because welcome screen changes // https://github.com/elastic/kibana/pull/108193 - cy.contains('APM').click({ force: true }); + cy.contains('Applications').click({ force: true }); cy.url().should('include', '/apm/services'); - cy.getByTestSubj('nav-search-input') - .should('be.visible') - .type('APM', { force: true, delay: 100 }); + cy.waitUntilPageContentIsLoaded(); + cy.getByTestSubj('nav-search-input').should('be.visible').type(keyword, { force: true }); // navigates to services page - cy.contains('APM / Service Inventory').click({ force: true }); + cy.contains('Applications / Service Inventory').click({ force: true }); cy.url().should('include', '/apm/services'); - cy.getByTestSubj('nav-search-input') - .should('be.visible') - .type('APM', { force: true, delay: 100 }); + cy.waitUntilPageContentIsLoaded(); + cy.getByTestSubj('nav-search-input').should('be.visible').type(keyword, { force: true }); // navigates to service groups page - cy.contains('APM / Service groups').click({ force: true }); + cy.contains('Applications / Service groups').click({ force: true }); cy.url().should('include', '/apm/service-groups'); - cy.getByTestSubj('nav-search-input') - .should('be.visible') - .type('APM', { force: true, delay: 100 }); + cy.waitUntilPageContentIsLoaded(); + cy.getByTestSubj('nav-search-input').should('be.visible').type(keyword, { force: true }); // navigates to traces page - cy.contains('APM / Traces').click({ force: true }); + cy.contains('Applications / Traces').click({ force: true }); cy.url().should('include', '/apm/traces'); - cy.getByTestSubj('nav-search-input') - .should('be.visible') - .type('APM', { force: true, delay: 100 }); + cy.waitUntilPageContentIsLoaded(); + cy.getByTestSubj('nav-search-input').should('be.visible').type(keyword, { force: true }); + scrollToBottomResults(); // navigates to service maps - cy.contains('APM / Service Map').click({ force: true }); + cy.contains('Applications / Service Map').click({ force: true }); cy.url().should('include', '/apm/service-map'); - cy.getByTestSubj('nav-search-input') - .should('be.visible') - .type('APM', { force: true, delay: 100 }); + cy.waitUntilPageContentIsLoaded(); + cy.getByTestSubj('nav-search-input').should('be.visible').type(keyword, { force: true }); + // scroll to the bottom because results are not rendering otherwise + scrollToBottomResults(); // navigates to dependencies page - cy.contains('APM / Dependencies').click({ force: true }); + cy.contains('Applications / Dependencies').click({ force: true }); cy.url().should('include', '/apm/dependencies/inventory'); - cy.getByTestSubj('nav-search-input') - .should('be.visible') - .type('APM', { force: true, delay: 100 }); + cy.waitUntilPageContentIsLoaded(); + cy.getByTestSubj('nav-search-input').should('be.visible').type(keyword, { force: true }); + // scroll to the bottom because results are not rendering otherwise + scrollToBottomResults(); // navigates to settings page - cy.contains('APM / Settings').click({ force: true }); + cy.contains('Applications / Settings').click({ force: true }); cy.url().should('include', '/apm/settings/general-settings'); - }); + } }); + +function scrollToBottomResults() { + cy.getByTestSubj('euiSelectableList').find('div > div').scrollTo('bottom'); +} diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts index 6198ba8c5d05..f550da1b997f 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_inventory/service_inventory.cy.ts @@ -23,10 +23,12 @@ const serviceInventoryHref = url.format({ const mainApiRequestsToIntercept = [ { + method: 'GET', endpoint: '/internal/apm/services?*', aliasName: 'servicesRequest', }, { + method: 'POST', endpoint: '/internal/apm/services/detailed_statistics?*', aliasName: 'detailedStatisticsRequest', }, @@ -50,8 +52,13 @@ describe('Service inventory', () => { describe('When navigating to the service inventory', () => { beforeEach(() => { + mainApiRequestsToIntercept.forEach(({ aliasName, endpoint, method }) => + cy.intercept(method, endpoint).as(aliasName) + ); cy.loginAsViewerUser(); - cy.visitKibana(serviceInventoryHref); + cy.visitKibana(serviceInventoryHref, { + localStorageOptions: [['apm.dismissedEntitiesInventoryCallout', 'false']], + }); }); it('has no detectable a11y violations on load', () => { @@ -79,9 +86,8 @@ describe('Service inventory', () => { describe('Calls APIs', () => { beforeEach(() => { - cy.intercept('GET', '/internal/apm/services?*').as('servicesRequest'); - cy.intercept('POST', '/internal/apm/services/detailed_statistics?*').as( - 'detailedStatisticsRequest' + mainApiRequestsToIntercept.forEach(({ aliasName, endpoint, method }) => + cy.intercept(method, endpoint).as(aliasName) ); cy.loginAsViewerUser(); @@ -91,9 +97,11 @@ describe('Service inventory', () => { it('with the correct environment when changing the environment', () => { cy.wait(mainAliasNames); - cy.getByTestSubj('environmentFilter').type('{selectall}production'); - - cy.contains('button', 'production').click(); + cy.getByTestSubj('environmentFilter').find('input').click(); + cy.getByTestSubj('comboBoxOptionsList environmentFilter-optionsList').should('be.visible'); + cy.getByTestSubj('comboBoxOptionsList environmentFilter-optionsList') + .contains('button', 'production') + .click(); cy.expectAPIsToHaveBeenCalledWith({ apisIntercepted: mainAliasNames, diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts index 4840037cafb8..509f857b612b 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/service_overview/service_overview.cy.ts @@ -191,19 +191,10 @@ describe('Service Overview', () => { it('with the correct environment when changing the environment', () => { cy.wait(aliasNames); - cy.intercept('GET', 'internal/apm/suggestions?*').as('suggestionsRequest'); - - cy.getByTestSubj('environmentFilter') - .find('input') - .type('{selectall}production', { force: true }); - - cy.expectAPIsToHaveBeenCalledWith({ - apisIntercepted: ['@suggestionsRequest'], - value: 'fieldValue=production', - }); - + cy.getByTestSubj('environmentFilter').find('input').click(); cy.getByTestSubj('comboBoxOptionsList environmentFilter-optionsList') - .contains('production') + .should('be.visible') + .contains('button', 'production') .click({ force: true }); cy.expectAPIsToHaveBeenCalledWith({ diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts index d5bb161512a9..f72d331dab20 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/settings/agent_configurations.cy.ts @@ -127,16 +127,18 @@ describe('Agent configuration', () => { 'serviceEnvironmentApi' ); cy.contains('Create configuration').click(); - cy.getByTestSubj('serviceNameComboBox').click().type('opbeans-node').type('{enter}'); - - cy.contains('opbeans-node').realClick(); + cy.getByTestSubj('serviceNameComboBox').find('input').click(); + cy.getByTestSubj('serviceNameComboBox').type('opbeans-node{enter}'); cy.wait('@serviceEnvironmentApi'); - cy.getByTestSubj('serviceEnviromentComboBox') - .click({ force: true }) - .type('prod') - .type('{enter}'); - cy.contains('production').realClick(); + cy.getByTestSubj('serviceEnviromentComboBox').find('input').click(); + cy.getByTestSubj('comboBoxOptionsList serviceEnviromentComboBox-optionsList').should( + 'be.visible' + ); + cy.getByTestSubj('comboBoxOptionsList serviceEnviromentComboBox-optionsList') + .contains('button', 'production') + .click(); + cy.contains('Next step').click(); cy.contains('Create configuration'); cy.contains('Edit').click(); @@ -152,13 +154,23 @@ describe('Agent configuration', () => { 'serviceEnvironmentApi' ); cy.contains('Create configuration').click(); - cy.getByTestSubj('serviceNameComboBox').click().type('All').type('{enter}'); - cy.contains('All').realClick(); + cy.getByTestSubj('serviceNameComboBox').find('input').type('All{enter}'); + cy.getByTestSubj('serviceNameComboBox').find('input').click(); + cy.getByTestSubj('comboBoxOptionsList serviceNameComboBox-optionsList').should('be.visible'); + + cy.getByTestSubj('comboBoxOptionsList serviceNameComboBox-optionsList') + .contains('button', 'All') + .click(); cy.wait('@serviceEnvironmentApi'); - cy.getByTestSubj('serviceEnviromentComboBox').click({ force: true }).type('All'); + cy.getByTestSubj('serviceEnviromentComboBox').find('input').click(); + cy.getByTestSubj('comboBoxOptionsList serviceEnviromentComboBox-optionsList').should( + 'be.visible' + ); + cy.getByTestSubj('comboBoxOptionsList serviceEnviromentComboBox-optionsList') + .contains('button', 'All') + .click(); - cy.get('mark').contains('All').click({ force: true }); cy.contains('Next step').click(); cy.get('[data-test-subj="settingsPage_serviceName"]').contains('All'); cy.get('[data-test-subj="settingsPage_environmentName"]').contains('All'); diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts index d9c0ef08590c..5085fe7d171f 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/commands.ts @@ -55,26 +55,32 @@ Cypress.Commands.add('loginAsApmReadPrivilegesWithWriteSettingsUser', () => { Cypress.Commands.add( 'loginAs', ({ username, password }: { username: string; password: string }) => { - // cy.session(username, () => { - const kibanaUrl = Cypress.env('KIBANA_URL'); - cy.log(`Logging in as ${username} on ${kibanaUrl}`); - cy.visit('/'); - cy.request({ - log: true, - method: 'POST', - url: `${kibanaUrl}/internal/security/login`, - body: { - providerType: 'basic', - providerName: 'basic', - currentURL: `${kibanaUrl}/login`, - params: { username, password }, - }, - headers: { - 'kbn-xsrf': 'e2e_test', + cy.session( + username, + () => { + const kibanaUrl = Cypress.env('KIBANA_URL'); + cy.log(`Logging in as ${username} on ${kibanaUrl}`); + cy.visit('/'); + cy.request({ + log: true, + method: 'POST', + url: `${kibanaUrl}/internal/security/login`, + body: { + providerType: 'basic', + providerName: 'basic', + currentURL: `${kibanaUrl}/login`, + params: { username, password }, + }, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + }); + cy.visit('/'); }, - // }); - }); - cy.visit('/'); + { + cacheAcrossSpecs: true, + } + ); } ); @@ -87,8 +93,14 @@ Cypress.Commands.add('changeTimeRange', (value: string) => { cy.contains(value).click(); }); -Cypress.Commands.add('visitKibana', (url: string) => { - cy.visit(url); +Cypress.Commands.add('visitKibana', (url, options) => { + cy.visit(url, { + onBeforeLoad(win) { + if (options?.localStorageOptions && options.localStorageOptions.length > 0) { + options.localStorageOptions.forEach(([key, value]) => win.localStorage.setItem(key, value)); + } + }, + }); cy.getByTestSubj('kbnLoadingMessage').should('exist'); cy.getByTestSubj('kbnLoadingMessage').should('not.exist', { timeout: 50000, @@ -149,6 +161,10 @@ Cypress.Commands.add('withHidden', (selector, callback) => { cy.get(selector).invoke('attr', 'style', ''); }); +Cypress.Commands.add('waitUntilPageContentIsLoaded', () => { + cy.getByTestSubj('kbnAppWrapper visibleChrome').find('[aria-busy=false]').should('be.visible'); +}); + // A11y configuration const axeConfig = { diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts index 2c5a4ae35f31..3d46e63dfaaa 100644 --- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts +++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/support/types.d.ts @@ -19,11 +19,12 @@ declare namespace Cypress { password: string; }): Cypress.Chainable<Cypress.Response<any>>; changeTimeRange(value: string): void; - visitKibana(url: string): void; + visitKibana(url: string, options?: { localStorageOptions?: Array<[string, string]> }): void; selectAbsoluteTimeRange(start: string, end: string): void; expectAPIsToHaveBeenCalledWith(params: { apisIntercepted: string[]; value: string }): void; updateAdvancedSettings(settings: Record<string, unknown>): void; getByTestSubj(selector: string): Chainable<JQuery<Element>>; withHidden(selector: string, callback: () => void): void; + waitUntilPageContentIsLoaded(): void; } } diff --git a/x-pack/plugins/observability_solution/apm/kibana.jsonc b/x-pack/plugins/observability_solution/apm/kibana.jsonc index 656f898f2406..bcb0801fc639 100644 --- a/x-pack/plugins/observability_solution/apm/kibana.jsonc +++ b/x-pack/plugins/observability_solution/apm/kibana.jsonc @@ -37,7 +37,8 @@ "lens", "maps", "uiActions", - "logsDataAccess" + "logsDataAccess", + "savedSearch", ], "optionalPlugins": [ "actions", diff --git a/x-pack/plugins/observability_solution/apm/public/application/index.tsx b/x-pack/plugins/observability_solution/apm/public/application/index.tsx index 23dde7de8146..f9785a136b06 100644 --- a/x-pack/plugins/observability_solution/apm/public/application/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/application/index.tsx @@ -59,6 +59,7 @@ export const renderApp = ({ observabilityAIAssistant: pluginsStart.observabilityAIAssistant, share: pluginsSetup.share, kibanaEnvironment, + licensing: pluginsStart.licensing, }; // render APM feedback link in global help menu diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx index a5d0df3b0553..682634819e62 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/alerts_overview/index.tsx @@ -13,6 +13,10 @@ import { EuiPanel, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; import { BoolQuery } from '@kbn/es-query'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { + apmAlertingConsumers, + apmAlertingRuleTypeIds, +} from '../../../../common/alerting/config/apm_alerting_feature_ids'; import { ApmPluginStartDeps } from '../../../plugin'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { SERVICE_NAME } from '../../../../common/es_fields/apm'; @@ -107,7 +111,8 @@ export function AlertsOverview() { alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} id={'service-overview-alerts'} configurationId={AlertConsumers.OBSERVABILITY} - featureIds={[AlertConsumers.APM, AlertConsumers.OBSERVABILITY]} + ruleTypeIds={apmAlertingRuleTypeIds} + consumers={apmAlertingConsumers} query={esQuery} showAlertStatusWithFlapping cellContext={{ observabilityRuleTypeRegistry }} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx index 5432c70e57ab..4b93123b589b 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_failed_transactions_correlations.test.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React, { ReactNode } from 'react'; +import React, { PropsWithChildren } from 'react'; import { merge } from 'lodash'; import { createMemoryHistory } from 'history'; -import { renderHook, act } from '@testing-library/react-hooks'; + +import { act, waitFor, renderHook } from '@testing-library/react'; import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context'; import { @@ -22,7 +23,7 @@ import { fromQuery } from '../../shared/links/url_helpers'; import { useFailedTransactionsCorrelations } from './use_failed_transactions_correlations'; import type { APIEndpoint } from '../../../../server'; -function wrapper({ children, error = false }: { children?: ReactNode; error: boolean }) { +function wrapper({ children, error = false }: PropsWithChildren<{ error?: boolean }>) { const getHttpMethodMock = (method: 'GET' | 'POST') => jest.fn().mockImplementation(async (pathname) => { await delay(100); @@ -107,17 +108,18 @@ describe('useFailedTransactionsCorrelations', () => { wrapper, }); - try { + await waitFor(() => expect(result.current.progress).toEqual({ isRunning: true, loaded: 0, - }); - expect(result.current.response).toEqual({ ccsWarning: false }); - expect(typeof result.current.startFetch).toEqual('function'); - expect(typeof result.current.cancelFetch).toEqual('function'); - } finally { - unmount(); - } + }) + ); + + expect(result.current.response).toEqual({ ccsWarning: false }); + expect(result.current.startFetch).toEqual(expect.any(Function)); + expect(result.current.cancelFetch).toEqual(expect.any(Function)); + + unmount(); }); it('should not have received any results after 50ms', async () => { @@ -125,21 +127,21 @@ describe('useFailedTransactionsCorrelations', () => { wrapper, }); - try { - jest.advanceTimersByTime(50); + jest.advanceTimersByTime(50); + await waitFor(() => expect(result.current.progress).toEqual({ isRunning: true, loaded: 0, - }); - expect(result.current.response).toEqual({ ccsWarning: false }); - } finally { - unmount(); - } + }) + ); + + expect(result.current.response).toEqual({ ccsWarning: false }); + unmount(); }); it('should receive partial updates and finish running', async () => { - const { result, unmount, waitFor } = renderHook(() => useFailedTransactionsCorrelations(), { + const { result, unmount } = renderHook(() => useFailedTransactionsCorrelations(), { wrapper, }); @@ -253,29 +255,37 @@ describe('useFailedTransactionsCorrelations', () => { }); describe('when throwing an error', () => { it('should automatically start fetching results', async () => { - const { result, unmount } = renderHook(() => useFailedTransactionsCorrelations(), { - wrapper, - initialProps: { - error: true, - }, + const { result, unmount } = renderHook(useFailedTransactionsCorrelations, { + wrapper: ({ children }) => + React.createElement( + wrapper, + { + error: true, + }, + children + ), }); - try { + await waitFor(() => expect(result.current.progress).toEqual({ isRunning: true, loaded: 0, - }); - } finally { - unmount(); - } + }) + ); + + unmount(); }); it('should still be running after 50ms', async () => { - const { result, unmount } = renderHook(() => useFailedTransactionsCorrelations(), { - wrapper, - initialProps: { - error: true, - }, + const { result, unmount } = renderHook(useFailedTransactionsCorrelations, { + wrapper: ({ children }) => + React.createElement( + wrapper, + { + error: true, + }, + children + ), }); try { @@ -292,11 +302,15 @@ describe('useFailedTransactionsCorrelations', () => { }); it('should stop and return an error after more than 100ms', async () => { - const { result, unmount, waitFor } = renderHook(() => useFailedTransactionsCorrelations(), { - wrapper, - initialProps: { - error: true, - }, + const { result, unmount } = renderHook(useFailedTransactionsCorrelations, { + wrapper: ({ children }) => + React.createElement( + wrapper, + { + error: true, + }, + children + ), }); try { @@ -316,7 +330,7 @@ describe('useFailedTransactionsCorrelations', () => { describe('when canceled', () => { it('should stop running', async () => { - const { result, unmount, waitFor } = renderHook(() => useFailedTransactionsCorrelations(), { + const { result, unmount } = renderHook(() => useFailedTransactionsCorrelations(), { wrapper, }); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_latency_correlations.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_latency_correlations.test.tsx index 70446d1d2b1f..e76420e3c1a9 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_latency_correlations.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/correlations/use_latency_correlations.test.tsx @@ -5,10 +5,11 @@ * 2.0. */ -import React, { ReactNode } from 'react'; +import React, { PropsWithChildren } from 'react'; import { merge } from 'lodash'; import { createMemoryHistory } from 'history'; -import { renderHook, act } from '@testing-library/react-hooks'; + +import { act, waitFor, renderHook } from '@testing-library/react'; import { ApmPluginContextValue } from '../../../context/apm_plugin/apm_plugin_context'; import { @@ -22,7 +23,7 @@ import { fromQuery } from '../../shared/links/url_helpers'; import { useLatencyCorrelations } from './use_latency_correlations'; import type { APIEndpoint } from '../../../../server'; -function wrapper({ children, error = false }: { children?: ReactNode; error: boolean }) { +function wrapper({ children, error = false }: PropsWithChildren<{ error?: boolean }>) { const getHttpMethodMock = (method: 'GET' | 'POST') => jest.fn().mockImplementation(async (pathname) => { await delay(100); @@ -86,16 +87,17 @@ function wrapper({ children, error = false }: { children?: ReactNode; error: boo } describe('useLatencyCorrelations', () => { - beforeEach(async () => { - jest.useFakeTimers({ legacyFakeTimers: true }); - }); - afterEach(() => { - jest.useRealTimers(); - }); - describe('when successfully loading results', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + it('should automatically start fetching results', async () => { - const { result, unmount } = renderHook(() => useLatencyCorrelations(), { + const { result, unmount } = renderHook(useLatencyCorrelations, { wrapper, }); @@ -113,7 +115,7 @@ describe('useLatencyCorrelations', () => { }); it('should not have received any results after 50ms', async () => { - const { result, unmount } = renderHook(() => useLatencyCorrelations(), { + const { result, unmount } = renderHook(useLatencyCorrelations, { wrapper, }); @@ -131,7 +133,7 @@ describe('useLatencyCorrelations', () => { }); it('should receive partial updates and finish running', async () => { - const { result, unmount, waitFor } = renderHook(() => useLatencyCorrelations(), { + const { result, unmount } = renderHook(useLatencyCorrelations, { wrapper, }); @@ -213,12 +215,17 @@ describe('useLatencyCorrelations', () => { }); describe('when throwing an error', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + it('should automatically start fetching results', async () => { - const { result, unmount } = renderHook(() => useLatencyCorrelations(), { - wrapper, - initialProps: { - error: true, - }, + const { result, unmount } = renderHook(useLatencyCorrelations, { + wrapper: ({ children }) => wrapper({ children, error: true }), }); try { @@ -232,11 +239,8 @@ describe('useLatencyCorrelations', () => { }); it('should still be running after 50ms', async () => { - const { result, unmount } = renderHook(() => useLatencyCorrelations(), { - wrapper, - initialProps: { - error: true, - }, + const { result, unmount } = renderHook(useLatencyCorrelations, { + wrapper: ({ children }) => wrapper({ children, error: true }), }); try { @@ -253,22 +257,21 @@ describe('useLatencyCorrelations', () => { }); it('should stop and return an error after more than 100ms', async () => { - const { result, unmount, waitFor } = renderHook(() => useLatencyCorrelations(), { - wrapper, - initialProps: { - error: true, - }, + const { result, unmount } = renderHook(useLatencyCorrelations, { + wrapper: ({ children }) => wrapper({ children, error: true }), }); try { - jest.advanceTimersByTime(150); - await waitFor(() => expect(result.current.progress.error).toBeDefined()); - - expect(result.current.progress).toEqual({ - error: 'Something went wrong', - isRunning: false, - loaded: 0, + act(() => { + jest.advanceTimersByTime(150); }); + await waitFor(() => + expect(result.current.progress).toEqual({ + error: 'Something went wrong', + isRunning: false, + loaded: 0, + }) + ); } finally { unmount(); } @@ -276,8 +279,16 @@ describe('useLatencyCorrelations', () => { }); describe('when canceled', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + it('should stop running', async () => { - const { result, unmount, waitFor } = renderHook(() => useLatencyCorrelations(), { + const { result, unmount } = renderHook(useLatencyCorrelations, { wrapper, }); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/infra_overview/infra_tabs/use_tabs.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/infra_overview/infra_tabs/use_tabs.test.tsx index 245d4e90631a..b1a1fea3924e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/infra_overview/infra_tabs/use_tabs.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/infra_overview/infra_tabs/use_tabs.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React, { ReactNode } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useTabs } from './use_tabs'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; import { CoreStart } from '@kbn/core/public'; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/filter_warning.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/filter_warning.tsx new file mode 100644 index 000000000000..71b487ff626c --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/filter_warning.tsx @@ -0,0 +1,66 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText, EuiToolTip } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +interface Props { + hostNames?: string[]; + containerIds?: string[]; +} + +export function FilterWarning({ containerIds = [], hostNames = [] }: Props) { + const hasContainerIds = containerIds.length > 0; + + return hasContainerIds ? ( + <FilterWarningToolTip + values={containerIds} + label={i18n.translate('xpack.apm.profiling.topFunctions.filteredLabel.containerId', { + defaultMessage: "Displaying profiling insights from the service's container id(s)", + })} + /> + ) : ( + <FilterWarningToolTip + values={hostNames} + label={i18n.translate('xpack.apm.profiling.topFunctions.filteredLabel.hostName', { + defaultMessage: "Displaying profiling insights from the service's host(s)", + })} + /> + ); +} + +interface FilterWarningToolTipProps { + values: string[]; + label: string; +} +function FilterWarningToolTip({ values = [], label }: FilterWarningToolTipProps) { + function renderTooltipOptions() { + return ( + <ul> + {values.map((value) => ( + <li key={value}>{`- ${value}`}</li> + ))} + </ul> + ); + } + + return ( + <EuiFlexGroup gutterSize="none"> + <EuiFlexItem grow={false}> + <EuiText size="xs" color="subdued"> + {label} + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiToolTip content={renderTooltipOptions()}> + <EuiIcon type="questionInCircle" /> + </EuiToolTip> + </EuiFlexItem> + </EuiFlexGroup> + ); +} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/host_names_filter_warning.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/host_names_filter_warning.tsx deleted file mode 100644 index 0f3fb6cdb69f..000000000000 --- a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/host_names_filter_warning.tsx +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText, EuiToolTip } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; - -interface Props { - hostNames?: string[]; -} -export function HostnamesFilterWarning({ hostNames = [] }: Props) { - function renderTooltipOptions() { - return ( - <ul> - {hostNames.map((hostName) => ( - <li key={hostName}>{`- ${hostName}`}</li> - ))} - </ul> - ); - } - - return ( - <EuiFlexGroup gutterSize="none"> - <EuiFlexItem grow={false}> - <EuiText size="xs" color="subdued"> - {i18n.translate('xpack.apm.profiling.flamegraph.filteredLabel', { - defaultMessage: "Displaying profiling insights from the service's host(s)", - })} - </EuiText> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiToolTip content={renderTooltipOptions()}> - <EuiIcon type="questionInCircle" /> - </EuiToolTip> - </EuiFlexItem> - </EuiFlexGroup> - ); -} diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_flamegraph.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_flamegraph.tsx index 92442d223390..0d6681d942d5 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_flamegraph.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_flamegraph.tsx @@ -9,12 +9,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React from 'react'; import { ApmDataSourceWithSummary } from '../../../../common/data_source'; import { ApmDocumentType } from '../../../../common/document_type'; -import { HOST_NAME } from '../../../../common/es_fields/apm'; +import { CONTAINER_ID, HOST_NAME } from '../../../../common/es_fields/apm'; import { mergeKueries, toKueryFilterFormat } from '../../../../common/utils/kuery_utils'; import { useFetcher } from '../../../hooks/use_fetcher'; import { FlamegraphChart } from '../../shared/charts/flamegraph'; import { ProfilingFlamegraphLink } from '../../shared/profiling/flamegraph/flamegraph_link'; -import { HostnamesFilterWarning } from './host_names_filter_warning'; +import { FilterWarning } from './filter_warning'; interface Props { serviceName: string; @@ -60,17 +60,20 @@ export function ProfilingHostsFlamegraph({ [dataSource, serviceName, start, end, environment, kuery] ); - const hostNamesKueryFormat = toKueryFilterFormat(HOST_NAME, data?.hostNames || []); + const profilingKueryFilter = + data?.containerIds && data.containerIds.length > 0 + ? toKueryFilterFormat(CONTAINER_ID, data?.containerIds || []) + : toKueryFilterFormat(HOST_NAME, data?.hostNames || []); return ( <> <EuiFlexGroup> <EuiFlexItem grow={false}> - <HostnamesFilterWarning hostNames={data?.hostNames} /> + <FilterWarning containerIds={data?.containerIds} hostNames={data?.hostNames} /> </EuiFlexItem> <EuiFlexItem> <ProfilingFlamegraphLink - kuery={mergeKueries([`(${hostNamesKueryFormat})`, kuery])} + kuery={mergeKueries([`(${profilingKueryFilter})`, kuery])} rangeFrom={rangeFrom} rangeTo={rangeTo} justifyContent="flexEnd" diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_top_functions.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_top_functions.tsx index 88726f880b66..2ad1106ab9ad 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_top_functions.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/profiling_overview/profiling_hosts_top_functions.tsx @@ -10,11 +10,11 @@ import { EmbeddableFunctions } from '@kbn/observability-shared-plugin/public'; import React from 'react'; import { ApmDataSourceWithSummary } from '../../../../common/data_source'; import { ApmDocumentType } from '../../../../common/document_type'; -import { HOST_NAME } from '../../../../common/es_fields/apm'; +import { CONTAINER_ID, HOST_NAME } from '../../../../common/es_fields/apm'; import { mergeKueries, toKueryFilterFormat } from '../../../../common/utils/kuery_utils'; import { isPending, useFetcher } from '../../../hooks/use_fetcher'; import { ProfilingTopNFunctionsLink } from '../../shared/profiling/top_functions/top_functions_link'; -import { HostnamesFilterWarning } from './host_names_filter_warning'; +import { FilterWarning } from './filter_warning'; interface Props { serviceName: string; @@ -66,17 +66,20 @@ export function ProfilingHostsTopNFunctions({ [dataSource, serviceName, start, end, environment, startIndex, endIndex, kuery] ); - const hostNamesKueryFormat = toKueryFilterFormat(HOST_NAME, data?.hostNames || []); + const profilingKueryFilter = + data?.containerIds && data.containerIds.length > 0 + ? toKueryFilterFormat(CONTAINER_ID, data?.containerIds || []) + : toKueryFilterFormat(HOST_NAME, data?.hostNames || []); return ( <> <EuiFlexGroup> <EuiFlexItem grow={false}> - <HostnamesFilterWarning hostNames={data?.hostNames} /> + <FilterWarning containerIds={data?.containerIds} hostNames={data?.hostNames} /> </EuiFlexItem> <EuiFlexItem> <ProfilingTopNFunctionsLink - kuery={mergeKueries([`(${hostNamesKueryFormat})`, kuery])} + kuery={mergeKueries([`(${profilingKueryFilter})`, kuery])} rangeFrom={rangeFrom} rangeTo={rangeTo} justifyContent="flexEnd" diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx index a1dadbf186b9..35f502642518 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_logs/index.tsx @@ -6,9 +6,9 @@ */ import React, { useMemo } from 'react'; -import moment from 'moment'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; -import { LogStream } from '@kbn/logs-shared-plugin/public'; +import { LazySavedSearchComponent } from '@kbn/saved-search-component'; +import useAsync from 'react-use/lib/useAsync'; import { ENVIRONMENT_ALL } from '../../../../common/environment_filter_values'; import { CONTAINER_ID, SERVICE_ENVIRONMENT, SERVICE_NAME } from '../../../../common/es_fields/apm'; import { useApmServiceContext } from '../../../context/apm_service/use_apm_service_context'; @@ -35,6 +35,19 @@ export function ServiceLogs() { } export function ClassicServiceLogsStream() { + const { + services: { + logsDataAccess: { + services: { logSourcesService }, + }, + embeddable, + dataViews, + data: { + search: { searchSource }, + }, + }, + } = useKibana(); + const { serviceName } = useApmServiceContext(); const { @@ -62,17 +75,31 @@ export function ClassicServiceLogsStream() { [environment, kuery, serviceName, start, end] ); - return ( - <LogStream - logView={{ type: 'log-view-reference', logViewId: 'default' }} - columns={[{ type: 'timestamp' }, { type: 'message' }]} + const logSources = useAsync(logSourcesService.getFlattenedLogSources); + + const timeRange = useMemo(() => ({ from: start, to: end }), [start, end]); + + const query = useMemo( + () => ({ + language: 'kuery', + query: getInfrastructureKQLFilter({ data, serviceName, environment }), + }), + [data, serviceName, environment] + ); + + return logSources.value ? ( + <LazySavedSearchComponent + dependencies={{ embeddable, searchSource, dataViews }} + index={logSources.value} + timeRange={timeRange} + query={query} height={'60vh'} - startTimestamp={moment(start).valueOf()} - endTimestamp={moment(end).valueOf()} - query={getInfrastructureKQLFilter({ data, serviceName, environment })} - showFlyoutAction + displayOptions={{ + enableDocumentViewer: true, + enableFilters: false, + }} /> - ); + ) : null; } export function ServiceLogsOverview() { diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_map/empty_banner.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_map/empty_banner.test.tsx index 20149d0f4079..168180e89c97 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_map/empty_banner.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_map/empty_banner.test.tsx @@ -58,11 +58,12 @@ describe('EmptyBanner', () => { it('does not render null', async () => { const component = renderWithTheme(<EmptyBanner />, { wrapper }); - await act(async () => { + act(() => { cy.add({ data: { id: 'test id' } }); - await waitFor(() => { - expect(component.container.children.length).toBeGreaterThan(0); - }); + }); + + await waitFor(() => { + expect(component.container.children.length).toBeGreaterThan(0); }); }); }); diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/service_map/use_cytoscape_event_handlers.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/service_map/use_cytoscape_event_handlers.test.tsx index 0f7fd67ae7c0..31604d893401 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/service_map/use_cytoscape_event_handlers.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/service_map/use_cytoscape_event_handlers.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import cytoscape from 'cytoscape'; import dagre from 'cytoscape-dagre'; import { EuiTheme } from '@kbn/kibana-react-plugin/common'; diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/trace_link/trace_link.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/trace_link/trace_link.test.tsx index 3250702b0cb8..06f7101520ba 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/app/trace_link/trace_link.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/app/trace_link/trace_link.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, render, waitFor } from '@testing-library/react'; +import { render, waitFor } from '@testing-library/react'; import { shallow } from 'enzyme'; import React, { ReactNode } from 'react'; import { MemoryRouter } from 'react-router-dom'; @@ -67,12 +67,9 @@ describe('TraceLink', () => { }, }); - let result; - act(() => { - const component = render(<TraceLink />, renderOptions); + const component = render(<TraceLink />, renderOptions); - result = component.getByText('Fetching trace...'); - }); + const result = component.getByText('Fetching trace...'); await waitFor(() => {}); expect(result).toBeDefined(); }); diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_service_template/use_tabs.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_service_template/use_tabs.test.tsx index 05c8464929d5..fee28395960c 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_service_template/use_tabs.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/apm_service_template/use_tabs.test.tsx @@ -6,7 +6,7 @@ */ import { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import React, { ReactNode } from 'react'; import { ServerlessType } from '../../../../../common/serverless'; diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_error_rate_chart.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_error_rate_chart.tsx index f75f9f08cc31..6cbd3e188720 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_error_rate_chart.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_error_rate_chart.tsx @@ -14,7 +14,7 @@ import { useApmParams } from '../../../../hooks/use_apm_params'; import { useFetcher } from '../../../../hooks/use_fetcher'; import { useTimeRange } from '../../../../hooks/use_time_range'; import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; -import { asInteger } from '../../../../../common/utils/formatters'; +import { asDecimalOrInteger } from '../../../../../common/utils/formatters'; import { TooltipContent } from './tooltip_content'; import { Popover } from './popover'; import { mergeKueries, toKueryFilterFormat } from '../../../../../common/utils/kuery_utils'; @@ -146,7 +146,7 @@ export function LogErrorRateChart({ height }: { height: number }) { showAnnotations={false} fetchStatus={status} timeseries={timeseries} - yLabelFormat={asInteger} + yLabelFormat={asDecimalOrInteger} /> </EuiPanel> ); diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_rate_chart.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_rate_chart.tsx index f4d5981da38e..8025a628067e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_rate_chart.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/log_rates/log_rate_chart.tsx @@ -13,7 +13,7 @@ import { useApmParams } from '../../../../hooks/use_apm_params'; import { useFetcher } from '../../../../hooks/use_fetcher'; import { useTimeRange } from '../../../../hooks/use_time_range'; import { APIReturnType } from '../../../../services/rest/create_call_apm_api'; -import { asInteger } from '../../../../../common/utils/formatters'; +import { asDecimalOrInteger } from '../../../../../common/utils/formatters'; import { TooltipContent } from './tooltip_content'; import { Popover } from './popover'; import { ChartType, getTimeSeriesColor } from '../helper/get_timeseries_color'; @@ -129,7 +129,7 @@ export function LogRateChart({ height }: { height: number }) { showAnnotations={false} fetchStatus={status} timeseries={timeseries} - yLabelFormat={asInteger} + yLabelFormat={asDecimalOrInteger} /> </EuiPanel> ); diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx index d71562e425e9..748b78366174 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/charts/timeline/marker/error_marker.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { fireEvent } from '@testing-library/react'; -import { act } from '@testing-library/react-hooks'; +import { fireEvent, act } from '@testing-library/react'; import React, { ReactNode } from 'react'; import { MemoryRouter } from 'react-router-dom'; import { MockApmPluginContextWrapper } from '../../../../../context/apm_plugin/mock_apm_plugin_context'; diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/service_transactions_overview_link.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/service_transactions_overview_link.test.tsx index 54999ead161b..ce2a56a3ecc8 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/service_transactions_overview_link.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/service_transactions_overview_link.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { render } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { render, renderHook } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import React from 'react'; import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; @@ -19,7 +18,7 @@ import { const history = createMemoryHistory(); function wrapper({ queryParams }: { queryParams?: Record<string, unknown> }) { - return ({ children }: { children: React.ReactElement }) => ( + return ({ children }: React.PropsWithChildren) => ( <MockApmPluginContextWrapper history={history}> <MockUrlParamsContextProvider params={queryParams}>{children}</MockUrlParamsContextProvider> </MockApmPluginContextWrapper> diff --git a/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/transaction_overview_link.test.tsx b/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/transaction_overview_link.test.tsx index bf095a4925fc..a1836a2a336e 100644 --- a/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/transaction_overview_link.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/components/shared/links/apm/transaction_overview_link.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { render } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { render, renderHook } from '@testing-library/react'; import { createMemoryHistory } from 'history'; import React from 'react'; import { MockApmPluginContextWrapper } from '../../../../context/apm_plugin/mock_apm_plugin_context'; @@ -15,7 +14,7 @@ import { TransactionOverviewLink, useTransactionsOverviewHref } from './transact const history = createMemoryHistory(); -function Wrapper({ children }: { children: React.ReactElement }) { +function Wrapper({ children }: React.PropsWithChildren) { return ( <MockApmPluginContextWrapper history={history}> <MockUrlParamsContextProvider>{children}</MockUrlParamsContextProvider> diff --git a/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx b/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx index e8ab9530b574..03711b7265e3 100644 --- a/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx +++ b/x-pack/plugins/observability_solution/apm/public/context/apm_plugin/apm_plugin_context.tsx @@ -19,6 +19,7 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai-assistant-plugin/public'; import { SharePluginSetup } from '@kbn/share-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { ApmPluginSetupDeps } from '../../plugin'; import type { ConfigSchema } from '../..'; import type { KibanaEnvContext } from '../kibana_environment_context/kibana_environment_context'; @@ -40,6 +41,7 @@ export interface ApmPluginContextValue { share: SharePluginSetup; kibanaEnvironment: KibanaEnvContext; lens: LensPublicStart; + licensing: LicensingPluginStart; } export const ApmPluginContext = createContext({} as ApmPluginContextValue); diff --git a/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx b/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx index 569c21637cef..927e4367dd37 100644 --- a/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx +++ b/x-pack/plugins/observability_solution/apm/public/context/license/license_context.tsx @@ -14,8 +14,7 @@ import { InvalidLicenseNotification } from './invalid_license_notification'; export const LicenseContext = React.createContext<ILicense | undefined>(undefined); export function LicenseProvider({ children }: { children: React.ReactChild }) { - const { plugins } = useApmPluginContext(); - const { licensing } = plugins; + const { licensing } = useApmPluginContext(); const license = useObservable(licensing.license$); // if license is not loaded yet, consider it valid const hasInvalidLicense = license?.isActive === false; diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_breakpoints.test.tsx b/x-pack/plugins/observability_solution/apm/public/hooks/use_breakpoints.test.tsx index d311f48fa0e5..7a9a7aa33b6b 100644 --- a/x-pack/plugins/observability_solution/apm/public/hooks/use_breakpoints.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_breakpoints.test.tsx @@ -6,7 +6,7 @@ */ import React, { FC, PropsWithChildren } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { EuiProvider } from '@elastic/eui'; import { useBreakpoints } from './use_breakpoints'; diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_debounce.test.tsx b/x-pack/plugins/observability_solution/apm/public/hooks/use_debounce.test.tsx index 6701024eea9e..98543601cab2 100644 --- a/x-pack/plugins/observability_solution/apm/public/hooks/use_debounce.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_debounce.test.tsx @@ -4,11 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; + +import { renderHook, act } from '@testing-library/react'; import { useStateDebounced } from './use_debounce'; // Replace 'your-module' with the actual module path describe('useStateDebounced', () => { - jest.useFakeTimers(); beforeAll(() => { // Mocks console.error so it won't polute tests output when testing the api throwing error jest.spyOn(console, 'error').mockImplementation(() => null); @@ -18,6 +18,14 @@ describe('useStateDebounced', () => { jest.restoreAllMocks(); }); + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + it('returns the initial value and a debounced setter function', () => { const { result } = renderHook(() => useStateDebounced('initialValue', 300)); @@ -34,7 +42,9 @@ describe('useStateDebounced', () => { result.current[1]('updatedValue'); }); expect(result.current[0]).toBe('initialValue'); - jest.advanceTimersByTime(300); + act(() => { + jest.advanceTimersByTime(300); + }); expect(result.current[0]).toBe('updatedValue'); }); @@ -44,12 +54,15 @@ describe('useStateDebounced', () => { act(() => { result.current[1]('updatedValue'); }); - jest.advanceTimersByTime(150); + act(() => { + jest.advanceTimersByTime(150); + }); expect(result.current[0]).toBe('initialValue'); act(() => { result.current[1]('newUpdatedValue'); + jest.advanceTimersByTime(400); }); - jest.advanceTimersByTime(400); + expect(result.current[0]).toBe('newUpdatedValue'); }); }); diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_fetcher.test.tsx b/x-pack/plugins/observability_solution/apm/public/hooks/use_fetcher.test.tsx index 14c58ab3977e..be61a03e2bd8 100644 --- a/x-pack/plugins/observability_solution/apm/public/hooks/use_fetcher.test.tsx +++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_fetcher.test.tsx @@ -5,46 +5,42 @@ * 2.0. */ -import { renderHook, RenderHookResult } from '@testing-library/react-hooks'; -import React, { ReactNode } from 'react'; +import React from 'react'; +import { waitFor, act, renderHook, type RenderHookResult } from '@testing-library/react'; import { CoreStart } from '@kbn/core/public'; import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; import { delay } from '../utils/test_helpers'; -import { FetcherResult, useFetcher, isPending, FETCH_STATUS } from './use_fetcher'; +import { useFetcher, isPending, FETCH_STATUS } from './use_fetcher'; // Wrap the hook with a provider so it can useKibana const KibanaReactContext = createKibanaReactContext({ notifications: { toasts: { add: () => {}, danger: () => {} } }, } as unknown as Partial<CoreStart>); -interface WrapperProps { - children?: ReactNode; - callback: () => Promise<string>; - args: string[]; -} -function wrapper({ children }: WrapperProps) { +function wrapper({ children }: React.PropsWithChildren) { return <KibanaReactContext.Provider>{children}</KibanaReactContext.Provider>; } describe('useFetcher', () => { describe('when resolving after 500ms', () => { - let hook: RenderHookResult< - WrapperProps, - FetcherResult<string> & { - refetch: () => void; - } - >; + let hook: RenderHookResult<ReturnType<typeof useFetcher>, Parameters<typeof useFetcher>>; beforeEach(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); + async function fn() { await delay(500); return 'response from hook'; } - hook = renderHook(() => useFetcher(() => fn(), []), { wrapper }); + + hook = renderHook(() => useFetcher(fn, []), { wrapper }); }); - it('should have loading spinner initally', async () => { + afterEach(() => { + jest.useRealTimers(); + }); + + it('should have loading spinner initially', () => { expect(hook.result.current).toEqual({ data: undefined, error: undefined, @@ -53,8 +49,10 @@ describe('useFetcher', () => { }); }); - it('should still show loading spinner after 100ms', async () => { - jest.advanceTimersByTime(100); + it('should still show loading spinner after 100ms', () => { + act(() => { + jest.advanceTimersByTime(100); + }); expect(hook.result.current).toEqual({ data: undefined, @@ -65,8 +63,11 @@ describe('useFetcher', () => { }); it('should show success after 1 second', async () => { - jest.advanceTimersByTime(1000); - await hook.waitForNextUpdate(); + act(() => { + jest.advanceTimersByTime(1000); + }); + + await waitFor(() => expect(hook.result.current.status).toBe('success')); expect(hook.result.current).toEqual({ data: 'response from hook', @@ -78,23 +79,23 @@ describe('useFetcher', () => { }); describe('when throwing after 500ms', () => { - let hook: RenderHookResult< - WrapperProps, - FetcherResult<string> & { - refetch: () => void; - } - >; + let hook: RenderHookResult<ReturnType<typeof useFetcher>, Parameters<typeof useFetcher>>; beforeEach(() => { - jest.useFakeTimers({ legacyFakeTimers: true }); + jest.useFakeTimers(); + async function fn(): Promise<string> { await delay(500); throw new Error('Something went wrong'); } - hook = renderHook(() => useFetcher(() => fn(), []), { wrapper }); + hook = renderHook(() => useFetcher(fn, []), { wrapper }); + }); + + afterEach(() => { + jest.useRealTimers(); }); - it('should have loading spinner initally', async () => { + it('should have loading spinner initially', () => { expect(hook.result.current).toEqual({ data: undefined, error: undefined, @@ -103,8 +104,10 @@ describe('useFetcher', () => { }); }); - it('should still show loading spinner after 100ms', async () => { - jest.advanceTimersByTime(100); + it('should still show loading spinner after 100ms', () => { + act(() => { + jest.advanceTimersByTime(100); + }); expect(hook.result.current).toEqual({ data: undefined, @@ -115,8 +118,11 @@ describe('useFetcher', () => { }); it('should show error after 1 second', async () => { - jest.advanceTimersByTime(1000); - await hook.waitForNextUpdate(); + act(() => { + jest.advanceTimersByTime(1000); + }); + + await waitFor(() => expect(hook.result.current.status).toBe('failure')); expect(hook.result.current).toEqual({ data: undefined, @@ -128,20 +134,27 @@ describe('useFetcher', () => { }); describe('when a hook already has data', () => { - it('should show "first response" while loading "second response"', async () => { - jest.useFakeTimers({ legacyFakeTimers: true }); + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + it('should show "first response" while loading "second response"', async () => { const hook = renderHook( /* eslint-disable-next-line react-hooks/exhaustive-deps */ ({ callback, args }) => useFetcher(callback, args), { initialProps: { - callback: async () => 'first response', + callback: () => Promise.resolve('first response'), args: ['a'], }, wrapper, } ); + expect(hook.result.current).toEqual({ data: undefined, error: undefined, @@ -149,15 +162,15 @@ describe('useFetcher', () => { status: 'loading', }); - await hook.waitForNextUpdate(); - // assert: first response has loaded and should be rendered - expect(hook.result.current).toEqual({ - data: 'first response', - error: undefined, - refetch: expect.any(Function), - status: 'success', - }); + await waitFor(() => + expect(hook.result.current).toEqual({ + data: 'first response', + error: undefined, + refetch: expect.any(Function), + status: 'success', + }) + ); // act: re-render hook with async callback hook.rerender({ @@ -168,55 +181,92 @@ describe('useFetcher', () => { args: ['b'], }); - jest.advanceTimersByTime(100); - - // assert: while loading new data the previous data should still be rendered - expect(hook.result.current).toEqual({ - data: 'first response', - error: undefined, - refetch: expect.any(Function), - status: 'loading', + act(() => { + jest.advanceTimersByTime(100); }); - jest.advanceTimersByTime(500); - await hook.waitForNextUpdate(); + // assert: while loading new data the previous data should still be rendered + await waitFor(() => + expect(hook.result.current).toEqual({ + data: 'first response', + error: undefined, + refetch: expect.any(Function), + status: 'loading', + }) + ); - // assert: "second response" has loaded and should be rendered - expect(hook.result.current).toEqual({ - data: 'second response', - error: undefined, - refetch: expect.any(Function), - status: 'success', + act(() => { + jest.advanceTimersByTime(500); }); + + await waitFor(() => + expect(hook.result.current).toEqual({ + data: 'second response', + error: undefined, + refetch: expect.any(Function), + status: 'success', + }) + ); }); it('should return the same object reference when data is unchanged between rerenders', async () => { + const initialProps = { + callback: () => Promise.resolve('data response'), + args: ['a'], + }; + const hook = renderHook( /* eslint-disable-next-line react-hooks/exhaustive-deps */ ({ callback, args }) => useFetcher(callback, args), { - initialProps: { - callback: async () => 'data response', - args: ['a'], - }, + initialProps, wrapper, } ); - await hook.waitForNextUpdate(); + + act(() => { + jest.runAllTimers(); + }); + + // assert: initial data has loaded; + await waitFor(() => + expect(hook.result.current).toEqual( + expect.objectContaining({ + data: 'data response', + status: 'success', + }) + ) + ); + const firstResult = hook.result.current; - hook.rerender(); + hook.rerender(initialProps); + + expect(hook.result.current).toEqual( + expect.objectContaining({ + data: 'data response', + status: 'success', + }) + ); + const secondResult = hook.result.current; // assert: subsequent rerender returns the same object reference expect(secondResult === firstResult).toEqual(true); hook.rerender({ - callback: async () => { - return 'second response'; - }, + callback: () => Promise.resolve('second response'), args: ['b'], }); - await hook.waitForNextUpdate(); + + await waitFor(() => + expect(hook.result.current).toEqual( + expect.objectContaining({ + data: 'second response', + status: 'success', + }) + ) + ); + const thirdResult = hook.result.current; // assert: rerender with different data returns a new object diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_time_range.test.ts b/x-pack/plugins/observability_solution/apm/public/hooks/use_time_range.test.ts index 2bbc5c60ca91..2f6c08aad8cc 100644 --- a/x-pack/plugins/observability_solution/apm/public/hooks/use_time_range.test.ts +++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_time_range.test.ts @@ -4,11 +4,12 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook, RenderHookResult } from '@testing-library/react-hooks'; + +import { renderHook, RenderHookResult } from '@testing-library/react'; import { useTimeRange } from './use_time_range'; describe('useTimeRange', () => { - let hook: RenderHookResult<Parameters<typeof useTimeRange>[0], ReturnType<typeof useTimeRange>>; + let hook: RenderHookResult<ReturnType<typeof useTimeRange>, Parameters<typeof useTimeRange>[0]>; beforeEach(() => { Date.now = jest.fn(() => new Date(Date.UTC(2021, 0, 1, 12)).valueOf()); diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts index b21bdedac9ef..532c0498f7a5 100644 --- a/x-pack/plugins/observability_solution/apm/public/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts @@ -34,7 +34,7 @@ import { Start as InspectorPluginStart } from '@kbn/inspector-plugin/public'; import type { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { LensPublicStart } from '@kbn/lens-plugin/public'; import { LicenseManagementUIPluginSetup } from '@kbn/license-management-plugin/public'; -import type { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { MapsStartApi } from '@kbn/maps-plugin/public'; import type { MlPluginSetup, MlPluginStart } from '@kbn/ml-plugin/public'; import type { @@ -70,6 +70,8 @@ import { map } from 'rxjs'; import type { CloudSetup } from '@kbn/cloud-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; import { LogsSharedClientStartExports } from '@kbn/logs-shared-plugin/public'; +import { LogsDataAccessPluginStart } from '@kbn/logs-data-access-plugin/public'; +import { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { ConfigSchema } from '.'; import { registerApmRuleTypes } from './components/alerting/rule_types/register_apm_rule_types'; import { registerEmbeddables } from './embeddable/register_embeddables'; @@ -96,7 +98,6 @@ export interface ApmPluginSetupDeps { unifiedSearch: UnifiedSearchPublicPluginStart; features: FeaturesPluginSetup; home?: HomePublicPluginSetup; - licensing: LicensingPluginSetup; licenseManagement?: LicenseManagementUIPluginSetup; ml?: MlPluginSetup; observability: ObservabilityPublicSetup; @@ -122,7 +123,7 @@ export interface ApmPluginStartDeps { embeddable: EmbeddableStart; home: void; inspector: InspectorPluginStart; - licensing: void; + licensing: LicensingPluginStart; maps?: MapsStartApi; ml?: MlPluginStart; triggersActionsUi: TriggersAndActionsUIPublicPluginStart; @@ -144,6 +145,8 @@ export interface ApmPluginStartDeps { metricsDataAccess: MetricsDataPluginStart; uiSettings: IUiSettingsClient; logsShared: LogsSharedClientStartExports; + logsDataAccess: LogsDataAccessPluginStart; + savedSearch: SavedSearchPublicPluginStart; } const applicationsTitle = i18n.translate('xpack.apm.navigation.rootTitle', { @@ -198,7 +201,6 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> { const { featureFlags } = config; if (pluginSetupDeps.home) { - pluginSetupDeps.home.environment.update({ apmUi: true }); pluginSetupDeps.home.featureCatalogue.register(featureCatalogueEntry); } @@ -350,12 +352,13 @@ export class ApmPlugin implements Plugin<ApmPluginSetup, ApmPluginStart> { core.application.register({ id: 'apm', - title: 'APM', + title: 'Applications', order: 8300, euiIconType: 'logoObservability', appRoute: '/app/apm', icon: 'plugins/apm/public/icon.svg', category: DEFAULT_APP_CATEGORIES.observability, + keywords: ['apm'], deepLinks: [ { id: 'service-groups-list', diff --git a/x-pack/plugins/observability_solution/apm/scripts/test/dat.js b/x-pack/plugins/observability_solution/apm/scripts/test/dat.js new file mode 100644 index 000000000000..b457cd4da5e7 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm/scripts/test/dat.js @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* eslint-disable no-console */ +const { times } = require('lodash'); +const yargs = require('yargs'); +const path = require('path'); +const childProcess = require('child_process'); +const { REPO_ROOT } = require('@kbn/repo-info'); + +const { argv } = yargs(process.argv.slice(2)) + .option('serverless', { + default: false, + type: 'boolean', + description: 'Loads serverless configuration', + }) + .option('stateful', { + default: false, + type: 'boolean', + description: 'Loads stateful configuration', + }) + .option('server', { + default: false, + type: 'boolean', + description: 'Only start ES and Kibana', + }) + .option('runner', { + default: false, + type: 'boolean', + description: 'Only run tests', + }) + .option('grep', { + alias: 'spec', + type: 'string', + description: 'Specify the specs to run', + }) + .option('grep-files', { + alias: 'files', + type: 'array', + string: true, + description: 'Specify the files to run', + }) + .option('inspect', { + default: false, + type: 'boolean', + description: 'Add --inspect-brk flag to the ftr for debugging', + }) + .option('times', { + type: 'number', + description: 'Repeat the test n number of times', + }) + .option('updateSnapshots', { + default: false, + type: 'boolean', + description: 'Update snapshots', + }) + .option('bail', { + default: false, + type: 'boolean', + description: 'Stop the test run at the first failure', + }) + .check((argv) => { + const { inspect, runner } = argv; + if (inspect && !runner) { + throw new Error('--inspect can only be used with --runner'); + } else { + return true; + } + }) + .help(); + +const { serverless, stateful, bail, server, runner, grep, grepFiles, inspect, updateSnapshots } = + argv; + +if ((serverless === false && stateful === false) || (serverless && stateful)) { + throw new Error('Please specify either --stateful or --serverless'); +} + +let ftrScript = 'functional_tests'; +if (server) { + ftrScript = 'functional_tests_server'; +} else if (runner) { + ftrScript = 'functional_test_runner'; +} + +const environment = serverless ? 'serverless' : 'stateful'; + +const cmd = [ + 'node', + ...(inspect ? ['--inspect-brk'] : []), + `${REPO_ROOT}/scripts/${ftrScript}`, + ...(grep ? [`--grep "${grep}"`] : []), + ...(updateSnapshots ? [`--updateSnapshots`] : []), + ...(bail ? [`--bail`] : []), + `--config ${REPO_ROOT}/x-pack/test/api_integration/deployment_agnostic/configs/${environment}/oblt.apm.${environment}.config.ts`, +].join(' '); + +console.log(`Running: "${cmd}"`); + +function runTests() { + childProcess.execSync(cmd, { + cwd: path.join(__dirname), + stdio: 'inherit', + env: { ...process.env, APM_TEST_GREP_FILES: JSON.stringify(grepFiles) }, + }); +} + +if (argv.times) { + const runCounter = { succeeded: 0, failed: 0, remaining: argv.times }; + let exitStatus = 0; + times(argv.times, () => { + try { + runTests(); + runCounter.succeeded++; + } catch (e) { + if (bail) { + throw e; + } + + exitStatus = 1; + runCounter.failed++; + } + runCounter.remaining--; + if (argv.times > 1) { + console.log(runCounter); + } + }); + process.exit(exitStatus); +} else { + runTests(); +} diff --git a/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts b/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts index 1dff57cef660..6a65e6126ff2 100644 --- a/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/assistant_functions/index.ts @@ -72,7 +72,10 @@ export function registerAssistantFunctions({ ruleDataClient, plugins, getApmIndices: async () => { - const apmIndices = await plugins.apmDataAccess.setup.getApmIndices(); + const coreContext = await resources.context.core; + const apmIndices = await plugins.apmDataAccess.setup.getApmIndices( + coreContext.savedObjects.client + ); return apmIndices; }, }; diff --git a/x-pack/plugins/observability_solution/apm/server/feature.ts b/x-pack/plugins/observability_solution/apm/server/feature.ts index f9b047c602cd..6e129d298e0a 100644 --- a/x-pack/plugins/observability_solution/apm/server/feature.ts +++ b/x-pack/plugins/observability_solution/apm/server/feature.ts @@ -15,10 +15,14 @@ import { import { APM_INDEX_SETTINGS_SAVED_OBJECT_TYPE } from '@kbn/apm-data-access-plugin/server/saved_objects/apm_indices'; import { ApmRuleType } from '@kbn/rule-data-utils'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureConfig, KibanaFeatureScope } from '@kbn/features-plugin/common'; import { APM_SERVER_FEATURE_ID } from '../common/rules/apm_rule_types'; -const ruleTypes = Object.values(ApmRuleType); +const alertingFeatures = Object.values(ApmRuleType).map((ruleTypeId) => ({ + ruleTypeId, + consumers: [APM_SERVER_FEATURE_ID, ALERTING_FEATURE_ID], +})); export const APM_FEATURE: KibanaFeatureConfig = { id: APM_SERVER_FEATURE_ID, @@ -33,7 +37,7 @@ export const APM_FEATURE: KibanaFeatureConfig = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: ruleTypes, + alerting: alertingFeatures, // see x-pack/plugins/features/common/feature_kibana_privileges.ts privileges: { all: { @@ -46,10 +50,10 @@ export const APM_FEATURE: KibanaFeatureConfig = { }, alerting: { alert: { - all: ruleTypes, + all: alertingFeatures, }, rule: { - all: ruleTypes, + all: alertingFeatures, }, }, management: { @@ -67,10 +71,10 @@ export const APM_FEATURE: KibanaFeatureConfig = { }, alerting: { alert: { - read: ruleTypes, + read: alertingFeatures, }, rule: { - read: ruleTypes, + read: alertingFeatures, }, }, management: { diff --git a/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts b/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts index b0e601fd4c0d..95c29472dbc7 100644 --- a/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts +++ b/x-pack/plugins/observability_solution/apm/server/lib/helpers/get_apm_alerts_client.ts @@ -12,6 +12,7 @@ import { DataTier } from '@kbn/observability-shared-plugin/common'; import { searchExcludedDataTiers } from '@kbn/observability-plugin/common/ui_settings_keys'; import { estypes } from '@elastic/elasticsearch'; import { getDataTierFilterCombined } from '@kbn/apm-data-access-plugin/server/utils'; +import { apmAlertingRuleTypeIds } from '../../../common/alerting/config/apm_alerting_feature_ids'; import type { MinimalAPMRouteHandlerResources } from '../../routes/apm_routes/register_apm_server_routes'; export type ApmAlertsClient = Awaited<ReturnType<typeof getApmAlertsClient>>; @@ -31,7 +32,7 @@ export async function getApmAlertsClient({ const ruleRegistryPluginStart = await plugins.ruleRegistry.start(); const alertsClient = await ruleRegistryPluginStart.getRacClientWithRequest(request); - const apmAlertsIndices = await alertsClient.getAuthorizedAlertsIndices(['apm']); + const apmAlertsIndices = await alertsClient.getAuthorizedAlertsIndices(apmAlertingRuleTypeIds); if (!apmAlertsIndices || isEmpty(apmAlertsIndices)) { throw Error('No alert indices exist for "apm"'); diff --git a/x-pack/plugins/observability_solution/apm/server/plugin.ts b/x-pack/plugins/observability_solution/apm/server/plugin.ts index de49ebcebf8b..1142a5c69a51 100644 --- a/x-pack/plugins/observability_solution/apm/server/plugin.ts +++ b/x-pack/plugins/observability_solution/apm/server/plugin.ts @@ -16,6 +16,7 @@ import { registerAssistantFunctions } from './assistant_functions'; import { registerDeprecations } from './deprecations'; import { APM_FEATURE, registerFeaturesUsage } from './feature'; import { createApmTelemetry } from './lib/apm_telemetry'; +import { getInternalSavedObjectsClient } from './lib/helpers/get_internal_saved_objects_client'; import { APM_RULE_TYPE_ALERT_CONTEXT, apmRuleTypeAlertFieldMap, @@ -114,6 +115,13 @@ export class APMPlugin }; }) as APMRouteHandlerResources['plugins']; + const apmIndicesPromise = (async () => { + const coreStart = await getCoreStart(); + const soClient = await getInternalSavedObjectsClient(coreStart); + const { getApmIndices } = plugins.apmDataAccess; + return getApmIndices(soClient); + })(); + // This if else block will go away in favour of removing Home Tutorial Integration // Ideally we will directly register a custom integration and pass the configs // for cloud, onPrem and Serverless so that the actual component can take @@ -121,8 +129,7 @@ export class APMPlugin if (currentConfig.serverlessOnboarding && plugins.customIntegrations) { plugins.customIntegrations?.registerCustomIntegration(apmTutorialCustomIntegration); } else { - plugins.apmDataAccess - .getApmIndices() + apmIndicesPromise .then((apmIndices) => { plugins.home?.tutorials.registerTutorial( tutorialProvider({ diff --git a/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts b/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts index 4c57ef4a10e1..ea653b47145a 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/alerts/register_apm_rule_types.ts @@ -8,10 +8,7 @@ import type { AlertsLocatorParams } from '@kbn/observability-plugin/common'; import { LocatorPublic } from '@kbn/share-plugin/common'; import { IBasePath, Logger, SavedObjectsClientContract } from '@kbn/core/server'; -import { - PluginSetupContract as AlertingPluginSetupContract, - type IRuleTypeAlerts, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, IRuleTypeAlerts } from '@kbn/alerting-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; @@ -100,7 +97,7 @@ export const ApmRuleTypeAlertDefinition: IRuleTypeAlerts<ObservabilityApmAlert> }; export interface RegisterRuleDependencies { - alerting: AlertingPluginSetupContract; + alerting: AlertingServerSetup; basePath: IBasePath; getApmIndices: (soClient: SavedObjectsClientContract) => Promise<APMIndices>; apmConfig: APMConfig; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts b/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts index ce3e67baea1d..9230ca498369 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/alerts/test_utils/index.ts @@ -9,7 +9,7 @@ import { IBasePath, Logger } from '@kbn/core/server'; import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; -import { PluginSetupContract as AlertingPluginSetupContract } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { DEFAULT_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common'; import { APMConfig, APM_SERVER_FEATURE_ID } from '../../..'; @@ -28,7 +28,7 @@ export const createRuleTypeMocks = () => { registerType: ({ executor }) => { alertExecutor = executor; }, - } as AlertingPluginSetupContract; + } as AlertingServerSetup; const scheduleActions = jest.fn(); const getUuid = jest.fn(); diff --git a/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts b/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts index 4792223610bb..197b4259d3f0 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/apm_routes/register_apm_server_routes.ts @@ -11,6 +11,7 @@ import { Logger, KibanaRequest, KibanaResponseFactory, RouteRegistrar } from '@k import { errors } from '@elastic/elasticsearch'; import agent from 'elastic-apm-node'; import { + DefaultRouteCreateOptions, IoTsParamsObject, ServerRouteRepository, stripNullishRequestParameters, @@ -30,6 +31,7 @@ import type { APMIndices } from '@kbn/apm-data-access-plugin/server'; import { ApmFeatureFlags } from '../../../common/apm_feature_flags'; import type { APMCore, + APMRouteCreateOptions, MinimalApmPluginRequestHandlerContext, TelemetryUsageCounter, } from '../typings'; @@ -78,7 +80,11 @@ export function registerRoutes({ const router = core.setup.http.createRouter(); routes.forEach((route) => { - const { params, endpoint, options, handler } = route; + const { endpoint, handler, security } = route; + + const options = ('options' in route ? route.options : {}) as DefaultRouteCreateOptions & + APMRouteCreateOptions; + const params = 'params' in route ? route.params : undefined; const { method, pathname, version } = parseEndpoint(endpoint); @@ -109,7 +115,10 @@ export function registerRoutes({ ); const getApmIndices = async () => { - const apmIndices = await plugins.apmDataAccess.setup.getApmIndices(); + const coreContext = await context.core; + const apmIndices = await plugins.apmDataAccess.setup.getApmIndices( + coreContext.savedObjects.client + ); return apmIndices; }; @@ -215,6 +224,7 @@ export function registerRoutes({ path: pathname, options, validate: passThroughValidationObject, + security, }, wrappedHandler ); @@ -228,6 +238,7 @@ export function registerRoutes({ path: pathname, access: pathname.includes('/internal/apm') ? 'internal' : 'public', options, + security, }).addVersion( { version, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts b/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts index f28e3f9df857..84e51675233c 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/assistant_functions/get_observability_alert_details_context/index.ts @@ -38,7 +38,8 @@ export const getAlertDetailsContextHandler = ( return async (requestContext, query) => { const resources = { getApmIndices: async () => { - return resourcePlugins.apmDataAccess.setup.getApmIndices(); + const coreContext = await requestContext.core; + return resourcePlugins.apmDataAccess.setup.getApmIndices(coreContext.savedObjects.client); }, request: requestContext.request, params: { query: { _inspect: false } }, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts b/x-pack/plugins/observability_solution/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts index 91da19224d83..954086ee5308 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/errors/get_error_groups/get_error_sample_details.ts @@ -69,7 +69,6 @@ export async function getErrorSampleDetails({ const requiredFields = asMutableArray([ AGENT_NAME, PROCESSOR_EVENT, - TRACE_ID, TIMESTAMP_US, AT_TIMESTAMP, SERVICE_NAME, @@ -78,6 +77,7 @@ export async function getErrorSampleDetails({ ] as const); const optionalFields = asMutableArray([ + TRACE_ID, TRANSACTION_ID, SPAN_ID, AGENT_VERSION, @@ -131,7 +131,7 @@ export async function getErrorSampleDetails({ const errorFromFields = unflattenKnownApmEventFields(hit.fields, requiredFields); const transactionId = errorFromFields.transaction?.id ?? errorFromFields.span?.id; - const traceId = errorFromFields.trace.id; + const traceId = errorFromFields.trace?.id; let transaction: Transaction | undefined; if (transactionId && traceId) { diff --git a/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts b/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts index 9d00c50b4ab4..2237548f2d32 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/fleet/register_fleet_policy_callbacks.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { Logger, CoreStart } from '@kbn/core/server'; +import { Logger, CoreStart, SavedObjectsClientContract } from '@kbn/core/server'; import { FleetStartContract, PostPackagePolicyCreateCallback, @@ -22,6 +22,7 @@ import { SOURCE_MAP_API_KEY_PATH, } from './get_package_policy_decorators'; import { createInternalESClient } from '../../lib/helpers/create_es_client/create_internal_es_client'; +import { getInternalSavedObjectsClient } from '../../lib/helpers/get_internal_saved_objects_client'; import { APMRouteHandlerResources } from '../apm_routes/register_apm_server_routes'; export async function registerFleetPolicyCallbacks({ @@ -148,7 +149,7 @@ function onPackagePolicyCreateOrUpdate({ coreStart, }: { fleetPluginStart: FleetStartContract; - getApmIndices: () => Promise<APMIndices>; + getApmIndices: (soClient: SavedObjectsClientContract) => Promise<APMIndices>; coreStart: CoreStart; }): PutPackagePolicyUpdateCallback & PostPackagePolicyCreateCallback { return async (packagePolicy) => { @@ -157,7 +158,8 @@ function onPackagePolicyCreateOrUpdate({ } const { asInternalUser } = coreStart.elasticsearch.client; - const apmIndices = await getApmIndices(); + const savedObjectsClient = await getInternalSavedObjectsClient(coreStart); + const apmIndices = await getApmIndices(savedObjectsClient); const internalESClient = await createInternalESClient({ debug: false, diff --git a/x-pack/plugins/observability_solution/apm/server/routes/profiling/get_service_host_names.ts b/x-pack/plugins/observability_solution/apm/server/routes/profiling/get_service_correlation_fields.ts similarity index 51% rename from x-pack/plugins/observability_solution/apm/server/routes/profiling/get_service_host_names.ts rename to x-pack/plugins/observability_solution/apm/server/routes/profiling/get_service_correlation_fields.ts index 11fe248da563..2171b8e27de4 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/profiling/get_service_host_names.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/profiling/get_service_correlation_fields.ts @@ -5,13 +5,26 @@ * 2.0. */ import { rangeQuery } from '@kbn/observability-plugin/server'; -import { ApmServiceTransactionDocumentType } from '../../../common/document_type'; -import { HOST_HOSTNAME, SERVICE_NAME } from '../../../common/es_fields/apm'; -import { RollupInterval } from '../../../common/rollup'; +import type { ApmServiceTransactionDocumentType } from '../../../common/document_type'; +import { + CONTAINER_ID, + HOST_HOSTNAME, + HOST_NAME, + SERVICE_NAME, +} from '../../../common/es_fields/apm'; +import type { RollupInterval } from '../../../common/rollup'; import { environmentQuery } from '../../../common/utils/environment_query'; -import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; +import type { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client'; -export async function getServiceHostNames({ +const getBucketKeysAsString = ( + buckets?: Array<{ + doc_count: number; + key: string | number; + key_as_string?: string | undefined; + }> +) => buckets?.map((bucket) => bucket.key as string) || []; + +export async function getServiceCorrelationFields({ apmEventClient, serviceName, start, @@ -45,15 +58,36 @@ export async function getServiceHostNames({ }, }, aggs: { - hostNames: { + hostHostNames: { terms: { field: HOST_HOSTNAME, size: 500, }, }, + hostNames: { + terms: { + field: HOST_NAME, + size: 500, + }, + }, + containerIds: { + terms: { + field: CONTAINER_ID, + size: 500, + }, + }, }, }, }); - return response.aggregations?.hostNames.buckets.map((bucket) => bucket.key as string) || []; + const allHostNames = [ + ...getBucketKeysAsString(response.aggregations?.hostHostNames.buckets), + ...getBucketKeysAsString(response.aggregations?.hostNames.buckets), + ]; + const hostNames = new Set<string>(allHostNames); + + return { + hostNames: Array.from(hostNames), + containerIds: getBucketKeysAsString(response.aggregations?.containerIds.buckets), + }; } diff --git a/x-pack/plugins/observability_solution/apm/server/routes/profiling/hosts/route.ts b/x-pack/plugins/observability_solution/apm/server/routes/profiling/hosts/route.ts index 5a748ddf5e11..3ddd2782f108 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/profiling/hosts/route.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/profiling/hosts/route.ts @@ -8,7 +8,7 @@ import { toNumberRt } from '@kbn/io-ts-utils'; import type { BaseFlameGraph, TopNFunctions } from '@kbn/profiling-utils'; import * as t from 'io-ts'; -import { HOST_NAME } from '../../../../common/es_fields/apm'; +import { CONTAINER_ID, HOST_NAME } from '../../../../common/es_fields/apm'; import { mergeKueries, toKueryFilterFormat } from '../../../../common/utils/kuery_utils'; import { getApmEventClient } from '../../../lib/helpers/get_apm_event_client'; import { createApmServerRoute } from '../../apm_routes/create_apm_server_route'; @@ -20,7 +20,7 @@ import { } from '../../default_api_types'; import { fetchFlamegraph } from '../fetch_flamegraph'; import { fetchFunctions } from '../fetch_functions'; -import { getServiceHostNames } from '../get_service_host_names'; +import { getServiceCorrelationFields } from '../get_service_correlation_fields'; const profilingHostsFlamegraphRoute = createApmServerRoute({ endpoint: 'GET /internal/apm/services/{serviceName}/profiling/hosts/flamegraph', @@ -31,7 +31,9 @@ const profilingHostsFlamegraphRoute = createApmServerRoute({ options: { tags: ['access:apm'] }, handler: async ( resources - ): Promise<{ flamegraph: BaseFlameGraph; hostNames: string[] } | undefined> => { + ): Promise< + { flamegraph: BaseFlameGraph; hostNames: string[]; containerIds: string[] } | undefined + > => { const { context, plugins, params } = resources; const core = await context.core; const [esClient, apmEventClient, profilingDataAccessStart] = await Promise.all([ @@ -43,7 +45,7 @@ const profilingHostsFlamegraphRoute = createApmServerRoute({ const { start, end, environment, documentType, rollupInterval, kuery } = params.query; const { serviceName } = params.path; - const serviceHostNames = await getServiceHostNames({ + const { hostNames, containerIds } = await getServiceCorrelationFields({ apmEventClient, start, end, @@ -53,7 +55,7 @@ const profilingHostsFlamegraphRoute = createApmServerRoute({ rollupInterval, }); - if (!serviceHostNames.length) { + if (!hostNames.length && !containerIds.length) { return undefined; } const startSecs = start / 1000; @@ -65,10 +67,13 @@ const profilingHostsFlamegraphRoute = createApmServerRoute({ esClient: esClient.asCurrentUser, start: startSecs, end: endSecs, - kuery: mergeKueries([`(${toKueryFilterFormat(HOST_NAME, serviceHostNames)})`, kuery]), + kuery: + containerIds.length > 0 + ? mergeKueries([`(${toKueryFilterFormat(CONTAINER_ID, containerIds)})`, kuery]) + : mergeKueries([`(${toKueryFilterFormat(HOST_NAME, hostNames)})`, kuery]), }); - return { flamegraph, hostNames: serviceHostNames }; + return { flamegraph, hostNames, containerIds }; } return undefined; @@ -90,7 +95,9 @@ const profilingHostsFunctionsRoute = createApmServerRoute({ options: { tags: ['access:apm'] }, handler: async ( resources - ): Promise<{ functions: TopNFunctions; hostNames: string[] } | undefined> => { + ): Promise< + { functions: TopNFunctions; hostNames: string[]; containerIds: string[] } | undefined + > => { const { context, plugins, params } = resources; const core = await context.core; const [esClient, apmEventClient, profilingDataAccessStart] = await Promise.all([ @@ -103,7 +110,7 @@ const profilingHostsFunctionsRoute = createApmServerRoute({ params.query; const { serviceName } = params.path; - const serviceHostNames = await getServiceHostNames({ + const { hostNames, containerIds } = await getServiceCorrelationFields({ apmEventClient, start, end, @@ -113,7 +120,7 @@ const profilingHostsFunctionsRoute = createApmServerRoute({ rollupInterval, }); - if (!serviceHostNames.length) { + if (!hostNames.length && !containerIds.length) { return undefined; } @@ -128,10 +135,13 @@ const profilingHostsFunctionsRoute = createApmServerRoute({ endIndex, start: startSecs, end: endSecs, - kuery: mergeKueries([`(${toKueryFilterFormat(HOST_NAME, serviceHostNames)})`, kuery]), + kuery: + containerIds.length > 0 + ? mergeKueries([`(${toKueryFilterFormat(CONTAINER_ID, containerIds)})`, kuery]) + : mergeKueries([`(${toKueryFilterFormat(HOST_NAME, hostNames)})`, kuery]), }); - return { functions, hostNames: serviceHostNames }; + return { functions, hostNames, containerIds }; } return undefined; diff --git a/x-pack/plugins/observability_solution/apm/server/routes/typings.ts b/x-pack/plugins/observability_solution/apm/server/routes/typings.ts index f9ea085a11e6..de5aeb6031d1 100644 --- a/x-pack/plugins/observability_solution/apm/server/routes/typings.ts +++ b/x-pack/plugins/observability_solution/apm/server/routes/typings.ts @@ -9,7 +9,6 @@ import type { CoreSetup, CustomRequestHandlerContext, CoreStart, - RouteConfigOptions, IScopedClusterClient, IUiSettingsClient, SavedObjectsClientContract, @@ -17,14 +16,12 @@ import type { import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server'; import type { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; -import type { RulesClientApi } from '@kbn/alerting-plugin/server/types'; +import { RulesClientApi } from '@kbn/alerting-plugin/server/types'; export type ApmPluginRequestHandlerContext = CustomRequestHandlerContext<{ licensing: Pick<LicensingApiRequestHandlerContext, 'license' | 'featureUsage'>; alerting: { - // Pick<AlertingApiRequestHandlerContext, 'getRulesClient'> is a superset of this - // and incompatible with the start contract from the alerting plugin - getRulesClient: () => RulesClientApi; + getRulesClient: () => Promise<RulesClientApi>; }; rac: Pick<RacApiRequestHandlerContext, 'getAlertsClient'>; }>; @@ -48,21 +45,18 @@ export type MinimalApmPluginRequestHandlerContext = Omit< }; export interface APMRouteCreateOptions { - options: { - tags: Array< - | 'access:apm' - | 'access:apm_write' - | 'access:apm_settings_write' - | 'access:ml:canGetJobs' - | 'access:ml:canCreateJob' - | 'access:ml:canCloseJob' - | 'access:ai_assistant' - | 'oas-tag:APM agent keys' - | 'oas-tag:APM annotations' - >; - body?: { accepts: Array<'application/json' | 'multipart/form-data'> }; - disableTelemetry?: boolean; - } & RouteConfigOptions<any>; + tags: Array< + | 'access:apm' + | 'access:apm_write' + | 'access:apm_settings_write' + | 'access:ml:canGetJobs' + | 'access:ml:canCreateJob' + | 'access:ml:canCloseJob' + | 'access:ai_assistant' + | 'oas-tag:APM agent keys' + | 'oas-tag:APM annotations' + >; + disableTelemetry?: boolean; } export type TelemetryUsageCounter = ReturnType<UsageCollectionSetup['createUsageCounter']>; diff --git a/x-pack/plugins/observability_solution/apm/server/types.ts b/x-pack/plugins/observability_solution/apm/server/types.ts index 84e0d5462c43..e99860b9d441 100644 --- a/x-pack/plugins/observability_solution/apm/server/types.ts +++ b/x-pack/plugins/observability_solution/apm/server/types.ts @@ -24,7 +24,7 @@ import { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server' import { HomeServerPluginSetup, HomeServerPluginStart } from '@kbn/home-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { ActionsPlugin } from '@kbn/actions-plugin/server'; -import { AlertingPlugin } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { FeaturesPluginSetup, FeaturesPluginStart } from '@kbn/features-plugin/server'; import { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing-plugin/server'; @@ -78,7 +78,7 @@ export interface APMPluginSetupDependencies { observabilityAIAssistant?: ObservabilityAIAssistantServerSetup; // optional dependencies actions?: ActionsPlugin['setup']; - alerting?: AlertingPlugin['setup']; + alerting?: AlertingServerSetup; cloud?: CloudSetup; fleet?: FleetPluginSetup; home?: HomeServerPluginSetup; @@ -105,7 +105,7 @@ export interface APMPluginStartDependencies { observabilityAIAssistant?: ObservabilityAIAssistantServerStart; // optional dependencies actions?: ActionsPlugin['start']; - alerting?: AlertingPlugin['start']; + alerting?: AlertingServerStart; cloud?: undefined; fleet?: FleetPluginStart; home?: HomeServerPluginStart; diff --git a/x-pack/plugins/observability_solution/apm/tsconfig.json b/x-pack/plugins/observability_solution/apm/tsconfig.json index d3de1633dcad..b2fda13c3f76 100644 --- a/x-pack/plugins/observability_solution/apm/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm/tsconfig.json @@ -127,6 +127,8 @@ "@kbn/router-utils", "@kbn/react-hooks", "@kbn/alerting-comparators", + "@kbn/saved-search-component", + "@kbn/saved-search-plugin", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc index 9d80dcd71ce9..4eb0859691ba 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/apm_data_access/kibana.jsonc @@ -1,10 +1,7 @@ { "type": "plugin", "id": "@kbn/apm-data-access-plugin", - "owner": [ - "@elastic/obs-knowledge-team", - "@elastic/obs-ux-infra_services-team" - ], + "owner": ["@elastic/obs-ux-infra_services-team"], "group": "observability", "visibility": "private", "plugin": { @@ -18,7 +15,9 @@ "requiredPlugins": [ "data" ], - "optionalPlugins": [], + "optionalPlugins": [ + "security" + ], "requiredBundles": [] } } \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/index.ts b/x-pack/plugins/observability_solution/apm_data_access/server/index.ts index 7afaa656591c..6b6385ded4ce 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/index.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/index.ts @@ -91,6 +91,7 @@ export type { APMEventESSearchRequest, APMLogEventESSearchRequest, DocumentSourcesRequest, + ApmDataAccessPrivilegesCheck, HostNamesRequest, GetDocumentTypeParams, } from './types'; diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts b/x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts new file mode 100644 index 000000000000..6b8e734a10b4 --- /dev/null +++ b/x-pack/plugins/observability_solution/apm_data_access/server/lib/check_privileges.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaRequest } from '@kbn/core-http-server'; +import { SecurityPluginStart } from '@kbn/security-plugin-types-server'; +import { mapValues } from 'lodash'; +import { APMIndices } from '..'; + +export interface ApmDataAccessPrivilegesCheck { + request: KibanaRequest; + security?: SecurityPluginStart; + getApmIndices: () => Promise<APMIndices>; +} + +export async function checkPrivileges({ + request, + getApmIndices, + security, +}: ApmDataAccessPrivilegesCheck) { + const authorization = security?.authz; + if (!authorization) { + return true; + } + + const [apmIndices, checkPrivilegesFn] = await Promise.all([ + getApmIndices(), + authorization.checkPrivilegesDynamicallyWithRequest(request), + ]); + + const { hasAllRequested } = await checkPrivilegesFn({ + elasticsearch: { + cluster: [], + index: mapValues(apmIndices, () => ['read']), + }, + }); + + return hasAllRequested; +} diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts b/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts index 6bf684985583..680079d080c8 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/plugin.ts @@ -5,19 +5,32 @@ * 2.0. */ -import { PluginInitializerContext, CoreSetup, CoreStart, Plugin, Logger } from '@kbn/core/server'; +import { + PluginInitializerContext, + CoreSetup, + CoreStart, + Plugin, + SavedObjectsClientContract, + Logger, +} from '@kbn/core/server'; import { APMDataAccessConfig } from '.'; -import { ApmDataAccessPluginSetup, ApmDataAccessPluginStart } from './types'; +import { + ApmDataAccessPluginSetup, + ApmDataAccessPluginStart, + ApmDataAccessServerDependencies, +} from './types'; import { migrateLegacyAPMIndicesToSpaceAware } from './saved_objects/migrations/migrate_legacy_apm_indices_to_space_aware'; import { apmIndicesSavedObjectDefinition, getApmIndicesSavedObject, } from './saved_objects/apm_indices'; import { getServices } from './services/get_services'; +import { ApmDataAccessPrivilegesCheck, checkPrivileges } from './lib/check_privileges'; export class ApmDataAccessPlugin implements Plugin<ApmDataAccessPluginSetup, ApmDataAccessPluginStart> { + public server?: ApmDataAccessServerDependencies; public config: APMDataAccessConfig; public logger: Logger; @@ -26,34 +39,45 @@ export class ApmDataAccessPlugin this.logger = initContext.logger.get(); } + getApmIndices = async (savedObjectsClient: SavedObjectsClientContract) => { + const apmIndicesFromSavedObject = await getApmIndicesSavedObject(savedObjectsClient); + return { ...this.config.indices, ...apmIndicesFromSavedObject }; + }; + public setup(core: CoreSetup): ApmDataAccessPluginSetup { // register saved object core.savedObjects.registerType(apmIndicesSavedObjectDefinition); - const getApmIndices = async () => { - const [coreStart] = await core.getStartServices(); - const soClient = await coreStart.savedObjects.createInternalRepository(); - - const apmIndicesFromSavedObject = await getApmIndicesSavedObject(soClient); - return { ...this.config.indices, ...apmIndicesFromSavedObject }; - }; - // expose return { apmIndicesFromConfigFile: this.config.indices, - getApmIndices, + getApmIndices: this.getApmIndices, getServices, }; } - public start(core: CoreStart) { + public start(core: CoreStart, plugins: ApmDataAccessServerDependencies) { // TODO: remove in 9.0 migrateLegacyAPMIndicesToSpaceAware({ coreStart: core, logger: this.logger }).catch((e) => { this.logger.error('Failed to run migration making APM indices space aware'); this.logger.error(e); }); - return {}; + const getApmIndicesWithInternalUserFn = async () => { + const soClient = core.savedObjects.createInternalRepository(); + return this.getApmIndices(soClient); + }; + + const startServices = { + hasPrivileges: ({ request }: Pick<ApmDataAccessPrivilegesCheck, 'request'>) => + checkPrivileges({ + request, + getApmIndices: getApmIndicesWithInternalUserFn, + security: plugins.security, + }), + }; + + return { ...startServices }; } public stop() {} diff --git a/x-pack/plugins/observability_solution/apm_data_access/server/types.ts b/x-pack/plugins/observability_solution/apm_data_access/server/types.ts index 968590e780ee..f10c23c1fd99 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/server/types.ts +++ b/x-pack/plugins/observability_solution/apm_data_access/server/types.ts @@ -5,17 +5,28 @@ * 2.0. */ +import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; +import type { SecurityPluginStart } from '@kbn/security-plugin-types-server'; import type { APMIndices } from '.'; import { getServices } from './services/get_services'; +import type { ApmDataAccessPrivilegesCheck } from './lib/check_privileges'; export interface ApmDataAccessPluginSetup { apmIndicesFromConfigFile: APMIndices; - getApmIndices: () => Promise<APMIndices>; + getApmIndices: (soClient: SavedObjectsClientContract) => Promise<APMIndices>; getServices: typeof getServices; } -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ApmDataAccessPluginStart {} +export interface ApmDataAccessServerDependencies { + security?: SecurityPluginStart; +} + +export interface ApmDataAccessPluginStart { + hasPrivileges: (params: Pick<ApmDataAccessPrivilegesCheck, 'request'>) => Promise<boolean>; +} +export interface ApmDataAccessServerDependencies { + security?: SecurityPluginStart; +} export type ApmDataAccessServices = ReturnType<typeof getServices>; export type { ApmDataAccessServicesParams } from './services/get_services'; @@ -27,3 +38,4 @@ export type { APMEventESSearchRequest, APMLogEventESSearchRequest, } from './lib/helpers'; +export type { ApmDataAccessPrivilegesCheck }; diff --git a/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json b/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json index f7ac83af0922..d4c38fddf967 100644 --- a/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json +++ b/x-pack/plugins/observability_solution/apm_data_access/tsconfig.json @@ -9,6 +9,7 @@ "@kbn/config-schema", "@kbn/core", "@kbn/i18n", + "@kbn/core-saved-objects-api-server", "@kbn/data-plugin", "@kbn/inspector-plugin", "@kbn/observability-plugin", @@ -17,6 +18,8 @@ "@kbn/apm-types", "@kbn/core-http-server-mocks", "@kbn/apm-utils", + "@kbn/core-http-server", + "@kbn/security-plugin-types-server", "@kbn/utility-types", "@kbn/elastic-agent-utils", "@kbn/observability-utils-common" diff --git a/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts b/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts index 51a1421aec91..7220f9014b47 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/common/api_types.ts @@ -95,13 +95,24 @@ export const integrationRt = rt.intersection([ export type IntegrationType = rt.TypeOf<typeof integrationRt>; +export const checkAndLoadIntegrationResponseRt = rt.union([ + rt.type({ isIntegration: rt.literal(false), areAssetsAvailable: rt.boolean }), + rt.type({ + isIntegration: rt.literal(true), + areAssetsAvailable: rt.literal(true), + integration: integrationRt, + }), +]); + +export type CheckAndLoadIntegrationResponse = rt.TypeOf<typeof checkAndLoadIntegrationResponseRt>; + export const getIntegrationsResponseRt = rt.exact( rt.type({ integrations: rt.array(integrationRt), }) ); -export type IntegrationResponse = rt.TypeOf<typeof getIntegrationsResponseRt>; +export type IntegrationsResponse = rt.TypeOf<typeof getIntegrationsResponseRt>; export const degradedFieldRt = rt.type({ name: rt.string, diff --git a/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts b/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts index ce74552b581b..f6372e1dc61a 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/common/data_stream_details/types.ts @@ -5,9 +5,7 @@ * 2.0. */ -export interface GetDataStreamIntegrationParams { - integrationName: string; -} +import { Integration } from '../data_streams_stats/integration'; export interface AnalyzeDegradedFieldsParams { dataStream: string; @@ -19,3 +17,13 @@ export interface UpdateFieldLimitParams { dataStream: string; newFieldLimit: number; } + +export interface CheckAndLoadIntegrationParams { + dataStream: string; +} + +export interface IntegrationType { + isIntegration: boolean; + areAssetsAvailable: boolean; + integration?: Integration; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx index 1056713ac207..5dc8d6d36701 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/field_mapping_limit.tsx @@ -29,7 +29,11 @@ import { IncreaseFieldMappingLimit } from './increase_field_mapping_limit'; import { FieldLimitDocLink } from './field_limit_documentation_link'; import { MessageCallout } from './message_callout'; -export function FieldMappingLimit({ isIntegration }: { isIntegration: boolean }) { +export function FieldMappingLimit({ + areIntegrationAssetsAvailable, +}: { + areIntegrationAssetsAvailable: boolean; +}) { const accordionId = useGeneratedHtmlId({ prefix: increaseFieldMappingLimitTitle, }); @@ -66,7 +70,7 @@ export function FieldMappingLimit({ isIntegration }: { isIntegration: boolean }) </ul> </EuiText> <EuiHorizontalRule margin="s" /> - {isIntegration && ( + {areIntegrationAssetsAvailable && ( <> <IncreaseFieldMappingLimit totalFieldLimit={degradedFieldAnalysis?.totalFieldLimit ?? 0} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/increase_field_mapping_limit.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/increase_field_mapping_limit.tsx index 158a5e5eba46..852e19dd19d0 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/increase_field_mapping_limit.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/field_limit/increase_field_mapping_limit.tsx @@ -69,7 +69,7 @@ export function IncreaseFieldMappingLimit({ totalFieldLimit }: { totalFieldLimit <EuiFlexItem grow={false}> <EuiFormRow hasEmptyLabelSpace> <EuiButton - data-test-subj="datasetQualityIncreaseFieldMappingLimitButtonButton" + data-test-subj="datasetQualityIncreaseFieldMappingLimitButton" disabled={isInvalid} onClick={() => updateNewFieldLimit(newFieldLimit)} isLoading={isMitigationInProgress} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx index 34f39f25a67e..d9ca2128521f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/index.tsx @@ -15,7 +15,7 @@ import { PossibleMitigationTitle } from './title'; export function PossibleMitigations() { const { degradedFieldAnalysis, isAnalysisInProgress } = useDegradedFields(); const { integrationDetails } = useDatasetQualityDetailsState(); - const isIntegration = Boolean(integrationDetails?.integration); + const areIntegrationAssetsAvailable = !!integrationDetails?.integration?.areAssetsAvailable; return ( !isAnalysisInProgress && ( @@ -24,7 +24,7 @@ export function PossibleMitigations() { <EuiSpacer size="m" /> {degradedFieldAnalysis?.isFieldLimitIssue && ( <> - <FieldMappingLimit isIntegration={isIntegration} /> + <FieldMappingLimit areIntegrationAssetsAvailable={areIntegrationAssetsAvailable} /> <EuiSpacer size="m" /> </> )} diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx index 54bbe91f2f2e..e8768d34cdcc 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/component_template_link.tsx @@ -13,7 +13,11 @@ import { useDatasetQualityDetailsState } from '../../../../../hooks'; import { getComponentTemplatePrefixFromIndexTemplate } from '../../../../../../common/utils/component_template_name'; import { otherMitigationsCustomComponentTemplate } from '../../../../../../common/translations'; -export function CreateEditComponentTemplateLink({ isIntegration }: { isIntegration: boolean }) { +export function CreateEditComponentTemplateLink({ + areIntegrationAssetsAvailable, +}: { + areIntegrationAssetsAvailable: boolean; +}) { const { services: { application, @@ -54,7 +58,7 @@ export function CreateEditComponentTemplateLink({ isIntegration }: { isIntegrati name, ]); - const templateUrl = isIntegration ? componentTemplatePath : indexTemplatePath; + const templateUrl = areIntegrationAssetsAvailable ? componentTemplatePath : indexTemplatePath; const onClickHandler = useCallback(async () => { const options = { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx index f931f3461fb5..34cdbe4b9b83 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/index.tsx @@ -13,27 +13,27 @@ import { CreateEditPipelineLink } from './pipeline_link'; import { otherMitigationsLoadingAriaText } from '../../../../../../common/translations'; export function ManualMitigations() { - const { integrationDetails, loadingState, dataStreamSettings } = useDatasetQualityDetailsState(); - const isIntegrationPresentInSettings = dataStreamSettings?.integration; - const isIntegration = !!integrationDetails?.integration; - const { dataStreamSettingsLoading, integrationDetailsLoadings } = loadingState; - - const hasIntegrationCheckCompleted = - !dataStreamSettingsLoading && - ((isIntegrationPresentInSettings && !integrationDetailsLoadings) || - !isIntegrationPresentInSettings); + const { + integrationDetails, + loadingState: { integrationDetailsLoaded }, + } = useDatasetQualityDetailsState(); + const areIntegrationAssetsAvailable = !!integrationDetails?.integration?.areAssetsAvailable; return ( <EuiSkeletonRectangle - isLoading={!hasIntegrationCheckCompleted} + isLoading={!integrationDetailsLoaded} contentAriaLabel={otherMitigationsLoadingAriaText} width="100%" height={300} borderRadius="none" + data-test-subj="datasetQualityDetailsFlyoutManualMitigationsLoading" + className="datasetQualityDetailsFlyoutManualMitigationsLoading" > - <CreateEditComponentTemplateLink isIntegration={isIntegration} /> + <CreateEditComponentTemplateLink + areIntegrationAssetsAvailable={areIntegrationAssetsAvailable} + /> <EuiSpacer size="s" /> - <CreateEditPipelineLink isIntegration={isIntegration} /> + <CreateEditPipelineLink areIntegrationAssetsAvailable={areIntegrationAssetsAvailable} /> </EuiSkeletonRectangle> ); } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx index 6179a3ed0736..f4084c52e2ef 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/degraded_field_flyout/possible_mitigations/manual/pipeline_link.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; import { @@ -34,7 +34,11 @@ const AccordionTitle = () => ( </EuiTitle> ); -export function CreateEditPipelineLink({ isIntegration }: { isIntegration: boolean }) { +export function CreateEditPipelineLink({ + areIntegrationAssetsAvailable, +}: { + areIntegrationAssetsAvailable: boolean; +}) { const { services: { share: { @@ -50,10 +54,7 @@ export function CreateEditPipelineLink({ isIntegration }: { isIntegration: boole const { datasetDetails } = useDatasetQualityDetailsState(); const { type, name } = datasetDetails; - const pipelineName = useMemo( - () => (isIntegration ? `${type}-${name}@custom` : `${type}@custom`), - [isIntegration, type, name] - ); + const pipelineName = areIntegrationAssetsAvailable ? `${type}-${name}@custom` : `${type}@custom`; const ingestPipelineLocator = locators.get('INGEST_PIPELINES_APP_LOCATOR'); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx index 17032d7866d0..8bbc9aa08542 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/details/dataset_summary.tsx @@ -7,7 +7,7 @@ import React, { Fragment } from 'react'; import { ES_FIELD_TYPES, KBN_FIELD_TYPES } from '@kbn/field-types'; -import { EuiBadge, EuiFlexGroup, EuiPanel, EuiText } from '@elastic/eui'; +import { EuiBadge, EuiFlexGroup, EuiPanel, EuiSkeletonRectangle, EuiText } from '@elastic/eui'; import { css } from '@emotion/react'; import { IntegrationActionsMenu } from './integration_actions_menu'; import { @@ -29,7 +29,8 @@ export function DatasetSummary() { const { dataStreamDetailsLoading, dataStreamSettingsLoading, - integrationDetailsLoadings, + integrationDetailsLoading, + integrationDetailsLoaded, integrationDashboardsLoading, } = loadingState; const formattedLastActivity = dataStreamDetails?.lastActivity @@ -39,12 +40,19 @@ export function DatasetSummary() { ? dataFormatter.convert(dataStreamSettings.createdOn) : '-'; - return ( + return !integrationDetailsLoaded ? ( + <EuiSkeletonRectangle + width="100%" + height="200px" + data-test-subj="datasetQualityDetailsDetailsSectionLoading" + className="datasetQualityDetailsDetailsSectionLoading" + /> + ) : ( <EuiPanel hasBorder={false} hasShadow={false} paddingSize="none"> <Fragment> <FieldsList fields={[ - ...(integrationDetails?.integration + ...(integrationDetails?.integration?.integration ? [ { fieldTitle: integrationNameText, @@ -56,24 +64,28 @@ export function DatasetSummary() { `} > <EuiFlexGroup gutterSize="xs" alignItems="center"> - <IntegrationIcon integration={integrationDetails.integration} /> - <EuiText size="s">{integrationDetails.integration?.name}</EuiText> + <IntegrationIcon + integration={integrationDetails.integration.integration} + /> + <EuiText size="s"> + {integrationDetails.integration.integration?.name} + </EuiText> </EuiFlexGroup> </EuiBadge> ), actionsMenu: ( <IntegrationActionsMenu - integration={integrationDetails.integration} + integration={integrationDetails.integration.integration} dashboards={integrationDetails.dashboard} dashboardsLoading={integrationDashboardsLoading} /> ), - isLoading: integrationDetailsLoadings, + isLoading: integrationDetailsLoading, }, { fieldTitle: integrationVersionText, - fieldValue: integrationDetails.integration?.version, - isLoading: integrationDetailsLoadings, + fieldValue: integrationDetails.integration.integration?.version, + isLoading: integrationDetailsLoading, }, ] : []), diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx index e45253b6405c..60a26d428573 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/header.tsx @@ -44,7 +44,8 @@ export function Header() { sendTelemetry, }); - const pageTitle = integrationDetails?.integration?.datasets?.[datasetDetails.name] ?? title; + const pageTitle = + integrationDetails?.integration?.integration?.datasets?.[datasetDetails.name] ?? title; return !loadingState.integrationDetailsLoaded ? ( <EuiSkeletonTitle @@ -67,7 +68,7 @@ export function Header() { border-radius: ${euiTheme.size.xxs}; `} > - <IntegrationIcon integration={integrationDetails?.integration} /> + <IntegrationIcon integration={integrationDetails?.integration?.integration} /> </div> </EuiFlexGroup> <p> diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx index 05de567a6dab..e25b1da9540f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx +++ b/x-pack/plugins/observability_solution/dataset_quality/public/components/dataset_quality_details/overview/document_trends/degraded_docs/index.tsx @@ -79,6 +79,7 @@ export default function DegradedDocs({ lastReloadTime }: { lastReloadTime: numbe dataStreamStat: datasetDetails, timeRangeConfig: timeRange, query: { language: 'kuery', query: `${_IGNORED}: *` }, + breakdownField: breakdownDataViewField?.name, sendTelemetry, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts index f613d3af7fdc..4d2d83841927 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_details_telemetry.ts @@ -42,7 +42,7 @@ export function useDatasetDetailsTelemetry() { breakdownField, isNonAggregatable, isBreakdownFieldEcs, - integration: integrationDetails.integration, + integration: integrationDetails.integration?.integration, }); } @@ -57,7 +57,7 @@ export function useDatasetDetailsTelemetry() { breakdownField, isNonAggregatable, isBreakdownFieldEcs, - integrationDetails.integration, + integrationDetails.integration?.integration, ]); const startTracking = useCallback(() => { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts index edd16652374a..cfea77ff4fa3 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_dataset_quality_details_state.ts @@ -51,7 +51,9 @@ export const useDatasetQualityDetailsState = () => { ); const dataStreamSettings = useSelector(service, (state) => - state.matches('initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields') + state.matches('initializing.dataStreamSettings.fetchingDataStreamDegradedFields') || + state.matches('initializing.dataStreamSettings.doneFetchingDegradedFields') || + state.matches('initializing.dataStreamSettings.errorFetchingDegradedFields') ? state.context.dataStreamSettings : undefined ); @@ -59,15 +61,17 @@ export const useDatasetQualityDetailsState = () => { const integrationDetails = { integration: useSelector(service, (state) => state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.done' - ) + 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' + ) || + state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards' + ) || + state.matches('initializing.checkAndLoadIntegrationAndDashboards.done') ? state.context.integration : undefined ), dashboard: useSelector(service, (state) => - state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.done' - ) + state.matches('initializing.checkAndLoadIntegrationAndDashboards.done') ? state.context.integrationDashboards : undefined ), @@ -77,7 +81,7 @@ export const useDatasetQualityDetailsState = () => { service, (state) => !state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.unauthorized' + 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards' ) ); @@ -106,14 +110,19 @@ export const useDatasetQualityDetailsState = () => { dataStreamSettingsLoading: state.matches( 'initializing.dataStreamSettings.fetchingDataStreamSettings' ), - integrationDetailsLoadings: state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.fetching' - ), - integrationDetailsLoaded: state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.done' + integrationDetailsLoading: state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.checkingAndLoadingIntegration' ), + integrationDetailsLoaded: + state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' + ) || + state.matches( + 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards' + ) || + state.matches('initializing.checkAndLoadIntegrationAndDashboards.done'), integrationDashboardsLoading: state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.fetching' + 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' ), })); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts index 90779613f0c0..d499535df166 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_docs_chart.ts @@ -16,29 +16,12 @@ import { useCreateDataView } from './use_create_dataview'; import { useKibanaContextForPlugin } from '../utils'; import { useDatasetQualityDetailsState } from './use_dataset_quality_details_state'; import { getLensAttributes } from '../components/dataset_quality_details/overview/document_trends/degraded_docs/lens_attributes'; -import { useRedirectLink } from './use_redirect_link'; import { useDatasetDetailsTelemetry } from './use_dataset_details_telemetry'; -import { useDatasetDetailsRedirectLinkTelemetry } from './use_redirect_link_telemetry'; - -const exploreDataInLogsExplorerText = i18n.translate( - 'xpack.datasetQuality.details.chartExploreDataInLogsExplorerText', - { - defaultMessage: 'Explore data in Logs Explorer', - } -); - -const exploreDataInDiscoverText = i18n.translate( - 'xpack.datasetQuality.details.chartExploreDataInDiscoverText', - { - defaultMessage: 'Explore data in Discover', - } -); const openInLensText = i18n.translate('xpack.datasetQuality.details.chartOpenInLensText', { defaultMessage: 'Open in Lens', }); -const ACTION_EXPLORE_IN_LOGS_EXPLORER = 'ACTION_EXPLORE_IN_LOGS_EXPLORER'; const ACTION_OPEN_IN_LENS = 'ACTION_OPEN_IN_LENS'; export const useDegradedDocsChart = () => { @@ -98,7 +81,8 @@ export const useDegradedDocsChart = () => { useEffect(() => { const dataStreamName = dataStream ?? DEFAULT_LOGS_DATA_VIEW; const datasetTitle = - integrationDetails?.integration?.datasets?.[datasetDetails.name] ?? datasetDetails.name; + integrationDetails?.integration?.integration?.datasets?.[datasetDetails.name] ?? + datasetDetails.name; const lensAttributes = getLensAttributes({ color: euiTheme.colors.danger, @@ -112,7 +96,7 @@ export const useDegradedDocsChart = () => { euiTheme.colors.danger, setAttributes, dataStream, - integrationDetails?.integration?.datasets, + integrationDetails?.integration?.integration?.datasets, datasetDetails.name, ]); @@ -154,45 +138,7 @@ export const useDegradedDocsChart = () => { }; }, [openInLensCallback]); - const { sendTelemetry } = useDatasetDetailsRedirectLinkTelemetry({ - query: { language: 'kuery', query: '_ignored:*' }, - navigationSource: navigationSources.Chart, - }); - - const redirectLinkProps = useRedirectLink({ - dataStreamStat: datasetDetails, - query: { language: 'kuery', query: '_ignored:*' }, - timeRangeConfig: timeRange, - breakdownField: breakdownDataViewField?.name, - sendTelemetry, - }); - - const getOpenInLogsExplorerAction = useMemo(() => { - return { - id: ACTION_EXPLORE_IN_LOGS_EXPLORER, - type: 'link', - getDisplayName(): string { - return redirectLinkProps?.isLogsExplorerAvailable - ? exploreDataInLogsExplorerText - : exploreDataInDiscoverText; - }, - getHref: async () => { - return redirectLinkProps.linkProps.href; - }, - getIconType(): string | undefined { - return 'visTable'; - }, - async isCompatible(): Promise<boolean> { - return true; - }, - async execute(): Promise<void> { - return redirectLinkProps.navigate(); - }, - order: 18, - }; - }, [redirectLinkProps]); - - const extraActions: Action[] = [getOpenInLensAction, getOpenInLogsExplorerAction]; + const extraActions: Action[] = [getOpenInLensAction]; const breakdown = useMemo(() => { return { diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts index 49ceb50abc3c..47b03074fe17 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_degraded_fields.ts @@ -77,10 +77,11 @@ export function useDegradedFields() { return renderedItems.find((item) => item.name === expandedDegradedField); }, [expandedDegradedField, renderedItems]); - const isDegradedFieldsLoading = useSelector(service, (state) => - state.matches( - 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.fetching' - ) + const isDegradedFieldsLoading = useSelector( + service, + (state) => + state.matches('initializing.dataStreamSettings.fetchingDataStreamSettings') || + state.matches('initializing.dataStreamSettings.fetchingDataStreamDegradedFields') ); const closeDegradedFieldFlyout = useCallback( diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts index 014d9f578eb6..8b8b92404d8d 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/hooks/use_summary_panel.ts @@ -14,8 +14,12 @@ import { filterInactiveDatasets } from '../utils'; const useSummaryPanel = () => { const { service } = useDatasetQualityContext(); - const { filteredItems, canUserMonitorDataset, canUserMonitorAnyDataStream, loading } = - useDatasetQualityTable(); + const { + filteredItems, + canUserMonitorDataset, + canUserMonitorAnyDataStream, + loading: isTableLoading, + } = useDatasetQualityTable(); const { timeRange } = useSelector(service, (state) => state.context.filters); @@ -27,9 +31,10 @@ const useSummaryPanel = () => { percentages: filteredItems.map((item) => item.degradedDocs.percentage), }; - const isDatasetsQualityLoading = useSelector(service, (state) => + const isDegradedDocsLoading = useSelector(service, (state) => state.matches('stats.degradedDocs.fetching') ); + const isDatasetsQualityLoading = isDegradedDocsLoading || isTableLoading; /* User Authorization @@ -38,7 +43,7 @@ const useSummaryPanel = () => { (item) => item.userPrivileges?.canMonitor ?? true ); - const isUserAuthorizedForDataset = !loading + const isUserAuthorizedForDataset = !isTableLoading ? canUserMonitorDataset && canUserMonitorAnyDataStream && canUserMonitorAllFilteredDataStreams : true; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts index 827cd4b0a1e4..7279bed2e185 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/data_stream_details_client.ts @@ -8,6 +8,8 @@ import { HttpStart } from '@kbn/core/public'; import { decodeOrThrow } from '@kbn/io-ts-utils'; import { + CheckAndLoadIntegrationResponse, + checkAndLoadIntegrationResponseRt, DataStreamRolloverResponse, dataStreamRolloverResponseRt, DegradedFieldAnalysis, @@ -17,10 +19,8 @@ import { getDataStreamDegradedFieldsResponseRt, getDataStreamsDetailsResponseRt, getDataStreamsSettingsResponseRt, - getIntegrationsResponseRt, IntegrationDashboardsResponse, integrationDashboardsRT, - IntegrationResponse, UpdateFieldLimitResponse, updateFieldLimitResponseRt, } from '../../../common/api_types'; @@ -40,7 +40,7 @@ import { IDataStreamDetailsClient } from './types'; import { Integration } from '../../../common/data_streams_stats/integration'; import { AnalyzeDegradedFieldsParams, - GetDataStreamIntegrationParams, + CheckAndLoadIntegrationParams, UpdateFieldLimitParams, } from '../../../common/data_stream_details/types'; import { DatasetQualityError } from '../../../common/errors'; @@ -139,43 +139,48 @@ export class DataStreamDetailsClient implements IDataStreamDetailsClient { )(response); } - public async getIntegrationDashboards({ integration }: GetIntegrationDashboardsParams) { + public async checkAndLoadIntegration({ dataStream }: CheckAndLoadIntegrationParams) { const response = await this.http - .get<IntegrationDashboardsResponse>( - `/internal/dataset_quality/integrations/${integration}/dashboards` + .get<CheckAndLoadIntegrationResponse>( + `/internal/dataset_quality/data_streams/${dataStream}/integration/check` ) .catch((error) => { - throw new DatasetQualityError(`Failed to fetch integration dashboards": ${error}`, error); + throw new DatasetQualityError( + `Failed to check if data stream belongs to an integration": ${error}`, + error + ); }); - const { dashboards } = decodeOrThrow( - integrationDashboardsRT, + const decodedResponse = decodeOrThrow( + checkAndLoadIntegrationResponseRt, (message: string) => - new DatasetQualityError(`Failed to decode integration dashboards response: ${message}"`) + new DatasetQualityError(`Failed to decode integration check response: ${message}"`) )(response); - return dashboards; + return { + ...decodedResponse, + integration: decodedResponse.isIntegration + ? Integration.create(decodedResponse.integration) + : undefined, + }; } - public async getDataStreamIntegration( - params: GetDataStreamIntegrationParams - ): Promise<Integration | undefined> { - const { integrationName } = params; + public async getIntegrationDashboards({ integration }: GetIntegrationDashboardsParams) { const response = await this.http - .get<IntegrationResponse>('/internal/dataset_quality/integrations') + .get<IntegrationDashboardsResponse>( + `/internal/dataset_quality/integrations/${integration}/dashboards` + ) .catch((error) => { - throw new DatasetQualityError(`Failed to fetch integrations: ${error}`, error); + throw new DatasetQualityError(`Failed to fetch integration dashboards": ${error}`, error); }); - const { integrations } = decodeOrThrow( - getIntegrationsResponseRt, + const { dashboards } = decodeOrThrow( + integrationDashboardsRT, (message: string) => - new DatasetQualityError(`Failed to decode integrations response: ${message}`) + new DatasetQualityError(`Failed to decode integration dashboards response: ${message}"`) )(response); - const integration = integrations.find((i) => i.name === integrationName); - - if (integration) return Integration.create(integration); + return dashboards; } public async analyzeDegradedField({ diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts index 6eac8bd73284..f38c68a68bff 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_stream_details/types.ts @@ -6,7 +6,6 @@ */ import { HttpStart } from '@kbn/core/public'; -import { Integration } from '../../../common/data_streams_stats/integration'; import { GetDataStreamSettingsParams, DataStreamSettings, @@ -19,7 +18,8 @@ import { } from '../../../common/data_streams_stats'; import { AnalyzeDegradedFieldsParams, - GetDataStreamIntegrationParams, + IntegrationType, + CheckAndLoadIntegrationParams, UpdateFieldLimitParams, } from '../../../common/data_stream_details/types'; import { @@ -49,10 +49,8 @@ export interface IDataStreamDetailsClient { getDataStreamDegradedFieldValues( params: GetDataStreamDegradedFieldValuesPathParams ): Promise<DegradedFieldValues>; + checkAndLoadIntegration(params: CheckAndLoadIntegrationParams): Promise<IntegrationType>; getIntegrationDashboards(params: GetIntegrationDashboardsParams): Promise<Dashboard[]>; - getDataStreamIntegration( - params: GetDataStreamIntegrationParams - ): Promise<Integration | undefined>; analyzeDegradedField(params: AnalyzeDegradedFieldsParams): Promise<DegradedFieldAnalysis>; setNewFieldLimit(params: UpdateFieldLimitParams): Promise<UpdateFieldLimitResponse>; rolloverDataStream(params: { dataStream: string }): Promise<DataStreamRolloverResponse>; diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts index 8e218819315b..5e4790309a07 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/services/data_streams_stats/data_streams_stats_client.ts @@ -17,7 +17,7 @@ import { getDataStreamTotalDocsResponseRt, getIntegrationsResponseRt, getNonAggregatableDatasetsRt, - IntegrationResponse, + IntegrationsResponse, NonAggregatableDatasets, } from '../../../common/api_types'; import { @@ -132,7 +132,7 @@ export class DataStreamsStatsClient implements IDataStreamsStatsClient { public async getIntegrations(): Promise<Integration[]> { const response = await this.http - .get<IntegrationResponse>('/internal/dataset_quality/integrations') + .get<IntegrationsResponse>('/internal/dataset_quality/integrations') .catch((error) => { throw new DatasetQualityError(`Failed to fetch integrations: ${error}`, error); }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts index f5fdd063492a..fbd2dd1dc191 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/notifications.ts @@ -44,17 +44,10 @@ export const fetchIntegrationDashboardsFailedNotifier = (toasts: IToasts, error: }); }; -export const fetchDataStreamIntegrationFailedNotifier = ( - toasts: IToasts, - error: Error, - integrationName?: string -) => { +export const fetchDataStreamIntegrationFailedNotifier = (toasts: IToasts, error: Error) => { toasts.addDanger({ title: i18n.translate('xpack.datasetQuality.details.fetchIntegrationsFailed', { - defaultMessage: "We couldn't get {integrationName} integration info.", - values: { - integrationName, - }, + defaultMessage: "We couldn't get integration info.", }), text: error.message, }); diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts index 8ac65a7dca4a..363919b35f65 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/state_machine.ts @@ -28,6 +28,8 @@ import { UpdateFieldLimitResponse, } from '../../../common/api_types'; import { fetchNonAggregatableDatasetsFailedNotifier } from '../common/notifications'; + +import { IntegrationType } from '../../../common/data_stream_details'; import { fetchDataStreamDetailsFailedNotifier, assertBreakdownFieldEcsFailedNotifier, @@ -37,7 +39,6 @@ import { updateFieldLimitFailedNotifier, rolloverDataStreamFailedNotifier, } from './notifications'; -import { Integration } from '../../../common/data_streams_stats/integration'; export const createPureDatasetQualityDetailsControllerStateMachine = ( initialContext: DatasetQualityDetailsControllerContext @@ -151,7 +152,7 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( invoke: { src: 'loadDataStreamSettings', onDone: { - target: 'loadingIntegrationsAndDegradedFields', + target: 'fetchingDataStreamDegradedFields', actions: ['storeDataStreamSettings'], }, onError: [ @@ -160,111 +161,49 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( cond: 'isIndexNotFoundError', }, { - target: 'done', + target: 'errorFetchingDataStreamSettings', actions: ['notifyFetchDataStreamSettingsFailed'], }, ], }, }, - loadingIntegrationsAndDegradedFields: { - type: 'parallel', - states: { - dataStreamDegradedFields: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDegradedFields', - onDone: { - target: 'done', - actions: ['storeDegradedFields', 'raiseDegradedFieldsLoaded'], - }, - onError: [ - { - target: '#DatasetQualityDetailsController.indexNotFound', - cond: 'isIndexNotFoundError', - }, - { - target: 'done', - }, - ], - }, - }, - done: { - on: { - UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA: { - target: 'done', - actions: ['storeDegradedFieldTableOptions'], - }, - OPEN_DEGRADED_FIELD_FLYOUT: { - target: - '#DatasetQualityDetailsController.initializing.degradedFieldFlyout.open', - actions: [ - 'storeExpandedDegradedField', - 'resetFieldLimitServerResponse', - ], - }, - TOGGLE_CURRENT_QUALITY_ISSUES: { - target: 'fetching', - actions: ['toggleCurrentQualityIssues'], - }, - }, - }, - }, + errorFetchingDataStreamSettings: {}, + fetchingDataStreamDegradedFields: { + invoke: { + src: 'loadDegradedFields', + onDone: { + target: 'doneFetchingDegradedFields', + actions: ['storeDegradedFields', 'raiseDegradedFieldsLoaded'], }, - integrationDetails: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadDataStreamIntegration', - onDone: { - target: 'done', - actions: ['storeDataStreamIntegration'], - }, - onError: { - target: 'done', - actions: ['notifyFetchDatasetIntegrationsFailed'], - }, - }, - }, - done: {}, + onError: [ + { + target: '#DatasetQualityDetailsController.indexNotFound', + cond: 'isIndexNotFoundError', }, - }, - integrationDashboards: { - initial: 'fetching', - states: { - fetching: { - invoke: { - src: 'loadIntegrationDashboards', - onDone: { - target: 'done', - actions: ['storeIntegrationDashboards'], - }, - onError: [ - { - target: 'unauthorized', - cond: 'checkIfActionForbidden', - }, - { - target: 'done', - actions: ['notifyFetchIntegrationDashboardsFailed'], - }, - ], - }, - }, - done: {}, - unauthorized: { - type: 'final', - }, + { + target: 'errorFetchingDegradedFields', }, - }, + ], }, - onDone: { - target: 'done', + }, + doneFetchingDegradedFields: { + on: { + UPDATE_DEGRADED_FIELDS_TABLE_CRITERIA: { + target: 'doneFetchingDegradedFields', + actions: ['storeDegradedFieldTableOptions'], + }, + OPEN_DEGRADED_FIELD_FLYOUT: { + target: + '#DatasetQualityDetailsController.initializing.degradedFieldFlyout.open', + actions: ['storeExpandedDegradedField', 'resetFieldLimitServerResponse'], + }, + TOGGLE_CURRENT_QUALITY_ISSUES: { + target: 'fetchingDataStreamDegradedFields', + actions: ['toggleCurrentQualityIssues'], + }, }, }, - done: {}, + errorFetchingDegradedFields: {}, }, on: { UPDATE_TIME_RANGE: { @@ -272,6 +211,54 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( }, }, }, + checkAndLoadIntegrationAndDashboards: { + initial: 'checkingAndLoadingIntegration', + states: { + checkingAndLoadingIntegration: { + invoke: { + src: 'checkAndLoadIntegration', + onDone: [ + { + target: 'loadingIntegrationDashboards', + actions: 'storeDataStreamIntegration', + cond: 'isDataStreamIsPartOfIntegration', + }, + { + actions: 'storeDataStreamIntegration', + target: 'done', + }, + ], + onError: { + target: 'done', + actions: ['notifyFetchDatasetIntegrationsFailed'], + }, + }, + }, + loadingIntegrationDashboards: { + invoke: { + src: 'loadIntegrationDashboards', + onDone: { + target: 'done', + actions: ['storeIntegrationDashboards'], + }, + onError: [ + { + target: 'unauthorizedToLoadDashboards', + cond: 'checkIfActionForbidden', + }, + { + target: 'done', + actions: ['notifyFetchIntegrationDashboardsFailed'], + }, + ], + }, + }, + unauthorizedToLoadDashboards: { + type: 'final', + }, + done: {}, + }, + }, degradedFieldFlyout: { initial: 'pending', states: { @@ -522,7 +509,7 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( } : {}; }), - storeDataStreamIntegration: assign((context, event: DoneInvokeEvent<Integration>) => { + storeDataStreamIntegration: assign((context, event: DoneInvokeEvent<IntegrationType>) => { return 'data' in event ? { integration: event.data, @@ -602,6 +589,14 @@ export const createPureDatasetQualityDetailsControllerStateMachine = ( !event.data.isLatestBackingIndexUpdated ); }, + isDataStreamIsPartOfIntegration: (_, event) => { + return ( + 'data' in event && + typeof event.data === 'object' && + 'isIntegration' in event.data && + event.data.isIntegration + ); + }, }, } ); @@ -634,9 +629,7 @@ export const createDatasetQualityDetailsControllerStateMachine = ({ notifyFetchIntegrationDashboardsFailed: (_context, event: DoneInvokeEvent<Error>) => fetchIntegrationDashboardsFailedNotifier(toasts, event.data), notifyFetchDatasetIntegrationsFailed: (context, event: DoneInvokeEvent<Error>) => { - const integrationName = - 'dataStreamSettings' in context ? context.dataStreamSettings?.integration : undefined; - return fetchDataStreamIntegrationFailedNotifier(toasts, event.data, integrationName); + return fetchDataStreamIntegrationFailedNotifier(toasts, event.data); }, notifySaveNewFieldLimitError: (_context, event: DoneInvokeEvent<Error>) => updateFieldLimitFailedNotifier(toasts, event.data), @@ -735,18 +728,15 @@ export const createDatasetQualityDetailsControllerStateMachine = ({ dataStream: context.dataStream, }); }, - loadDataStreamIntegration: (context) => { - if ('dataStreamSettings' in context && context.dataStreamSettings?.integration) { - return dataStreamDetailsClient.getDataStreamIntegration({ - integrationName: context.dataStreamSettings.integration, - }); - } - return Promise.resolve(); + checkAndLoadIntegration: (context) => { + return dataStreamDetailsClient.checkAndLoadIntegration({ + dataStream: context.dataStream, + }); }, loadIntegrationDashboards: (context) => { - if ('dataStreamSettings' in context && context.dataStreamSettings?.integration) { + if ('integration' in context && context.integration && context.integration.integration) { return dataStreamDetailsClient.getIntegrationDashboards({ - integration: context.dataStreamSettings.integration, + integration: context.integration.integration.name, }); } diff --git a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts index cdebcfbe53d8..d33e5c4f0415 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/public/state_machines/dataset_quality_details_controller/types.ts @@ -20,7 +20,7 @@ import { UpdateFieldLimitResponse, } from '../../../common/api_types'; import { TableCriteria, TimeRangeConfig } from '../../../common/types'; -import { Integration } from '../../../common/data_streams_stats/integration'; +import { IntegrationType } from '../../../common/data_stream_details'; export interface DataStream { name: string; @@ -53,7 +53,7 @@ export interface WithDefaultControllerState { breakdownField?: string; isBreakdownFieldEcs?: boolean; isIndexNotFoundError?: boolean; - integration?: Integration; + integration?: IntegrationType; expandedDegradedField?: string; isNonAggregatable?: boolean; fieldLimit?: FieldLimit; @@ -84,8 +84,11 @@ export interface WithDataStreamSettings { } export interface WithIntegration { - integration: Integration; - integrationDashboards?: Dashboard[]; + integration: IntegrationType; +} + +export interface WithIntegrationDashboards { + integrationDashboards: Dashboard[]; } export interface WithDegradedFieldValues { @@ -116,15 +119,14 @@ export type DatasetQualityDetailsControllerTypeState = value: | 'initializing' | 'initializing.nonAggregatableDataset.fetching' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.fetching' + | 'initializing.dataStreamDetails.fetching' | 'initializing.dataStreamSettings.fetchingDataStreamSettings' - | 'initializing.dataStreamDetails.fetching'; + | 'initializing.dataStreamSettings.errorFetchingDataStreamSettings' + | 'initializing.checkAndLoadIntegrationAndDashboards.checkingAndLoadingIntegration'; context: WithDefaultControllerState; } | { - value: - | 'initializing.nonAggregatableDataset.done' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.fetching'; + value: 'initializing.nonAggregatableDataset.done'; context: WithDefaultControllerState & WithNonAggregatableDatasetStatus; } | { @@ -139,25 +141,25 @@ export type DatasetQualityDetailsControllerTypeState = value: 'initializing.checkBreakdownFieldIsEcs.done'; context: WithDefaultControllerState & WithBreakdownInEcsCheck; } - | { - value: 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.dataStreamDegradedFields.done'; - context: WithDefaultControllerState & - WithNonAggregatableDatasetStatus & - WithDegradedFieldsData; - } | { value: - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.fetching' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.fetching' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.unauthorized'; + | 'initializing.dataStreamSettings.fetchingDataStreamDegradedFields' + | 'initializing.dataStreamSettings.errorFetchingDegradedFields'; context: WithDefaultControllerState & WithDataStreamSettings; } + | { + value: 'initializing.dataStreamSettings.doneFetchingDegradedFields'; + context: WithDefaultControllerState & WithDataStreamSettings & WithDegradedFieldsData; + } | { value: - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDetails.done' - | 'initializing.dataStreamSettings.loadingIntegrationsAndDegradedFields.integrationDashboards.done'; - context: WithDefaultControllerState & WithDataStreamSettings & WithIntegration; + | 'initializing.checkAndLoadIntegrationAndDashboards.loadingIntegrationDashboards' + | 'initializing.checkAndLoadIntegrationAndDashboards.unauthorizedToLoadDashboards'; + context: WithDefaultControllerState & WithIntegration; + } + | { + value: 'initializing.checkAndLoadIntegrationAndDashboards.done'; + context: WithDefaultControllerState & WithIntegration & WithIntegrationDashboards; } | { value: 'initializing.degradedFieldFlyout.open'; @@ -233,8 +235,8 @@ export type DatasetQualityDetailsControllerEvent = | DoneInvokeEvent<DegradedFieldResponse> | DoneInvokeEvent<DegradedFieldValues> | DoneInvokeEvent<DataStreamSettings> - | DoneInvokeEvent<Integration> | DoneInvokeEvent<Dashboard[]> | DoneInvokeEvent<DegradedFieldAnalysis> | DoneInvokeEvent<UpdateFieldLimitResponse> - | DoneInvokeEvent<DataStreamRolloverResponse>; + | DoneInvokeEvent<DataStreamRolloverResponse> + | DoneInvokeEvent<IntegrationType>; diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/index.ts new file mode 100644 index 000000000000..a6606028b6cf --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/index.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { PackageClient } from '@kbn/fleet-plugin/server'; +import { Logger } from '@kbn/logging'; +import { validateCustomComponentTemplate } from './validate_custom_component_template'; +import { getIntegration, getIntegrations } from '../../integrations/get_integrations'; +import { getComponentTemplatePrefixFromIndexTemplate } from '../../../../common/utils/component_template_name'; +import { CheckAndLoadIntegrationResponse } from '../../../../common/api_types'; +import { dataStreamService } from '../../../services'; + +// The function works on 2 conditions: +// 1. It checks if integration name is present in meta field response of the datastream. +// If yes, it considers it to be an integration. No further checks +// 2. If not, then it does the various checks +export async function checkAndLoadIntegration({ + esClient, + packageClient, + logger, + dataStream, +}: { + esClient: ElasticsearchClient; + packageClient: PackageClient; + logger: Logger; + dataStream: string; +}): Promise<CheckAndLoadIntegrationResponse> { + const [dataStreamInfo] = await dataStreamService.getMatchingDataStreams(esClient, dataStream); + + const indexTemplate = dataStreamInfo?.template; + const isManaged = dataStreamInfo?._meta?.managed; + + const integrationNameFromDataStream = dataStreamInfo?._meta?.package?.name; + + // Index template must be present and isManaged should be true or + // integration name should be present + // Else it's not an integration + if ((!indexTemplate || !isManaged) && !integrationNameFromDataStream) { + return { isIntegration: false, areAssetsAvailable: false }; + } + + // If integration name is present, then we find and return the integration + if (integrationNameFromDataStream) { + try { + const integrationDetailsMatchingDataStream = await getIntegration({ + packageClient, + logger, + packageName: integrationNameFromDataStream, + }); + + if (integrationDetailsMatchingDataStream) { + return { + isIntegration: true, + integration: integrationDetailsMatchingDataStream, + areAssetsAvailable: true, + }; + } + } catch (e) { + // This should ideally not happen. As integration name is present in Data stream + // meta response but the integration itself is not found + // Worst case i could think of is, may be the integration is deleted from the + // system at a later point of time + return { isIntegration: false, areAssetsAvailable: false }; + } + } + + // cleaning the index template name as some have @template suffix + const indexTemplateNameWithoutSuffix = getComponentTemplatePrefixFromIndexTemplate(indexTemplate); + + // Check if index template name has both type and dataset part + const isDedicatedComponentTemplate = indexTemplateNameWithoutSuffix.split('-').length === 2; + + // If only 1 part exists, then it's not a dedicated index template + // Data stream name must starts with this index template, then it's a dedicated index template else not + if (!isDedicatedComponentTemplate || !dataStream.startsWith(indexTemplateNameWithoutSuffix)) { + return { isIntegration: false, areAssetsAvailable: false }; + } + + const isValidCustomComponentTemplate = await validateCustomComponentTemplate({ + esClient, + indexTemplateName: indexTemplate, + }); + + if (!isValidCustomComponentTemplate) { + return { isIntegration: false, areAssetsAvailable: false }; + } + + const datasetName = indexTemplateNameWithoutSuffix.split('-')[1]; + + const allIntegrations = await getIntegrations({ packageClient, logger }); + const integrationFromDataset = allIntegrations.find( + (integration) => datasetName in (integration?.datasets ?? {}) + ); + + if (integrationFromDataset) { + return { isIntegration: true, integration: integrationFromDataset, areAssetsAvailable: true }; + } + + // Since the logic reached the last statement, it means it passed all checks for assets being available + return { isIntegration: false, areAssetsAvailable: true }; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/validate_custom_component_template.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/validate_custom_component_template.ts new file mode 100644 index 000000000000..13213814935f --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/check_and_load_integration/validate_custom_component_template.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { createDatasetQualityESClient } from '../../../utils'; +import { getComponentTemplatePrefixFromIndexTemplate } from '../../../../common/utils/component_template_name'; + +export async function validateCustomComponentTemplate({ + esClient, + indexTemplateName, +}: { + esClient: ElasticsearchClient; + indexTemplateName: string; +}): Promise<boolean> { + const datasetQualityESClient = createDatasetQualityESClient(esClient); + // cleaning the index template name as some have @template suffix + const componentTemplateName = getComponentTemplatePrefixFromIndexTemplate(indexTemplateName); + + try { + const { index_templates: indexTemplates } = await datasetQualityESClient.indexTemplates({ + name: indexTemplateName, + }); + + return indexTemplates.some((template) => + template.index_template.composed_of.includes(componentTemplateName + '@custom') + ); + } catch (error) { + return false; + } +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts index 288eff11b92a..0ca2ae94214e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_data_stream_details/index.ts @@ -16,38 +16,12 @@ import { rangeQuery } from '@kbn/observability-plugin/server'; import { MAX_HOSTS_METRIC_VALUE } from '../../../../common/constants'; import { _IGNORED } from '../../../../common/es_fields'; -import { DataStreamDetails, DataStreamSettings } from '../../../../common/api_types'; +import { DataStreamDetails } from '../../../../common/api_types'; import { createDatasetQualityESClient } from '../../../utils'; -import { dataStreamService, datasetQualityPrivileges } from '../../../services'; +import { datasetQualityPrivileges } from '../../../services'; import { getDataStreams } from '../get_data_streams'; import { getDataStreamsMeteringStats } from '../get_data_streams_metering_stats'; -export async function getDataStreamSettings({ - esClient, - dataStream, -}: { - esClient: ElasticsearchClient; - dataStream: string; -}): Promise<DataStreamSettings> { - const [createdOn, [dataStreamInfo], datasetUserPrivileges] = await Promise.all([ - getDataStreamCreatedOn(esClient, dataStream), - dataStreamService.getMatchingDataStreams(esClient, dataStream), - datasetQualityPrivileges.getDatasetPrivileges(esClient, dataStream), - ]); - - const integration = dataStreamInfo?._meta?.package?.name; - const lastBackingIndex = dataStreamInfo?.indices?.slice(-1)[0]; - const indexTemplate = dataStreamInfo?.template; - - return { - createdOn, - integration, - datasetUserPrivileges, - lastBackingIndexName: lastBackingIndex?.index_name, - indexTemplate, - }; -} - export async function getDataStreamDetails({ esClient, dataStream, @@ -118,16 +92,6 @@ export async function getDataStreamDetails({ } } -async function getDataStreamCreatedOn(esClient: ElasticsearchClient, dataStream: string) { - const indexSettings = await dataStreamService.getDataStreamIndexSettings(esClient, dataStream); - - const indexesList = Object.values(indexSettings); - - return indexesList - .map((index) => Number(index.settings?.index?.creation_date)) - .sort((a, b) => a - b)[0]; -} - type TermAggregation = Record<string, { terms: { field: string; size: number } }>; const MAX_HOSTS = MAX_HOSTS_METRIC_VALUE + 1; // Adding 1 so that we can show e.g. '50+' diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/get_datastream_created_on.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/get_datastream_created_on.ts new file mode 100644 index 000000000000..d9d22d326bff --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/get_datastream_created_on.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { dataStreamService } from '../../../services'; + +export async function getDataStreamCreatedOn(esClient: ElasticsearchClient, dataStream: string) { + const indexSettings = await dataStreamService.getDataStreamIndexSettings(esClient, dataStream); + + const indexesList = Object.values(indexSettings); + + return indexesList + .map((index) => Number(index.settings?.index?.creation_date)) + .sort((a, b) => a - b)[0]; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/index.ts new file mode 100644 index 000000000000..8044c8a5abf6 --- /dev/null +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/get_datastream_settings/index.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { datasetQualityPrivileges, dataStreamService } from '../../../services'; +import { DataStreamSettings } from '../../../../common/api_types'; +import { getDataStreamCreatedOn } from './get_datastream_created_on'; + +export async function getDataStreamSettings({ + esClient, + dataStream, +}: { + esClient: ElasticsearchClient; + dataStream: string; +}): Promise<DataStreamSettings> { + const [createdOn, [dataStreamInfo], datasetUserPrivileges] = await Promise.all([ + getDataStreamCreatedOn(esClient, dataStream), + dataStreamService.getMatchingDataStreams(esClient, dataStream), + datasetQualityPrivileges.getDatasetPrivileges(esClient, dataStream), + ]); + + const integration = dataStreamInfo?._meta?.package?.name; + const lastBackingIndex = dataStreamInfo?.indices?.at(-1); + const indexTemplate = dataStreamInfo?.template; + + return { + createdOn, + integration, + datasetUserPrivileges, + lastBackingIndexName: lastBackingIndex?.index_name, + indexTemplate, + }; +} diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts index 3a60f0b9a8ef..c8ed3296908e 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/routes.ts @@ -18,11 +18,12 @@ import { DataStreamDocsStat, UpdateFieldLimitResponse, DataStreamRolloverResponse, + CheckAndLoadIntegrationResponse, } from '../../../common/api_types'; import { rangeRt, typeRt, typesRt } from '../../types/default_api_types'; import { createDatasetQualityServerRoute } from '../create_datasets_quality_server_route'; import { datasetQualityPrivileges } from '../../services'; -import { getDataStreamDetails, getDataStreamSettings } from './get_data_stream_details'; +import { getDataStreamDetails } from './get_data_stream_details'; import { getDataStreams } from './get_data_streams'; import { getDataStreamsStats } from './get_data_streams_stats'; import { getDegradedDocsPaginated } from './get_degraded_docs'; @@ -34,6 +35,8 @@ import { getDataStreamsMeteringStats } from './get_data_streams_metering_stats'; import { getAggregatedDatasetPaginatedResults } from './get_dataset_aggregated_paginated_results'; import { updateFieldLimit } from './update_field_limit'; import { createDatasetQualityESClient } from '../../utils'; +import { getDataStreamSettings } from './get_datastream_settings'; +import { checkAndLoadIntegration } from './check_and_load_integration'; const statsRoute = createDatasetQualityServerRoute({ endpoint: 'GET /internal/dataset_quality/data_streams/stats', @@ -293,6 +296,38 @@ const dataStreamSettingsRoute = createDatasetQualityServerRoute({ }, }); +const checkAndLoadIntegrationRoute = createDatasetQualityServerRoute({ + endpoint: 'GET /internal/dataset_quality/data_streams/{dataStream}/integration/check', + params: t.type({ + path: t.type({ + dataStream: t.string, + }), + }), + options: { + tags: [], + }, + async handler(resources): Promise<CheckAndLoadIntegrationResponse> { + const { context, params, plugins, logger } = resources; + const { dataStream } = params.path; + const coreContext = await context.core; + + // Query dataStreams as the current user as the Kibana internal user may not have all the required permissions + const esClient = coreContext.elasticsearch.client.asCurrentUser; + + const fleetPluginStart = await plugins.fleet.start(); + const packageClient = fleetPluginStart.packageService.asInternalUser; + + const integration = await checkAndLoadIntegration({ + esClient, + packageClient, + logger, + dataStream, + }); + + return integration; + }, +}); + const dataStreamDetailsRoute = createDatasetQualityServerRoute({ endpoint: 'GET /internal/dataset_quality/data_streams/{dataStream}/details', params: t.type({ @@ -418,6 +453,7 @@ export const dataStreamsRouteRepository = { ...degradedFieldValuesRoute, ...dataStreamDetailsRoute, ...dataStreamSettingsRoute, + ...checkAndLoadIntegrationRoute, ...analyzeDegradedFieldRoute, ...updateFieldLimitRoute, ...rolloverDataStream, diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts index f377ea1e2642..d00831a58aa7 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/data_streams/update_field_limit/index.ts @@ -11,7 +11,7 @@ import { createDatasetQualityESClient } from '../../../utils'; import { updateComponentTemplate } from './update_component_template'; import { updateLastBackingIndexSettings } from './update_settings_last_backing_index'; import { UpdateFieldLimitResponse } from '../../../../common/api_types'; -import { getDataStreamSettings } from '../get_data_stream_details'; +import { getDataStreamSettings } from '../get_datastream_settings'; export async function updateFieldLimit({ esClient, diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts index 10e89db800a2..b8bf8719783c 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/integrations/get_integrations.ts @@ -8,9 +8,29 @@ import { Logger } from '@kbn/core/server'; import { PackageClient } from '@kbn/fleet-plugin/server'; import { PackageNotFoundError } from '@kbn/fleet-plugin/server/errors'; -import { PackageListItem, RegistryDataStream } from '@kbn/fleet-plugin/common'; +import { PackageInfo, RegistryDataStream } from '@kbn/fleet-plugin/common'; import { IntegrationType } from '../../../common/api_types'; +export async function getIntegration({ + packageClient, + logger, + packageName, +}: { + packageClient: PackageClient; + logger: Logger; + packageName: string; +}): Promise<IntegrationType> { + const latestPackage = await packageClient.getLatestPackageInfo(packageName); + + return { + name: latestPackage.name, + title: latestPackage.title, + version: latestPackage.version, + icons: latestPackage.icons, + datasets: await getDatasets({ packageClient, logger, pkg: latestPackage }), + }; +} + export async function getIntegrations(options: { packageClient: PackageClient; logger: Logger; @@ -36,7 +56,7 @@ export async function getIntegrations(options: { const getDatasets = async (options: { packageClient: PackageClient; logger: Logger; - pkg: PackageListItem; + pkg: Pick<PackageInfo, 'name' | 'version' | 'data_streams'>; }) => { const { packageClient, logger, pkg } = options; diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/register_routes.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/register_routes.ts index 4e1970d7fc88..db5620e0778f 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/register_routes.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/register_routes.ts @@ -39,14 +39,18 @@ export function registerRoutes({ const router = core.http.createRouter(); routes.forEach((route) => { - const { endpoint, options, handler, params } = route; + const { endpoint, handler } = route; const { pathname, method } = parseEndpoint(endpoint); + const params = 'params' in route ? route.params : undefined; + const options = 'options' in route ? route.options : {}; + (router[method] as RouteRegistrar<typeof method, DatasetQualityRequestHandlerContext>)( { path: pathname, validate: passThroughValidationObject, options, + security: route.security, }, async (context, request, response) => { try { diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/routes/types.ts b/x-pack/plugins/observability_solution/dataset_quality/server/routes/types.ts index 86dd9e098625..298d0c45efc4 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/routes/types.ts @@ -29,7 +29,5 @@ export interface DatasetQualityRouteHandlerResources { } export interface DatasetQualityRouteCreateOptions { - options: { - tags: string[]; - }; + tags: string[]; } diff --git a/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts b/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts index 8a78b4163da9..cb6c963435f1 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts +++ b/x-pack/plugins/observability_solution/dataset_quality/server/utils/create_dataset_quality_es_client.ts @@ -13,6 +13,8 @@ import { FieldCapsRequest, FieldCapsResponse, Indices, + IndicesGetIndexTemplateRequest, + IndicesGetIndexTemplateResponse, IndicesGetMappingResponse, IndicesGetSettingsResponse, IndicesPutSettingsRequest, @@ -63,5 +65,10 @@ export function createDatasetQualityESClient(esClient: ElasticsearchClient) { rollover(params: { alias: string }): Promise<IndicesRolloverResponse> { return esClient.indices.rollover(params); }, + indexTemplates( + params: IndicesGetIndexTemplateRequest + ): Promise<IndicesGetIndexTemplateResponse> { + return esClient.indices.getIndexTemplate(params); + }, }; } diff --git a/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json b/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json index 8576b08bd947..57b159cdbd29 100644 --- a/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json +++ b/x-pack/plugins/observability_solution/dataset_quality/tsconfig.json @@ -61,7 +61,8 @@ "@kbn/rison", "@kbn/task-manager-plugin", "@kbn/core-application-browser", - "@kbn/field-utils" + "@kbn/field-utils", + "@kbn/logging" ], "exclude": [ "target/**/*" diff --git a/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx b/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx index 8c978db6f675..59740fb8f813 100644 --- a/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx +++ b/x-pack/plugins/observability_solution/entity_manager_app/public/pages/overview/index.tsx @@ -101,17 +101,29 @@ function EntitySourceForm({ /> </EuiFormRow> </EuiFlexItem> + + <EuiFlexItem> + <EuiFormRow label="Display name"> + <EuiFieldText + data-test-subj="entityManagerFormDisplayName" + name="display_name" + defaultValue={source.display_name} + onChange={(e) => onFieldChange(index, 'display_name', e.target.value)} + /> + </EuiFormRow> + </EuiFlexItem> </EuiFlexGroup> ); } interface EntitySource { id: string; - index_patterns?: string[]; - identity_fields?: string[]; - metadata_fields?: string[]; - filters?: string[]; + index_patterns: string[]; + identity_fields: string[]; + metadata_fields: string[]; + filters: string[]; timestamp_field?: string; + display_name?: string; } const newEntitySource = ({ @@ -126,7 +138,7 @@ const newEntitySource = ({ metadataFields?: string[]; filters?: string[]; timestampField?: string; -}) => ({ +}): EntitySource => ({ id: uuid(), index_patterns: indexPatterns, identity_fields: identityFields, @@ -320,6 +332,10 @@ export function EntityManagerOverviewPage() { field: 'entity.id', name: 'entity.id', }, + { + field: 'entity.display_name', + name: 'entity.display_name', + }, { field: 'entity.type', name: 'entity.type', @@ -329,16 +345,10 @@ export function EntityManagerOverviewPage() { name: 'entity.last_seen_timestamp', }, ...Array.from(new Set(entitySources.flatMap((source) => source.identity_fields))).map( - (field) => ({ - field, - name: field, - }) + (field) => ({ field, name: field }) ), ...Array.from(new Set(entitySources.flatMap((source) => source.metadata_fields))).map( - (field) => ({ - field: `metadata.${field}`, - name: `metadata.${field}`, - }) + (field) => ({ field, name: field }) ), ]} /> diff --git a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx index ee95d2a7f61a..efb6623f80e3 100644 --- a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx +++ b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/components/action_menu/action_menu.tsx @@ -8,7 +8,7 @@ import React, { useState } from 'react'; import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { LensEmbeddableInput, TypedLensByValueInput } from '@kbn/lens-plugin/public'; +import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { EmbedAction } from '../../header/embed_action'; import { AddToCaseAction } from '../../header/add_to_case_action'; import { useKibana } from '../../hooks/use_kibana'; @@ -94,7 +94,7 @@ export function ExpViewActionMenuContent({ {isSaveOpen && lensAttributes && ( <LensSaveModalComponent - initialInput={lensAttributes as unknown as LensEmbeddableInput} + initialInput={{ attributes: lensAttributes }} onClose={() => setIsSaveOpen(false)} // if we want to do anything after the viz is saved // right now there is no action, so an empty function diff --git a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts index 75a5c42c7644..846044a7a7b0 100644 --- a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts +++ b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.test.ts @@ -22,6 +22,7 @@ import { obsvReportConfigMap } from '../obsv_exploratory_view'; import { sampleAttributeWithReferenceLines } from './test_data/sample_attribute_with_reference_lines'; import { lensPluginMock } from '@kbn/lens-plugin/public/mocks'; import { FormulaPublicApi, XYState } from '@kbn/lens-plugin/public'; +import { Query } from '@kbn/es-query'; describe('Lens Attribute', () => { mockAppDataView(); @@ -448,7 +449,9 @@ describe('Lens Attribute', () => { reportViewConfig.reportType, formulaHelper ).getJSON(); - expect(multiSeriesLensAttr.state.query.query).toEqual('transaction.duration.us < 60000000'); + expect((multiSeriesLensAttr.state.query as Query).query).toEqual( + 'transaction.duration.us < 60000000' + ); }); describe('Layer breakdowns', function () { diff --git a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.ts b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.ts index dd98e9879e82..282ae5b76826 100644 --- a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.ts +++ b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/configurations/lens_attributes.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import { capitalize } from 'lodash'; -import { ExistsFilter, Filter, isExistsFilter } from '@kbn/es-query'; +import { type ExistsFilter, type Query, type Filter, isExistsFilter } from '@kbn/es-query'; import { AvgIndexPatternColumn, CardinalityIndexPatternColumn, @@ -1300,7 +1300,7 @@ export class LensAttributes { visualizationType: 'lnsXY' | 'lnsLegacyMetric' | 'lnsHeatmap' = 'lnsXY', lastRefresh?: number ): TypedLensByValueInput['attributes'] { - const query = this.globalFilter || this.layerConfigs[0].seriesConfig.query; + const query: Query | undefined = this.globalFilter || this.layerConfigs[0].seriesConfig.query; const { internalReferences, adHocDataViews } = this.getReferences(); diff --git a/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts b/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts index b8410a478b6f..2ae0e0b00a2d 100644 --- a/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts +++ b/x-pack/plugins/observability_solution/infra/common/alerting/logs/log_threshold/types.ts @@ -10,7 +10,7 @@ import * as rt from 'io-ts'; import { persistedLogViewReferenceRT } from '@kbn/logs-shared-plugin/common'; import { commonSearchSuccessResponseFieldsRT } from '../../../utils/elasticsearch_runtime_types'; -export const LOG_DOCUMENT_COUNT_RULE_TYPE_ID = 'logs.alert.document.count'; +export { LOG_THRESHOLD_ALERT_TYPE_ID as LOG_DOCUMENT_COUNT_RULE_TYPE_ID } from '@kbn/rule-data-utils'; const ThresholdTypeRT = rt.keyof({ count: null, diff --git a/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts b/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts index b5a3c084c47c..d1adb75d5113 100644 --- a/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts +++ b/x-pack/plugins/observability_solution/infra/common/alerting/metrics/types.ts @@ -8,16 +8,12 @@ import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/ import { InventoryItemType, SnapshotMetricType } from '@kbn/metrics-data-access-plugin/common'; import { COMPARATORS } from '@kbn/alerting-comparators'; import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator'; +export { INFRA_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { SnapshotCustomMetricInput } from '../../http_api'; export const METRIC_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.threshold'; export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold'; -export enum InfraRuleType { - MetricThreshold = 'metrics.alert.threshold', - InventoryThreshold = 'metrics.alert.inventory.threshold', -} - export enum Aggregators { COUNT = 'count', AVERAGE = 'avg', diff --git a/x-pack/plugins/observability_solution/infra/common/constants.ts b/x-pack/plugins/observability_solution/infra/common/constants.ts index 482406171a67..c86d39cddb3f 100644 --- a/x-pack/plugins/observability_solution/infra/common/constants.ts +++ b/x-pack/plugins/observability_solution/infra/common/constants.ts @@ -5,14 +5,25 @@ * 2.0. */ +import { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils'; + export const METRICS_INDEX_PATTERN = 'metrics-*,metricbeat-*'; export const LOGS_INDEX_PATTERN = 'logs-*,filebeat-*,kibana_sample_data_logs*'; export const METRICS_APP = 'metrics'; export const LOGS_APP = 'logs'; -export const METRICS_FEATURE_ID = 'infrastructure'; -export const INFRA_ALERT_FEATURE_ID = 'infrastructure'; -export const LOGS_FEATURE_ID = 'logs'; +export const METRICS_FEATURE_ID = AlertConsumers.INFRASTRUCTURE; +export const INFRA_ALERT_FEATURE_ID = AlertConsumers.INFRASTRUCTURE; +export const LOGS_FEATURE_ID = AlertConsumers.LOGS; + +export const INFRA_ALERT_CONSUMERS: ValidFeatureId[] = [ + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.OBSERVABILITY, + AlertConsumers.LOGS, + AlertConsumers.SLO, + AlertConsumers.APM, + AlertConsumers.ALERTS, +]; export type InfraFeatureId = typeof METRICS_FEATURE_ID | typeof LOGS_FEATURE_ID; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts index ca56a5887522..01da12c5f59a 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/add_metrics_callout/constants.ts @@ -62,7 +62,7 @@ const containerDefaultActions = ( return { actions: { primary: { - href: locator?.getRedirectUrl({ category: OnboardingFlow.Infra }), + href: locator?.getRedirectUrl({ category: OnboardingFlow.Hosts }), label: defaultPrimaryActionLabel, }, link: { diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_container_metrics_charts.test.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_container_metrics_charts.test.ts index 392582d4f9ee..496029a8b436 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_container_metrics_charts.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_container_metrics_charts.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { ContainerMetricTypes } from '../charts/types'; import { useK8sContainerPageViewMetricsCharts, @@ -48,10 +48,10 @@ describe('useDockerContainerCharts', () => { async (metric) => { const expectedOrder = getContainerChartsExpectedOrder(metric); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useDockerContainerPageViewMetricsCharts({ metricsDataViewId, metric }) ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { charts } = result.current; @@ -68,13 +68,14 @@ describe('useDockerContainerCharts', () => { describe('useDockerKPIMetricsCharts', () => { it('should return an array of charts with correct order', async () => { const expectedOrder = ['cpuUsage', 'memoryUsage']; - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useDockerContainerKpiCharts({ dataViewId: metricsDataViewId }) ); - await waitForNextUpdate(); - expect(result.current).toHaveLength(expectedOrder.length); - result.current.forEach((chart, index) => { - expect(chart).toHaveProperty('id', expectedOrder[index]); + await waitFor(() => { + expect(result.current).toHaveLength(expectedOrder.length); + result.current.forEach((chart, index) => { + expect(chart).toHaveProperty('id', expectedOrder[index]); + }); }); }); }); @@ -86,10 +87,10 @@ describe('useK8sContainerCharts', () => { async (metric) => { const expectedOrder = getK8sContainerChartsExpectedOrder(metric); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useK8sContainerPageViewMetricsCharts({ metricsDataViewId, metric }) ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { charts } = result.current; @@ -106,13 +107,14 @@ describe('useK8sContainerCharts', () => { describe('useK8sContainerKPIMetricsCharts', () => { it('should return an array of charts with correct order', async () => { const expectedOrder = ['k8sCpuUsage', 'k8sMemoryUsage']; - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useK8sContainerKpiCharts({ dataViewId: metricsDataViewId }) ); - await waitForNextUpdate(); - expect(result.current).toHaveLength(expectedOrder.length); - result.current.forEach((chart, index) => { - expect(chart).toHaveProperty('id', expectedOrder[index]); + await waitFor(() => { + expect(result.current).toHaveLength(expectedOrder.length); + result.current.forEach((chart, index) => { + expect(chart).toHaveProperty('id', expectedOrder[index]); + }); }); }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_entity_summary.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_entity_summary.ts index e62defaac6d4..500dd02c63e1 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_entity_summary.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_entity_summary.ts @@ -6,10 +6,16 @@ */ import * as z from '@kbn/zod'; -import { EntityDataStreamType, ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; +import { + EntityDataStreamType, + BUILT_IN_ENTITY_TYPES, +} from '@kbn/observability-shared-plugin/common'; import { useFetcher } from '../../../hooks/use_fetcher'; -const EntityTypeSchema = z.union([z.literal(ENTITY_TYPES.HOST), z.literal(ENTITY_TYPES.CONTAINER)]); +const EntityTypeSchema = z.union([ + z.literal(BUILT_IN_ENTITY_TYPES.HOST), + z.literal(BUILT_IN_ENTITY_TYPES.CONTAINER), +]); const EntityDataStreamSchema = z.union([ z.literal(EntityDataStreamType.METRICS), z.literal(EntityDataStreamType.LOGS), diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_host_metrics_charts.test.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_host_metrics_charts.test.ts index 006fae9bec75..f95ab156222e 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_host_metrics_charts.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_host_metrics_charts.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { HostMetricTypes } from '../charts/types'; import { useHostKpiCharts, useHostCharts, useKubernetesCharts } from './use_host_metrics_charts'; @@ -40,10 +40,8 @@ describe('useHostCharts', () => { async (metric) => { const expectedOrder = getHostChartsExpectedOrder(metric, false); - const { result, waitForNextUpdate } = renderHook(() => - useHostCharts({ dataViewId, metric }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => useHostCharts({ dataViewId, metric })); + await waitFor(() => new Promise((resolve) => resolve(null))); const { charts } = result.current; @@ -60,10 +58,10 @@ describe('useHostCharts', () => { async (metric) => { const expectedOrder = getHostChartsExpectedOrder(metric, true); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useHostCharts({ dataViewId, metric, overview: true }) ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { charts } = result.current; @@ -80,10 +78,8 @@ describe('useHostCharts', () => { describe('useKubernetesCharts', () => { it('should return an array of charts with correct order - overview', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useKubernetesCharts({ dataViewId, overview: true }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => useKubernetesCharts({ dataViewId, overview: true })); + await waitFor(() => new Promise((resolve) => resolve(null))); const expectedOrder = ['nodeCpuCapacity', 'nodeMemoryCapacity']; @@ -97,8 +93,8 @@ describe('useKubernetesCharts', () => { }); it('should return an array of charts with correct order', async () => { - const { result, waitForNextUpdate } = renderHook(() => useKubernetesCharts({ dataViewId })); - await waitForNextUpdate(); + const { result } = renderHook(() => useKubernetesCharts({ dataViewId })); + await waitFor(() => new Promise((resolve) => resolve(null))); const expectedOrder = [ 'nodeCpuCapacity', @@ -119,8 +115,8 @@ describe('useKubernetesCharts', () => { describe('useHostKpiCharts', () => { it('should return an array of charts with correct order', async () => { - const { result, waitForNextUpdate } = renderHook(() => useHostKpiCharts({ dataViewId })); - await waitForNextUpdate(); + const { result } = renderHook(() => useHostKpiCharts({ dataViewId })); + await waitFor(() => new Promise((resolve) => resolve(null))); const expectedOrder = ['cpuUsage', 'normalizedLoad1m', 'memoryUsage', 'diskUsage']; @@ -140,10 +136,8 @@ describe('useHostKpiCharts', () => { getSubtitle: () => 'Custom Subtitle', }; - const { result, waitForNextUpdate } = renderHook(() => - useHostKpiCharts({ dataViewId, ...options }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => useHostKpiCharts({ dataViewId, ...options })); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current).toHaveLength(4); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.test.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.test.ts index becd0e81c0a9..2475c97cec0e 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_loading_state.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useLoadingState } from './use_loading_state'; import { useDatePickerContext, type UseDateRangeProviderProps } from './use_date_picker'; import { BehaviorSubject, EMPTY, of, Subject, Subscription, skip } from 'rxjs'; @@ -102,7 +102,7 @@ describe('useLoadingState', () => { }); it('should set isAutoRefreshRequestPending to true when there are requests pending', async () => { - const { result, unmount, waitFor } = renderHook(() => useLoadingState()); + const { result, unmount } = renderHook(() => useLoadingState()); let receivedValue = false; subscription.add( @@ -128,7 +128,7 @@ describe('useLoadingState', () => { }); it('should set isAutoRefreshRequestPending to false when all requests complete', async () => { - const { result, unmount, waitFor } = renderHook(() => useLoadingState()); + const { result, unmount } = renderHook(() => useLoadingState()); let receivedValue = true; subscription.add( @@ -153,7 +153,7 @@ describe('useLoadingState', () => { }); it('should not call updateSearchSessionId if waitUntilNextSessionCompletesMock$ returns empty', async () => { - const { unmount, waitFor } = renderHook(() => useLoadingState()); + const { unmount } = renderHook(() => useLoadingState()); // waitUntilNextSessionCompletes$ returns EMPTY when the status is loading or none sessionState$.next(SearchSessionState.Loading); @@ -171,7 +171,7 @@ describe('useLoadingState', () => { }); it('should call updateSearchSessionId when waitUntilNextSessionCompletesMock$ returns', async () => { - const { unmount, waitFor } = renderHook(() => useLoadingState()); + const { unmount } = renderHook(() => useLoadingState()); // waitUntilNextSessionCompletes$ returns something when the status is Completed or BackgroundCompleted sessionState$.next(SearchSessionState.Loading); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_profiling_kuery.test.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_profiling_kuery.test.tsx index 10325ce51f81..0d4db96a23fa 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_profiling_kuery.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_profiling_kuery.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { MemoryRouter, useHistory } from 'react-router-dom'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useProfilingKuery } from './use_profiling_kuery'; import { useAssetDetailsRenderPropsContext } from './use_asset_details_render_props'; diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_request_observable.test.ts b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_request_observable.test.ts index 9ca4bd17ca34..9be24cbfcf3f 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_request_observable.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/hooks/use_request_observable.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useRequestObservable } from './use_request_observable'; import { type RequestState, useLoadingStateContext } from './use_loading_state'; import { useDatePickerContext, type UseDateRangeProviderProps } from './use_date_picker'; @@ -69,7 +69,7 @@ describe('useRequestObservable', () => { }); it('should process a valid request function', async () => { - const { result, waitFor, unmount } = renderHook(() => useRequestObservable()); + const { result, unmount } = renderHook(() => useRequestObservable()); act(() => { result.current.request$.next(() => Promise.resolve()); @@ -85,7 +85,7 @@ describe('useRequestObservable', () => { }); it('should be able to make new requests if isAutoRefreshRequestPending is false', async () => { - const { result, waitFor, unmount } = renderHook(() => useRequestObservable()); + const { result, unmount } = renderHook(() => useRequestObservable()); act(() => { isAutoRefreshRequestPendingMock$.next(false); @@ -102,7 +102,7 @@ describe('useRequestObservable', () => { }); it('should block new requests when isAutoRefreshRequestPending is true', async () => { - const { result, waitFor, unmount } = renderHook(() => useRequestObservable()); + const { result, unmount } = renderHook(() => useRequestObservable()); act(() => { isAutoRefreshRequestPendingMock$.next(false); @@ -123,7 +123,7 @@ describe('useRequestObservable', () => { }); it('should not block new requests when auto-refresh is paused', async () => { - const { result, waitFor, unmount } = renderHook(() => useRequestObservable()); + const { result, unmount } = renderHook(() => useRequestObservable()); act(() => { autoRefreshConfig$.next({ isPaused: true, interval: 5000 }); @@ -144,7 +144,7 @@ describe('useRequestObservable', () => { }); it('should complete the request when an error is thrown', async () => { - const { result, waitFor, unmount } = renderHook(() => useRequestObservable()); + const { result, unmount } = renderHook(() => useRequestObservable()); act(() => { autoRefreshConfig$.next({ isPaused: true, interval: 5000 }); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx index f49fa026892b..65d19f769374 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/metrics/container_metrics.tsx @@ -14,6 +14,7 @@ import { MetricsTemplate } from './metrics_template'; import { DockerCharts, KubernetesContainerCharts } from '../../charts'; import { DOCKER_METRIC_TYPES, INTEGRATIONS, KUBERNETES_METRIC_TYPES } from '../../constants'; import { useIntegrationCheck } from '../../hooks/use_integration_check'; +import { AddMetricsCallout } from '../../add_metrics_callout'; export const ContainerMetrics = () => { const ref = useRef<HTMLDivElement>(null); @@ -29,7 +30,7 @@ export const ContainerMetrics = () => { }); if (!isDockerContainer && !isKubernetesContainer) { - return null; + return <AddMetricsCallout id="containerMetrics" />; } return ( diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx index 304e67a0debd..dc4d78baeb5a 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/alerts/alerts.tsx @@ -75,7 +75,7 @@ export const AlertsSummaryContent = ({ )} <EuiFlexItem grow={false}> <LinkToAlertsPage - kuery={`${assetIdField}:"${assetId}"`} + kuery={`"${assetId}"`} dateRange={dateRange} data-test-subj="infraAssetDetailsAlertsTabAlertsShowAllButton" /> diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx index e4f0eee51dbc..9ace5606599d 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/overview/overview.tsx @@ -27,8 +27,6 @@ import { AddMetricsCallout } from '../../add_metrics_callout'; import { AddMetricsCalloutKey } from '../../add_metrics_callout/constants'; import { useEntitySummary } from '../../hooks/use_entity_summary'; import { isMetricsSignal } from '../../utils/get_data_stream_types'; -import { INTEGRATIONS } from '../../constants'; -import { useIntegrationCheck } from '../../hooks/use_integration_check'; export const Overview = () => { const { dateRange } = useDatePickerContext(); @@ -50,10 +48,6 @@ export const Overview = () => { `infra.dismissedAddMetricsCallout.${addMetricsCalloutId}`, false ); - const isDockerContainer = useIntegrationCheck({ dependsOn: INTEGRATIONS.docker }); - const isKubernetesContainer = useIntegrationCheck({ - dependsOn: INTEGRATIONS.kubernetesContainer, - }); const metadataSummarySection = isFullPageView ? ( <MetadataSummaryList metadata={metadata} loading={metadataLoading} assetType={asset.type} /> @@ -74,13 +68,7 @@ export const Overview = () => { return false; } - const { type } = asset; - const baseCondition = !isMetricsSignal(dataStreams); - - const isRelevantContainer = - type === 'container' && (isDockerContainer || isKubernetesContainer); - - return baseCondition && (type === 'host' || isRelevantContainer); + return !isMetricsSignal(dataStreams); }; const showAddMetricsCallout = shouldShowCallout(); diff --git a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/processes/processes.tsx b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/processes/processes.tsx index 2177cd050908..57a07d4dc296 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/processes/processes.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/asset_details/tabs/processes/processes.tsx @@ -23,7 +23,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { getFieldByType } from '@kbn/metrics-data-access-plugin/common'; import { decodeOrThrow } from '@kbn/io-ts-utils'; import useLocalStorage from 'react-use/lib/useLocalStorage'; -import { ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; +import { BUILT_IN_ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; import { useSourceContext } from '../../../../containers/metrics_source'; import { isPending, useFetcher } from '../../../../hooks/use_fetcher'; import { parseSearchString } from './parse_search_string'; @@ -58,7 +58,7 @@ export const Processes = () => { const { request$ } = useRequestObservable(); const { isActiveTab } = useTabSwitcherContext(); const { dataStreams, status: dataStreamsStatus } = useEntitySummary({ - entityType: ENTITY_TYPES.HOST, + entityType: BUILT_IN_ENTITY_TYPES.HOST, entityId: asset.name, }); const addMetricsCalloutId: AddMetricsCalloutKey = 'hostProcesses'; diff --git a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx index b244ff12222d..56d69fa9b6c7 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_chart.tsx @@ -25,6 +25,12 @@ import { ChartLoadError } from './chart_load_error'; import { HOST_MISSING_FIELDS } from '../../common/visualizations/constants'; const MIN_HEIGHT = 300; +const DEFAULT_DISABLED_ACTIONS = [ + 'ACTION_CUSTOMIZE_PANEL', + 'ACTION_EXPORT_CSV', + 'embeddable_addToExistingCase', + 'create-ml-ad-job-action', +]; export type LensChartProps = BaseChartProps & Pick<EuiPanelProps, 'borderRadius'> & { @@ -33,6 +39,8 @@ export type LensChartProps = BaseChartProps & description?: string; } & { lensAttributes: UseLensAttributesParams; + withDefaultActions?: boolean; + disabledActions?: string[]; }; export const LensChart = React.memo( @@ -52,6 +60,8 @@ export const LensChart = React.memo( height = MIN_HEIGHT, loading = false, lensAttributes, + withDefaultActions = true, + disabledActions = DEFAULT_DISABLED_ACTIONS, }: LensChartProps) => { const { formula, attributes, getExtraActions, error } = useLensAttributes(lensAttributes); @@ -122,6 +132,8 @@ export const LensChart = React.memo( dateRange={dateRange} disableTriggers={disableTriggers} extraActions={extraActions} + withDefaultActions={withDefaultActions} + disabledActions={disabledActions} filters={filters} hidePanelTitles={hidePanelTitles} loading={isLoading} diff --git a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx index 01d409fc9a1a..01ce60b59346 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/lens/lens_wrapper.tsx @@ -93,7 +93,6 @@ export const LensWrapper = ({ <div css={css` position: relative; - overflow: hidden; height: 100%; .echMetric { border-radius: ${euiTheme.border.radius.medium}; diff --git a/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/alerts_overview.tsx b/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/alerts_overview.tsx index 55ac129e5466..e1143948f167 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/alerts_overview.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/alerts_overview.tsx @@ -8,14 +8,15 @@ import React, { useCallback, useMemo, useState } from 'react'; import type { AlertStatus } from '@kbn/observability-plugin/common/typings'; import type { TimeRange } from '@kbn/es-query'; import { useSummaryTimeRange } from '@kbn/observability-plugin/public'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers, OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { BrushEndListener, XYBrushEvent } from '@elastic/charts'; import type { InventoryItemType } from '@kbn/metrics-data-access-plugin/common'; +import { INFRA_ALERT_CONSUMERS } from '../../../../common/constants'; import { AlertsCount } from '../../../hooks/use_alerts_count'; import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; import { createAlertsEsQuery } from '../../../utils/filters/create_alerts_es_query'; -import { ALERT_STATUS_ALL, infraAlertFeatureIds } from './constants'; +import { ALERT_STATUS_ALL } from './constants'; import AlertsStatusFilter from './alerts_status_filter'; import { useAssetDetailsUrlState } from '../../asset_details/hooks/use_asset_details_url_state'; @@ -27,8 +28,6 @@ interface AlertsOverviewProps { assetType?: InventoryItemType; } -const alertFeatureIds = [...infraAlertFeatureIds, AlertConsumers.OBSERVABILITY]; - export const AlertsOverview = ({ assetId, dateRange, @@ -114,7 +113,8 @@ export const AlertsOverview = ({ <EuiFlexItem> <AlertSummaryWidget chartProps={chartProps} - featureIds={infraAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS} + consumers={INFRA_ALERT_CONSUMERS} filter={alertsEsQuery} timeRange={summaryTimeRange} onLoaded={onLoaded} @@ -127,7 +127,8 @@ export const AlertsOverview = ({ alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} id={'assetDetailsAlertsTable'} configurationId={AlertConsumers.OBSERVABILITY} - featureIds={alertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS} + consumers={INFRA_ALERT_CONSUMERS} showAlertStatusWithFlapping query={alertsEsQueryByStatus} initialPageSize={5} diff --git a/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/constants.ts b/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/constants.ts index 1719a58af61e..a876d5f812de 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/constants.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/shared/alerts/constants.ts @@ -11,11 +11,10 @@ import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, ALERT_STATUS_UNTRACKED, - AlertConsumers, } from '@kbn/rule-data-utils'; import type { Filter } from '@kbn/es-query'; import type { AlertStatus } from '@kbn/observability-plugin/common/typings'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; +import { INFRA_ALERT_CONSUMERS } from '../../../../common/constants'; export const ALERT_STATUS_ALL = 'all'; @@ -88,5 +87,4 @@ export const ALERTS_PATH = '/app/observability/alerts'; export const ALERTS_PER_PAGE = 10; export const ALERTS_TABLE_ID = 'xpack.infra.hosts.alerts.table'; -export const INFRA_ALERT_FEATURE_ID = 'infrastructure'; -export const infraAlertFeatureIds: ValidFeatureId[] = [AlertConsumers.INFRASTRUCTURE]; +export const infraAlertFeatureIds = INFRA_ALERT_CONSUMERS; diff --git a/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts b/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts index 3859f93ddc43..28e0d00c751a 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts +++ b/x-pack/plugins/observability_solution/infra/public/components/shared/templates/no_data_config.ts @@ -18,7 +18,7 @@ import { noMetricIndicesPromptDescription, noMetricIndicesPromptTitle } from '.. export enum OnboardingFlow { Infra = 'infra', - Hosts = 'logs', + Hosts = 'host', } interface NoDataConfigDetails { diff --git a/x-pack/plugins/observability_solution/infra/public/containers/ml/infra_ml_module_status.test.ts b/x-pack/plugins/observability_solution/infra/public/containers/ml/infra_ml_module_status.test.ts index 80d538ef1e50..b754537107e4 100644 --- a/x-pack/plugins/observability_solution/infra/public/containers/ml/infra_ml_module_status.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/containers/ml/infra_ml_module_status.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useModuleStatus } from './infra_ml_module_status'; describe('useModuleStatus', () => { diff --git a/x-pack/plugins/observability_solution/infra/public/containers/plugin_config_context.test.tsx b/x-pack/plugins/observability_solution/infra/public/containers/plugin_config_context.test.tsx index 62c582a81824..a33c3432f06f 100644 --- a/x-pack/plugins/observability_solution/infra/public/containers/plugin_config_context.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/containers/plugin_config_context.test.tsx @@ -6,15 +6,15 @@ */ import type { InfraConfig } from '../../common/plugin_config_types'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { PluginConfigProvider, usePluginConfig } from './plugin_config_context'; describe('usePluginConfig()', () => { it('throws an error if the context value was not set before using the hook', () => { - const { result } = renderHook(() => usePluginConfig()); - - expect(result.error).not.toEqual(undefined); + expect(() => renderHook(() => usePluginConfig())).toThrow( + /PluginConfigContext value was not initialized./ + ); }); it('returns the plugin config what was set through the provider', () => { @@ -40,7 +40,6 @@ describe('usePluginConfig()', () => { }, }); - expect(result.error).toEqual(undefined); expect(result.current).toEqual(config); }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.test.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.test.ts index 2b2dc755c94c..e6f0e63c2c29 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; -import { ALERT_STATUS, ValidFeatureId } from '@kbn/rule-data-utils'; +import { waitFor, renderHook } from '@testing-library/react'; +import { ALERT_STATUS } from '@kbn/rule-data-utils'; import { useAlertsCount } from './use_alerts_count'; import { KibanaReactContextValue, useKibana } from '@kbn/kibana-react-plugin/public'; @@ -53,7 +53,8 @@ const mockUseKibana = () => { }; describe('useAlertsCount', () => { - const featureIds: ValidFeatureId[] = ['infrastructure']; + const ruleTypeIds = ['metrics.alert.inventory.threshold']; + const consumers = ['foo']; beforeAll(() => { mockUseKibana(); @@ -66,12 +67,12 @@ describe('useAlertsCount', () => { it('should return the mocked data from API', async () => { mockedPostAPI.mockResolvedValue(mockedAlertsCountResponse); - const { result, waitForNextUpdate } = renderHook(() => useAlertsCount({ featureIds })); + const { result } = renderHook(() => useAlertsCount({ ruleTypeIds })); expect(result.current.loading).toBe(true); expect(result.current.alertsCount).toEqual(undefined); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { alertsCount, loading, error } = result.current; expect(alertsCount).toEqual(expectedResult); @@ -88,29 +89,31 @@ describe('useAlertsCount', () => { }; mockedPostAPI.mockResolvedValue(mockedAlertsCountResponse); - const { waitForNextUpdate } = renderHook(() => + renderHook(() => useAlertsCount({ - featureIds, + ruleTypeIds, + consumers, query, }) ); - await waitForNextUpdate(); - const body = JSON.stringify({ aggs: { count: { terms: { field: ALERT_STATUS }, }, }, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, query, size: 0, }); - expect(mockedPostAPI).toHaveBeenCalledWith( - '/internal/rac/alerts/find', - expect.objectContaining({ body }) + await waitFor(() => + expect(mockedPostAPI).toHaveBeenCalledWith( + '/internal/rac/alerts/find', + expect.objectContaining({ body }) + ) ); }); @@ -118,10 +121,8 @@ describe('useAlertsCount', () => { const error = new Error('Fetch Alerts Count Failed'); mockedPostAPI.mockRejectedValueOnce(error); - const { result, waitForNextUpdate } = renderHook(() => useAlertsCount({ featureIds })); - - await waitForNextUpdate(); + const { result } = renderHook(() => useAlertsCount({ ruleTypeIds })); - expect(result.current.error?.message).toMatch(error.message); + await waitFor(() => expect(result.current.error?.message).toMatch(error.message)); }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts index 5c602d09b7d2..aab542d597f9 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_alerts_count.ts @@ -12,17 +12,19 @@ import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common/const import { estypes } from '@elastic/elasticsearch'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import type { HttpSetup } from '@kbn/core/public'; -import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED, ValidFeatureId } from '@kbn/rule-data-utils'; +import { ALERT_STATUS_ACTIVE, ALERT_STATUS_RECOVERED } from '@kbn/rule-data-utils'; import { InfraClientCoreStart } from '../types'; interface UseAlertsCountProps { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; query?: estypes.QueryDslQueryContainer; } interface FetchAlertsCountParams { - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; query?: estypes.QueryDslQueryContainer; http: HttpSetup; signal: AbortSignal; @@ -35,7 +37,7 @@ export interface AlertsCount { const ALERT_STATUS = 'kibana.alert.status'; -export function useAlertsCount({ featureIds, query }: UseAlertsCountProps) { +export function useAlertsCount({ ruleTypeIds, consumers, query }: UseAlertsCountProps) { const { http } = useKibana<InfraClientCoreStart>().services; const abortCtrlRef = useRef(new AbortController()); @@ -45,13 +47,14 @@ export function useAlertsCount({ featureIds, query }: UseAlertsCountProps) { abortCtrlRef.current.abort(); abortCtrlRef.current = new AbortController(); return fetchAlertsCount({ - featureIds, + ruleTypeIds, + consumers, query, http, signal: abortCtrlRef.current.signal, }); }, - [featureIds, query, http], + [ruleTypeIds, query, http], { loading: true } ); @@ -70,7 +73,8 @@ export function useAlertsCount({ featureIds, query }: UseAlertsCountProps) { } async function fetchAlertsCount({ - featureIds, + ruleTypeIds, + consumers, http, query, signal, @@ -84,7 +88,8 @@ async function fetchAlertsCount({ terms: { field: ALERT_STATUS }, }, }, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, query, size: 0, }), diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.test.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.test.ts index 0a619069c04a..5e5f00fd6613 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.test.ts @@ -6,7 +6,7 @@ */ import 'jest-canvas-mock'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useLensAttributes } from './use_lens_attributes'; import { coreMock } from '@kbn/core/public/mocks'; import { type KibanaReactContextValue, useKibana } from '@kbn/kibana-react-plugin/public'; @@ -72,15 +72,15 @@ describe('useLensAttributes hook', () => { }); it('should return the basic lens attributes', async () => { - const { waitForNextUpdate } = renderHook(() => useLensAttributes(params)); - await waitForNextUpdate(); - - expect(LensConfigBuilderMock.mock.instances[0].build).toHaveBeenCalledWith(params); + renderHook(() => useLensAttributes(params)); + await waitFor(() => + expect(LensConfigBuilderMock.mock.instances[0].build).toHaveBeenCalledWith(params) + ); }); it('should return extra actions', async () => { - const { result, waitForNextUpdate } = renderHook(() => useLensAttributes(params)); - await waitForNextUpdate(); + const { result } = renderHook(() => useLensAttributes(params)); + await waitFor(() => new Promise((resolve) => resolve(null))); const extraActions = result.current.getExtraActions({ timeRange: { diff --git a/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.ts b/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.ts index 9e0f9071eb07..b1248a1f05e1 100644 --- a/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/observability_solution/infra/public/hooks/use_lens_attributes.ts @@ -6,7 +6,7 @@ */ import { useCallback } from 'react'; -import { Filter, Query, TimeRange } from '@kbn/es-query'; +import { AggregateQuery, Filter, Query, TimeRange } from '@kbn/es-query'; import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; import { i18n } from '@kbn/i18n'; import useAsync from 'react-use/lib/useAsync'; @@ -37,7 +37,13 @@ export const useLensAttributes = (params: UseLensAttributesParams) => { }, [params, dataViews, lens]); const injectFilters = useCallback( - ({ filters, query }: { filters: Filter[]; query: Query }): LensAttributes | null => { + ({ + filters, + query, + }: { + filters: Filter[]; + query: Query | AggregateQuery; + }): LensAttributes | null => { if (!attributes) { return null; } @@ -63,7 +69,7 @@ export const useLensAttributes = (params: UseLensAttributesParams) => { }: { timeRange: TimeRange; filters: Filter[]; - query: Query; + query: Query | AggregateQuery; searchSessionId?: string; }) => () => { @@ -94,7 +100,7 @@ export const useLensAttributes = (params: UseLensAttributesParams) => { }: { timeRange: TimeRange; filters?: Filter[]; - query?: Query; + query?: Query | AggregateQuery; searchSessionId?: string; }) => { const openInLens = getOpenInLensAction( diff --git a/x-pack/plugins/observability_solution/infra/public/pages/link_to/use_host_ip_to_name.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/link_to/use_host_ip_to_name.test.ts index 150416a204b0..2a9d56a6f4df 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/link_to/use_host_ip_to_name.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/link_to/use_host_ip_to_name.test.ts @@ -6,7 +6,7 @@ */ import { useHostIpToName } from './use_host_ip_to_name'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; const renderUseHostIpToNameHook = () => renderHook((props) => useHostIpToName(props.ipAddress, props.indexPattern), { @@ -32,10 +32,10 @@ jest.mock('@kbn/kibana-react-plugin/public', () => { describe('useHostIpToName Hook', () => { it('should basically work', async () => { mockedFetch.mockResolvedValue({ host: 'example-01' } as any); - const { result, waitForNextUpdate } = renderUseHostIpToNameHook(); + const { result } = renderUseHostIpToNameHook(); expect(result.current.name).toBe(null); expect(result.current.loading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.name).toBe('example-01'); expect(result.current.loading).toBe(false); expect(result.current.error).toBe(null); @@ -44,10 +44,10 @@ describe('useHostIpToName Hook', () => { it('should handle errors', async () => { const error = new Error('Host not found'); mockedFetch.mockRejectedValue(error); - const { result, waitForNextUpdate } = renderUseHostIpToNameHook(); + const { result } = renderUseHostIpToNameHook(); expect(result.current.name).toBe(null); expect(result.current.loading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.name).toBe(null); expect(result.current.loading).toBe(false); expect(result.current.error).toBe(error); @@ -56,16 +56,16 @@ describe('useHostIpToName Hook', () => { it('should reset errors', async () => { const error = new Error('Host not found'); mockedFetch.mockRejectedValue(error); - const { result, waitForNextUpdate, rerender } = renderUseHostIpToNameHook(); + const { result, rerender } = renderUseHostIpToNameHook(); expect(result.current.name).toBe(null); expect(result.current.loading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.name).toBe(null); expect(result.current.loading).toBe(false); expect(result.current.error).toBe(error); mockedFetch.mockResolvedValue({ host: 'example-01' } as any); rerender({ ipAddress: '192.168.1.2', indexPattern: 'metricbeat-*' }); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.name).toBe('example-01'); expect(result.current.loading).toBe(false); expect(result.current.error).toBe(null); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx b/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx index 8f42b4cf1bc6..0e16a404cbd5 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/logs/settings/indices_configuration_panel.tsx @@ -19,7 +19,7 @@ import { import { EuiCallOut } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { loadRuleAggregations } from '@kbn/triggers-actions-ui-plugin/public'; -import { LOG_THRESHOLD_ALERT_TYPE_ID } from '@kbn/rule-data-utils'; +import { AlertConsumers, LOG_THRESHOLD_ALERT_TYPE_ID } from '@kbn/rule-data-utils'; import { rulesLocatorID, RulesParams } from '@kbn/observability-plugin/public'; import { EuiLink } from '@elastic/eui'; @@ -93,7 +93,8 @@ export const IndicesConfigurationPanel = React.memo<{ if (http) { const { ruleExecutionStatus } = await loadRuleAggregations({ http, - typesFilter: [LOG_THRESHOLD_ALERT_TYPE_ID], + ruleTypeIds: [LOG_THRESHOLD_ALERT_TYPE_ID], + consumers: [AlertConsumers.LOGS, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], }); const numberOfRules = Object.values(ruleExecutionStatus).reduce( (acc, value) => acc + value, diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx index a3926b95383d..7b0ec7ed2d2f 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts/alerts_tab_content.tsx @@ -6,11 +6,16 @@ */ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { AlertConsumers, ALERT_RULE_PRODUCER } from '@kbn/rule-data-utils'; +import { + AlertConsumers, + INFRA_RULE_TYPE_IDS, + OBSERVABILITY_RULE_TYPE_IDS, +} from '@kbn/rule-data-utils'; import { BrushEndListener, type XYBrushEvent } from '@elastic/charts'; import { useSummaryTimeRange } from '@kbn/observability-plugin/public'; import { useBoolean } from '@kbn/react-hooks'; import type { TimeRange } from '@kbn/es-query'; +import { INFRA_ALERT_CONSUMERS } from '../../../../../../../common/constants'; import { useKibanaContextForPlugin } from '../../../../../../hooks/use_kibana'; import { HeightRetainer } from '../../../../../../components/height_retainer'; import { useUnifiedSearchContext } from '../../../hooks/use_unified_search'; @@ -20,18 +25,18 @@ import { AlertsEsQuery } from '../../../../../../utils/filters/create_alerts_es_ import { ALERTS_PER_PAGE, ALERTS_TABLE_ID, - infraAlertFeatureIds, } from '../../../../../../components/shared/alerts/constants'; import AlertsStatusFilter from '../../../../../../components/shared/alerts/alerts_status_filter'; import { CreateAlertRuleButton } from '../../../../../../components/shared/alerts/links/create_alert_rule_button'; import { LinkToAlertsPage } from '../../../../../../components/shared/alerts/links/link_to_alerts_page'; -import { INFRA_ALERT_FEATURE_ID } from '../../../../../../../common/constants'; import { AlertFlyout } from '../../../../../../alerting/inventory/components/alert_flyout'; import { usePluginConfig } from '../../../../../../containers/plugin_config_context'; +import { useHostsViewContext } from '../../../hooks/use_hosts_view'; export const AlertsTabContent = () => { const { services } = useKibanaContextForPlugin(); const { featureFlags } = usePluginConfig(); + const { hostNodes } = useHostsViewContext(); const { alertStatus, setAlertStatus, alertsEsQueryByStatus } = useAlertsQuery(); const [isAlertFlyoutVisible, { toggle: toggleAlertFlyout }] = useBoolean(false); @@ -43,6 +48,11 @@ export const AlertsTabContent = () => { const { alertsTableConfigurationRegistry, getAlertsStateTable: AlertsStateTable } = triggersActionsUi; + const hostsWithAlertsKuery = hostNodes + .filter((host) => host.alertsCount) + .map((host) => `"${host.name}"`) + .join(' OR '); + return ( <HeightRetainer> <EuiFlexGroup direction="column" gutterSize="m" data-test-subj="hostsView-alerts"> @@ -63,7 +73,7 @@ export const AlertsTabContent = () => { <LinkToAlertsPage dateRange={searchCriteria.dateRange} data-test-subj="infraHostAlertsTabAlertsShowAllButton" - kuery={`${ALERT_RULE_PRODUCER}: ${INFRA_ALERT_FEATURE_ID}`} + kuery={`${hostsWithAlertsKuery}`} /> </EuiFlexItem> </EuiFlexGroup> @@ -80,7 +90,8 @@ export const AlertsTabContent = () => { <AlertsStateTable alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} configurationId={AlertConsumers.OBSERVABILITY} - featureIds={infraAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS} + consumers={INFRA_ALERT_CONSUMERS} id={ALERTS_TABLE_ID} initialPageSize={ALERTS_PER_PAGE} query={alertsEsQueryByStatus} @@ -135,7 +146,8 @@ const MemoAlertSummaryWidget = React.memo( return ( <AlertSummaryWidget chartProps={chartProps} - featureIds={infraAlertFeatureIds} + ruleTypeIds={INFRA_RULE_TYPE_IDS} + consumers={INFRA_ALERT_CONSUMERS} filter={alertsQuery} fullSize timeRange={summaryTimeRange} diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts_tab_badge.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts_tab_badge.tsx index c2361ce39dfe..9647d7a47583 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts_tab_badge.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/components/tabs/alerts_tab_badge.tsx @@ -7,15 +7,17 @@ import React from 'react'; import { EuiIcon, EuiLoadingSpinner, EuiBadge, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { INFRA_ALERT_CONSUMERS } from '../../../../../../common/constants'; +import { INFRA_RULE_TYPE_IDS } from '../../../../../../common/alerting/metrics/types'; import { useAlertsCount } from '../../../../../hooks/use_alerts_count'; import { useAlertsQuery } from '../../hooks/use_alerts_query'; -import { infraAlertFeatureIds } from '../../../../../components/shared/alerts/constants'; export const AlertsTabBadge = () => { const { alertsEsQuery } = useAlertsQuery(); const { alertsCount, loading, error } = useAlertsCount({ - featureIds: infraAlertFeatureIds, + ruleTypeIds: INFRA_RULE_TYPE_IDS, + consumers: INFRA_ALERT_CONSUMERS, query: alertsEsQuery, }); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts index a0ebb2018491..abae2d5cadbf 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_hosts_table.test.ts @@ -6,7 +6,7 @@ */ import { type HostNodeRow, useHostsTable } from './use_hosts_table'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { InfraAssetMetricsItem } from '../../../../../common/http_api'; import * as useUnifiedSearchHooks from './use_unified_search'; import * as useHostsViewHooks from './use_hosts_view'; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_metrics_charts.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_metrics_charts.test.ts index b76d5938f0cb..9d68b3ff76e7 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_metrics_charts.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/hosts/hooks/use_metrics_charts.test.ts @@ -6,16 +6,14 @@ */ import type { LensSeriesLayer } from '@kbn/lens-embeddable-utils/config_builder'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { PAGE_SIZE_OPTIONS } from '../constants'; import { useMetricsCharts } from './use_metrics_charts'; describe('useMetricsCharts', () => { it('should return an array of charts with breakdown config', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useMetricsCharts({ dataViewId: 'dataViewId' }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => useMetricsCharts({ dataViewId: 'dataViewId' })); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current).toHaveLength(11); @@ -29,10 +27,8 @@ describe('useMetricsCharts', () => { }); it('should return an array of charts with correct order', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useMetricsCharts({ dataViewId: 'dataViewId' }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => useMetricsCharts({ dataViewId: 'dataViewId' })); + await waitFor(() => new Promise((resolve) => resolve(null))); const expectedOrder = [ 'cpuUsage', diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts index 7fe7b8b3fe18..533857130b11 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_filters.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { DataView } from '@kbn/data-views-plugin/common'; import { useWaffleFilters, WaffleFiltersState } from './use_waffle_filters'; import { TIMESTAMP_FIELD } from '../../../../../common/constants'; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts index 50f4e95b58a3..757a0e955b4d 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/inventory_view/hooks/use_waffle_options.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useWaffleOptions, WaffleOptionsState } from './use_waffle_options'; diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx index bcea796c3b00..0e70071f199f 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metric_explorer_state.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useMetricsExplorerState } from './use_metric_explorer_state'; import { MetricsExplorerOptionsContainer } from './use_metrics_explorer_options'; import React from 'react'; @@ -75,6 +75,10 @@ describe('useMetricsExplorerState', () => { delete STORE.MetricsExplorerTimeRange; }); + afterEach(() => { + jest.clearAllMocks(); + }); + it('should just work', async () => { mockedUseMetricsExplorerData.mockReturnValue({ isLoading: false, @@ -92,12 +96,14 @@ describe('useMetricsExplorerState', () => { describe('handleRefresh', () => { it('should trigger an addition request when handleRefresh is called', async () => { const { result } = renderUseMetricsExplorerStateHook(); - expect(result.all.length).toBe(2); - const numberOfHookCalls = result.all.length; + + const numberOfHookCalls = mockedUseMetricsExplorerData.mock.calls.length; + + expect(numberOfHookCalls).toEqual(2); act(() => { result.current.refresh(); }); - expect(result.all.length).toBe(numberOfHookCalls + 1); + expect(mockedUseMetricsExplorerData).toHaveBeenCalledTimes(numberOfHookCalls + 1); }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx index 202ae51990ad..8cc6bff922d9 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_data.test.tsx @@ -9,7 +9,7 @@ import React, { FC, PropsWithChildren } from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useMetricsExplorerData } from './use_metrics_explorer_data'; import { DataView } from '@kbn/data-views-plugin/common'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, act, renderHook } from '@testing-library/react'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { @@ -108,15 +108,14 @@ describe('useMetricsExplorerData Hook', () => { it('should just work', async () => { mockedFetch.mockResolvedValue(resp); - const { result, waitForNextUpdate } = renderUseMetricsExplorerDataHook(); + const { result } = renderUseMetricsExplorerDataHook(); expect(result.current.data).toBeUndefined(); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); const { series } = result.current.data!.pages[0]; expect(series).toBeDefined(); expect(series.length).toBe(3); @@ -124,12 +123,11 @@ describe('useMetricsExplorerData Hook', () => { it('should paginate', async () => { mockedFetch.mockResolvedValue(resp); - const { result, waitForNextUpdate } = renderUseMetricsExplorerDataHook(); + const { result } = renderUseMetricsExplorerDataHook(); expect(result.current.data).toBeUndefined(); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); const { series } = result.current.data!.pages[0]; expect(series).toBeDefined(); expect(series.length).toBe(3); @@ -137,41 +135,45 @@ describe('useMetricsExplorerData Hook', () => { pageInfo: { total: 10, afterKey: 'host-06' }, series: [createSeries('host-04'), createSeries('host-05'), createSeries('host-06')], } as any); - result.current.fetchNextPage(); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(false); - const { series: nextSeries } = result.current.data!.pages[1]; - expect(nextSeries).toBeDefined(); - expect(nextSeries.length).toBe(3); + await act(async () => { + await result.current.fetchNextPage(); + }); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + const { series: nextSeries } = result.current.data!.pages[1]; + expect(nextSeries).toBeDefined(); + expect(nextSeries.length).toBe(3); + }); }); it('should reset error upon recovery', async () => { const error = new Error('Network Error'); mockedFetch.mockRejectedValue(error); - const { result, waitForNextUpdate } = renderUseMetricsExplorerDataHook(); + const { result } = renderUseMetricsExplorerDataHook(); expect(result.current.data).toBeUndefined(); expect(result.current.error).toEqual(null); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.data).toBeUndefined(); expect(result.current.error).toEqual(error); - expect(result.current.isLoading).toBe(false); mockedFetch.mockResolvedValue(resp as any); - result.current.refetch(); - await waitForNextUpdate(); - expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); - expect(result.current.error).toBe(null); + await act(async () => { + await result.current.refetch(); + }); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.data!.pages[0]).toEqual(resp); + expect(result.current.error).toBe(null); + }); }); it('should not paginate on option change', async () => { mockedFetch.mockResolvedValue(resp as any); - const { result, waitForNextUpdate, rerender } = renderUseMetricsExplorerDataHook(); + const { result, rerender } = renderUseMetricsExplorerDataHook(); expect(result.current.data).toBeUndefined(); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); const { series } = result.current.data!.pages[0]; expect(series).toBeDefined(); expect(series.length).toBe(3); @@ -187,19 +189,19 @@ describe('useMetricsExplorerData Hook', () => { timestamps, }); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); - expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.data!.pages[0]).toEqual(resp); + }); }); it('should not paginate on time change', async () => { mockedFetch.mockResolvedValue(resp as any); - const { result, waitForNextUpdate, rerender } = renderUseMetricsExplorerDataHook(); + const { result, rerender } = renderUseMetricsExplorerDataHook(); expect(result.current.data).toBeUndefined(); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toBe(false)); expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); const { series } = result.current.data!.pages[0]; expect(series).toBeDefined(); expect(series.length).toBe(3); @@ -211,8 +213,9 @@ describe('useMetricsExplorerData Hook', () => { timestamps: { fromTimestamp: 1678378092225, toTimestamp: 1678381693477, interval: '>=10s' }, }); expect(result.current.isLoading).toBe(true); - await waitForNextUpdate(); - expect(result.current.data!.pages[0]).toEqual(resp); - expect(result.current.isLoading).toBe(false); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.data!.pages[0]).toEqual(resp); + }); }); }); diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx index 795728fa8d8e..f5c257e1f86a 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useMetricsExplorerOptions, MetricsExplorerOptions, diff --git a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx index 8deaa805ba9b..328ef4680680 100644 --- a/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx +++ b/x-pack/plugins/observability_solution/infra/public/pages/metrics/settings/source_configuration_settings.tsx @@ -20,6 +20,7 @@ import { import { loadRuleAggregations } from '@kbn/triggers-actions-ui-plugin/public'; import { HttpSetup } from '@kbn/core-http-browser'; import { + AlertConsumers, METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, METRIC_THRESHOLD_ALERT_TYPE_ID, } from '@kbn/rule-data-utils'; @@ -56,7 +57,12 @@ export const SourceConfigurationSettings = ({ if (http) { const { ruleExecutionStatus } = await loadRuleAggregations({ http, - typesFilter: [METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, METRIC_THRESHOLD_ALERT_TYPE_ID], + ruleTypeIds: [METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, METRIC_THRESHOLD_ALERT_TYPE_ID], + consumers: [ + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.ALERTS, + AlertConsumers.OBSERVABILITY, + ], }); const numberOfRules = Object.values(ruleExecutionStatus).reduce( (acc, value) => acc + value, diff --git a/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_data_search_request.test.tsx b/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_data_search_request.test.tsx index 33369c1125e1..08907b162708 100644 --- a/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_data_search_request.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_data_search_request.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import React from 'react'; import { firstValueFrom, Observable, of, Subject } from 'rxjs'; import type { ISearchGeneric, IKibanaSearchResponse } from '@kbn/search-types'; diff --git a/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_latest_partial_data_search_response.test.tsx b/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_latest_partial_data_search_response.test.tsx index a4b01be03d80..24433f23bc67 100644 --- a/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_latest_partial_data_search_response.test.tsx +++ b/x-pack/plugins/observability_solution/infra/public/utils/data_search/use_latest_partial_data_search_response.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { BehaviorSubject, Observable, of, Subject } from 'rxjs'; import { IKibanaSearchRequest } from '@kbn/search-types'; import { ParsedDataSearchRequestDescriptor, ParsedKibanaSearchResponse } from './types'; diff --git a/x-pack/plugins/observability_solution/infra/server/features.ts b/x-pack/plugins/observability_solution/infra/server/features.ts index b2f83967920e..77fb8d317fef 100644 --- a/x-pack/plugins/observability_solution/infra/server/features.ts +++ b/x-pack/plugins/observability_solution/infra/server/features.ts @@ -14,6 +14,7 @@ import { } from '@kbn/rule-data-utils'; import { ES_QUERY_ID } from '@kbn/rule-data-utils'; import { metricsDataSourceSavedObjectName } from '@kbn/metrics-data-access-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { LOG_DOCUMENT_COUNT_RULE_TYPE_ID } from '../common/alerting/logs/log_threshold/types'; import { @@ -31,6 +32,11 @@ const metricRuleTypes = [ ML_ANOMALY_DETECTION_RULE_TYPE_ID, ]; +const metricAlertingFeatures = metricRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [METRICS_FEATURE_ID, ALERTING_FEATURE_ID], +})); + export const METRICS_FEATURE = { id: METRICS_FEATURE_ID, name: i18n.translate('xpack.infra.featureRegistry.linkInfrastructureTitle', { @@ -44,7 +50,7 @@ export const METRICS_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: metricRuleTypes, + alerting: metricAlertingFeatures, privileges: { all: { app: ['infra', 'metrics', 'kibana'], @@ -56,10 +62,10 @@ export const METRICS_FEATURE = { }, alerting: { rule: { - all: metricRuleTypes, + all: metricAlertingFeatures, }, alert: { - all: metricRuleTypes, + all: metricAlertingFeatures, }, }, management: { @@ -77,10 +83,10 @@ export const METRICS_FEATURE = { }, alerting: { rule: { - read: metricRuleTypes, + read: metricAlertingFeatures, }, alert: { - read: metricRuleTypes, + read: metricAlertingFeatures, }, }, management: { @@ -98,6 +104,11 @@ const logsRuleTypes = [ ML_ANOMALY_DETECTION_RULE_TYPE_ID, ]; +const logsAlertingFeatures = logsRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [LOGS_FEATURE_ID, ALERTING_FEATURE_ID], +})); + export const LOGS_FEATURE = { id: LOGS_FEATURE_ID, name: i18n.translate('xpack.infra.featureRegistry.linkLogsTitle', { @@ -111,7 +122,7 @@ export const LOGS_FEATURE = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: logsRuleTypes, + alerting: logsAlertingFeatures, privileges: { all: { app: ['infra', 'logs', 'kibana', 'observability-logs-explorer'], @@ -123,10 +134,10 @@ export const LOGS_FEATURE = { }, alerting: { rule: { - all: logsRuleTypes, + all: logsAlertingFeatures, }, alert: { - all: logsRuleTypes, + all: logsAlertingFeatures, }, }, management: { @@ -140,10 +151,10 @@ export const LOGS_FEATURE = { api: ['infra', 'rac'], alerting: { rule: { - read: logsRuleTypes, + read: logsAlertingFeatures, }, alert: { - read: logsRuleTypes, + read: logsAlertingFeatures, }, }, management: { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts index b8dd11a17fb0..3ee4f9632b35 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/adapters/framework/adapter_types.ts @@ -20,7 +20,7 @@ import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { VisTypeTimeseriesSetup } from '@kbn/vis-type-timeseries-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; -import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; import { RuleRegistryPluginSetupContract, @@ -46,7 +46,7 @@ import type { } from '@kbn/entityManager-plugin/server'; export interface InfraServerPluginSetupDeps { - alerting: AlertingPluginContract; + alerting: AlertingServerSetup; data: DataPluginSetup; home: HomeServerPluginSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts index 7b69d76ba0ce..f85738248a9c 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_rule_type.ts @@ -8,7 +8,7 @@ import { schema, Type } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; -import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import { GetViewInAppRelativeUrlFnOpts, AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { TimeUnitChar } from '@kbn/observability-plugin/common/utils/formatters/duration'; import { @@ -81,7 +81,7 @@ const groupActionVariableDescription = i18n.translate( ); export function registerInventoryThresholdRuleType( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, { featureFlags }: InfraConfig, locators: InfraLocators diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts index decac47dbb5f..d4eb9050499c 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/log_threshold/register_log_threshold_rule_type.ts @@ -7,7 +7,10 @@ import { i18n } from '@kbn/i18n'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; -import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { + GetViewInAppRelativeUrlFnOpts, + AlertingServerSetup, +} from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { decodeOrThrow } from '@kbn/io-ts-utils'; import type { InfraConfig } from '../../../../common/plugin_config_types'; @@ -103,7 +106,7 @@ const viewInAppUrlActionVariableDescription = i18n.translate( ); export function registerLogThresholdRuleType( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, { featureFlags }: InfraConfig ) { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 9777f7ceda47..4227ff10ad90 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -102,6 +102,7 @@ const mockOptions = { const date = STARTED_AT_MOCK_DATE.toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }; const setEvaluationResults = (response: Array<Record<string, Evaluation>>) => { diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts index 6369465773cf..3cc272a02c7f 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/metric_threshold/register_metric_threshold_rule_type.ts @@ -8,7 +8,10 @@ import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { i18n } from '@kbn/i18n'; -import { GetViewInAppRelativeUrlFnOpts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { + GetViewInAppRelativeUrlFnOpts, + AlertingServerSetup, +} from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import { COMPARATORS } from '@kbn/alerting-comparators'; import { LEGACY_COMPARATORS } from '@kbn/observability-plugin/common/utils/convert_legacy_outside_comparator'; @@ -46,7 +49,7 @@ import { MetricsRulesTypeAlertDefinition } from '../register_rule_types'; import { O11Y_AAD_FIELDS } from '../../../../common/constants'; export function registerMetricThresholdRuleType( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, { featureFlags }: InfraConfig, locators: InfraLocators diff --git a/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts b/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts index 125c3135a235..6d06c2c98607 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/alerting/register_rule_types.ts @@ -6,7 +6,7 @@ */ import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; -import { type IRuleTypeAlerts, PluginSetupContract } from '@kbn/alerting-plugin/server'; +import { type IRuleTypeAlerts, AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { registerMetricThresholdRuleType } from './metric_threshold/register_metric_threshold_rule_type'; import { registerInventoryThresholdRuleType } from './inventory_metric_threshold/register_inventory_metric_threshold_rule_type'; import { registerLogThresholdRuleType } from './log_threshold/register_log_threshold_rule_type'; @@ -36,7 +36,7 @@ export const MetricsRulesTypeAlertDefinition: IRuleTypeAlerts<MetricThresholdAle }; const registerRuleTypes = ( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, libs: InfraBackendLibs, config: InfraConfig, locators: InfraLocators diff --git a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_apm_data_access_client.ts b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_apm_data_access_client.ts index dcf63e01b7e9..e99d57eb4d6c 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_apm_data_access_client.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_apm_data_access_client.ts @@ -27,17 +27,23 @@ export const getApmDataAccessClient = ({ context: InfraPluginRequestHandlerContext; request: KibanaRequest; }) => { + const hasPrivileges = async () => { + const apmDataAccessStart = await libs.plugins.apmDataAccess.start(); + return apmDataAccessStart.hasPrivileges({ request }); + }; + const getServices = async () => { const apmDataAccess = libs.plugins.apmDataAccess.setup; const coreContext = await context.core; - const { uiSettings, elasticsearch } = coreContext; + const { savedObjects, uiSettings, elasticsearch } = coreContext; + const savedObjectsClient = savedObjects.client; const esClient = elasticsearch.client.asCurrentUser; const uiSettingsClient = uiSettings.client; const [apmIndices, includeFrozen] = await Promise.all([ - apmDataAccess.getApmIndices(), + apmDataAccess.getApmIndices(savedObjectsClient), uiSettingsClient.get<boolean>(UI_SETTINGS.SEARCH_INCLUDE_FROZEN), ]); @@ -80,5 +86,5 @@ export const getApmDataAccessClient = ({ }; }; - return { getServices }; + return { hasPrivileges, getServices }; }; diff --git a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts index 58dfdde223eb..99464efd0256 100644 --- a/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts +++ b/x-pack/plugins/observability_solution/infra/server/lib/helpers/get_infra_alerts_client.ts @@ -8,6 +8,7 @@ import { isEmpty } from 'lodash'; import type { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import type { KibanaRequest } from '@kbn/core/server'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import type { InfraBackendLibs } from '../infra_types'; type RequiredParams = ESSearchRequest & { @@ -26,7 +27,9 @@ export async function getInfraAlertsClient({ }) { const [, { ruleRegistry }] = await libs.getStartServices(); const alertsClient = await ruleRegistry.getRacClientWithRequest(request); - const infraAlertsIndices = await alertsClient.getAuthorizedAlertsIndices(['infrastructure']); + const infraAlertsIndices = await alertsClient.getAuthorizedAlertsIndices( + OBSERVABILITY_RULE_TYPE_IDS + ); if (!infraAlertsIndices || isEmpty(infraAlertsIndices)) { throw Error('No alert indices exist for "infrastructure"'); diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts index c109f53be1f1..c7669e6f9acd 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/get_latest_entity.ts @@ -44,18 +44,25 @@ export async function getLatestEntity({ return undefined; } - const response = await inventoryEsClient.esql<{ - source_data_stream?: { type?: string | string[] }; - }>('get_latest_entities', { - query: `FROM ${ENTITIES_LATEST_ALIAS} + const response = await inventoryEsClient.esql< + { + 'source_data_stream.type'?: string | string; + }, + { transform: 'plain' } + >( + 'get_latest_entities', + { + query: `FROM ${ENTITIES_LATEST_ALIAS} | WHERE ${ENTITY_TYPE} == ? | WHERE ${hostOrContainerIdentityField} == ? | KEEP ${SOURCE_DATA_STREAM_TYPE} `, - params: [entityType, entityId], - }); + params: [entityType, entityId], + }, + { transform: 'plain' } + ); - return { sourceDataStreamType: response[0].source_data_stream?.type }; + return { sourceDataStreamType: response.hits[0]['source_data_stream.type'] }; } catch (e) { logger.error(e); } diff --git a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts index 46f2cecf4525..4056faba9427 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/entities/index.ts @@ -9,7 +9,7 @@ import { schema } from '@kbn/config-schema'; import { METRICS_APP_ID } from '@kbn/deeplinks-observability/constants'; import { entityCentricExperience } from '@kbn/observability-plugin/common'; import { createObservabilityEsClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; -import { ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; +import { BUILT_IN_ENTITY_TYPES } from '@kbn/observability-shared-plugin/common'; import { getInfraMetricsClient } from '../../lib/helpers/get_infra_metrics_client'; import { InfraBackendLibs } from '../../lib/infra_types'; import { getDataStreamTypes } from './get_data_stream_types'; @@ -24,8 +24,8 @@ export const initEntitiesConfigurationRoutes = (libs: InfraBackendLibs) => { validate: { params: schema.object({ entityType: schema.oneOf([ - schema.literal(ENTITY_TYPES.HOST), - schema.literal(ENTITY_TYPES.CONTAINER), + schema.literal(BUILT_IN_ENTITY_TYPES.HOST), + schema.literal(BUILT_IN_ENTITY_TYPES.CONTAINER), ]), entityId: schema.string(), }), diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts index 3f91a034c810..1b720eeb3186 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/index.ts @@ -41,11 +41,12 @@ export const initInfraAssetRoutes = (libs: InfraBackendLibs) => { try { const apmDataAccessClient = getApmDataAccessClient({ request, libs, context }); + const hasApmPrivileges = await apmDataAccessClient.hasPrivileges(); const [infraMetricsClient, alertsClient, apmDataAccessServices] = await Promise.all([ getInfraMetricsClient({ request, libs, context }), getInfraAlertsClient({ libs, request }), - apmDataAccessClient.getServices(), + hasApmPrivileges ? apmDataAccessClient.getServices() : undefined, ]); const hosts = await getHosts({ @@ -96,10 +97,11 @@ export const initInfraAssetRoutes = (libs: InfraBackendLibs) => { try { const apmDataAccessClient = getApmDataAccessClient({ request, libs, context }); + const hasApmPrivileges = await apmDataAccessClient.hasPrivileges(); const [infraMetricsClient, apmDataAccessServices] = await Promise.all([ getInfraMetricsClient({ request, libs, context }), - apmDataAccessClient.getServices(), + hasApmPrivileges ? apmDataAccessClient.getServices() : undefined, ]); const count = await getHostsCount({ diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts index 52da69cd7c00..570c1499f3b7 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/helpers/query.ts @@ -9,7 +9,6 @@ import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common'; import { termQuery } from '@kbn/observability-plugin/server'; import { ApmDocumentType, type TimeRangeMetadata } from '@kbn/apm-data-access-plugin/common'; import { estypes } from '@elastic/elasticsearch'; -import { castArray } from 'lodash'; import type { ApmDataAccessServicesWrapper } from '../../../../lib/helpers/get_apm_data_access_client'; import { EVENT_MODULE, @@ -18,16 +17,12 @@ import { } from '../../../../../common/constants'; import type { InfraAssetMetricType } from '../../../../../common/http_api/infra'; -export const getFilterByIntegration = ( - integration: typeof SYSTEM_INTEGRATION, - extraFilter: estypes.QueryDslQueryContainer[] = [] -) => { +export const getFilterByIntegration = (integration: typeof SYSTEM_INTEGRATION) => { return { bool: { should: [ ...termQuery(EVENT_MODULE, integration), ...termQuery(METRICSET_MODULE, integration), - ...extraFilter, ], minimum_should_match: 1, }, @@ -68,6 +63,7 @@ export const getDocumentsFilter = async ({ from: number; to: number; }) => { + const filters: estypes.QueryDslQueryContainer[] = [getFilterByIntegration('system')]; const apmDocumentsFilter = apmDataAccessServices && apmDocumentSources ? await getApmDocumentsFilter({ @@ -78,9 +74,9 @@ export const getDocumentsFilter = async ({ }) : undefined; - const filters: estypes.QueryDslQueryContainer[] = [ - getFilterByIntegration('system', apmDocumentsFilter && castArray(apmDocumentsFilter)), - ]; + if (apmDocumentsFilter) { + filters.push(apmDocumentsFilter); + } return filters; }; diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts index 63fef5d438b0..bb5bd51cfe1f 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts.ts @@ -49,7 +49,6 @@ export const getHosts = async ({ const [hostMetricsResponse, alertsCountResponse] = await Promise.all([ getAllHosts({ infraMetricsClient, - apmDataAccessServices, apmDocumentSources, from, to, diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts index c3d8f0f674d5..dbb1a3c2ceb6 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_alerts_count.ts @@ -6,14 +6,13 @@ */ import { termQuery, termsQuery } from '@kbn/observability-plugin/server'; -import { observabilityFeatureId } from '@kbn/observability-shared-plugin/common'; import { ALERT_RULE_PRODUCER, ALERT_STATUS, ALERT_STATUS_ACTIVE, ALERT_UUID, } from '@kbn/rule-data-utils'; -import { HOST_NAME_FIELD, INFRA_ALERT_FEATURE_ID } from '../../../../../common/constants'; +import { HOST_NAME_FIELD, INFRA_ALERT_CONSUMERS } from '../../../../../common/constants'; import { GetHostParameters } from '../types'; export async function getHostsAlertsCount({ @@ -41,7 +40,7 @@ export async function getHostsAlertsCount({ query: { bool: { filter: [ - ...termsQuery(ALERT_RULE_PRODUCER, INFRA_ALERT_FEATURE_ID, observabilityFeatureId), + ...termsQuery(ALERT_RULE_PRODUCER, ...INFRA_ALERT_CONSUMERS), ...termQuery(ALERT_STATUS, ALERT_STATUS_ACTIVE), ...termsQuery(HOST_NAME_FIELD, ...hostNames), ...rangeQuery, diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts index e36811ea5b87..154fd8796520 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/host/get_hosts_count.ts @@ -25,14 +25,8 @@ export async function getHostsCount({ }) { assertQueryStructure(query); - const apmDocumentSources = await apmDataAccessServices?.getDocumentSources({ - start: from, - end: to, - }); - const documentsFilter = await getDocumentsFilter({ apmDataAccessServices, - apmDocumentSources, from, to, }); @@ -45,7 +39,7 @@ export async function getHostsCount({ query: { bool: { filter: [query, ...rangeQuery(from, to)], - must: [...documentsFilter], + should: [...documentsFilter], }, }, aggs: { diff --git a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts index 8f50d9eb89f1..87679f24271d 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/infra/lib/types.ts @@ -13,5 +13,5 @@ import { InfraMetricsClient } from '../../../lib/helpers/get_infra_metrics_clien export interface GetHostParameters extends GetInfraMetricsRequestBodyPayload { infraMetricsClient: InfraMetricsClient; alertsClient: InfraAlertsClient; - apmDataAccessServices: ApmDataAccessServicesWrapper; + apmDataAccessServices?: ApmDataAccessServicesWrapper; } diff --git a/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts b/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts index bc6ce91e830a..9673b3178848 100644 --- a/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts +++ b/x-pack/plugins/observability_solution/infra/server/routes/services/index.ts @@ -36,6 +36,16 @@ export const initServicesRoute = (libs: InfraBackendLibs) => { const { from, to, size = 10, validatedFilters } = request.query; const apmDataAccessClient = getApmDataAccessClient({ request, libs, context }); + const hasApmPrivileges = await apmDataAccessClient.hasPrivileges(); + + if (!hasApmPrivileges) { + return response.customError({ + statusCode: 403, + body: { + message: 'APM data access service is not available', + }, + }); + } const apmDataAccessServices = await apmDataAccessClient.getServices(); diff --git a/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts b/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts index 68ae0bd95b41..ee2d5967b081 100644 --- a/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts +++ b/x-pack/plugins/observability_solution/infra/server/services/rules/types.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { IRuleDataClient, RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; export interface RulesServiceSetupDeps { - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; ruleRegistry: RuleRegistryPluginSetupContract; } diff --git a/x-pack/plugins/observability_solution/inventory/common/entities.ts b/x-pack/plugins/observability_solution/inventory/common/entities.ts index 65fd8a4ffbd7..b006fa0c7f6d 100644 --- a/x-pack/plugins/observability_solution/inventory/common/entities.ts +++ b/x-pack/plugins/observability_solution/inventory/common/entities.ts @@ -5,8 +5,6 @@ * 2.0. */ import { ENTITY_LATEST, entitiesAliasPattern, type EntityMetadata } from '@kbn/entities-schema'; -import { decode, encode } from '@kbn/rison'; -import { isRight } from 'fp-ts/lib/Either'; import * as t from 'io-ts'; export const entityColumnIdsRt = t.union([ @@ -19,49 +17,6 @@ export const entityColumnIdsRt = t.union([ export type EntityColumnIds = t.TypeOf<typeof entityColumnIdsRt>; -export const entityViewRt = t.union([t.literal('unified'), t.literal('grouped')]); - -const paginationRt = t.record(t.string, t.number); -export const entityPaginationRt = new t.Type<Record<string, number> | undefined, string, unknown>( - 'entityPaginationRt', - paginationRt.is, - (input, context) => { - switch (typeof input) { - case 'string': { - try { - const decoded = decode(input); - const validation = paginationRt.decode(decoded); - if (isRight(validation)) { - return t.success(validation.right); - } - - return t.failure(input, context); - } catch (e) { - return t.failure(input, context); - } - } - - case 'undefined': - return t.success(input); - - default: { - const validation = paginationRt.decode(input); - - if (isRight(validation)) { - return t.success(validation.right); - } - - return t.failure(input, context); - } - } - }, - (o) => encode(o) -); - -export type EntityView = t.TypeOf<typeof entityViewRt>; - -export type EntityPagination = t.TypeOf<typeof entityPaginationRt>; - export const defaultEntitySortField: EntityColumnIds = 'alertsCount'; export const MAX_NUMBER_OF_ENTITIES = 500; diff --git a/x-pack/plugins/observability_solution/inventory/common/rt_types.ts b/x-pack/plugins/observability_solution/inventory/common/rt_types.ts new file mode 100644 index 000000000000..17496d672e61 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/common/rt_types.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { decode, encode } from '@kbn/rison'; +import { isRight } from 'fp-ts/lib/Either'; +import * as t from 'io-ts'; + +const validate = (validationRt: t.Any) => (input: unknown, context: t.Context) => { + switch (typeof input) { + case 'string': { + try { + const decoded = decode(input); + const validation = validationRt.decode(decoded); + if (isRight(validation)) { + return t.success(validation.right); + } + + return t.failure(input, context); + } catch (e) { + return t.failure(input, context); + } + } + + case 'undefined': + return t.success(input); + + default: { + const validation = validationRt.decode(input); + + if (isRight(validation)) { + return t.success(validation.right); + } + + return t.failure(input, context); + } + } +}; + +const entityTypeCheckOptions = t.union([t.literal('on'), t.literal('off'), t.literal('mixed')]); +export type EntityTypeCheckOptions = t.TypeOf<typeof entityTypeCheckOptions>; + +const entityTypeRt = t.record(t.string, entityTypeCheckOptions); +export type EntityType = t.TypeOf<typeof entityTypeRt>; +export const entityTypesRt = new t.Type< + Record<string, 'on' | 'off' | 'mixed'> | undefined, + string, + unknown +>('entityTypesRt', entityTypeRt.is, validate(entityTypeRt), (o) => encode(o)); + +const paginationRt = t.record(t.string, t.number); +export type EntityPagination = t.TypeOf<typeof entityPaginationRt>; +export const entityPaginationRt = new t.Type<Record<string, number> | undefined, string, unknown>( + 'entityPaginationRt', + paginationRt.is, + validate(paginationRt), + (o) => encode(o) +); diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts index fdb68826e9dc..c2e7f1232e6a 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/e2e/home.cy.ts @@ -80,25 +80,6 @@ describe('Home page', () => { cy.contains('foo'); }); - it('Shows inventory page with unified view of entities', () => { - cy.intercept('GET', '/internal/entities/managed/enablement', { - fixture: 'eem_enabled.json', - }).as('getEEMStatus'); - cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); - cy.visitKibana('/app/inventory'); - cy.wait('@getEEMStatus'); - cy.contains('Group entities by: Type'); - cy.getByTestSubj('groupSelectorDropdown').click(); - cy.getByTestSubj('panelUnified').click(); - cy.wait('@getEntities'); - cy.contains('server1'); - cy.contains('host'); - cy.contains('synth-node-trace-logs'); - cy.contains('service'); - cy.contains('foo'); - cy.contains('container'); - }); - it('Navigates to apm when clicking on a service type entity', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', @@ -148,85 +129,85 @@ describe('Home page', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as( - 'entityTypeControlGroupOptions' - ); cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.intercept('GET', '/internal/inventory/entities/types').as('getEntitiesTypes'); cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); + cy.wait('@getEntitiesTypes'); cy.wait('@getEEMStatus'); - cy.getByTestSubj('optionsList-control-entity.type').click(); - cy.wait('@entityTypeControlGroupOptions'); - cy.getByTestSubj('optionsList-control-selection-service').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_service').click(); cy.wait('@getGroups'); cy.getByTestSubj('inventoryGroupTitle_entity.type_service').click(); cy.wait('@getEntities'); cy.get('server1').should('not.exist'); cy.contains('synth-node-trace-logs'); cy.contains('foo').should('not.exist'); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_service').click(); + cy.getByTestSubj('inventoryGroupTitle_entity.type_service').should('not.exist'); }); it('Filters entities by host type', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as( - 'entityTypeControlGroupOptions' - ); cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.intercept('GET', '/internal/inventory/entities/types').as('getEntitiesTypes'); cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); + cy.wait('@getEntitiesTypes'); cy.wait('@getEEMStatus'); - cy.getByTestSubj('optionsList-control-entity.type').click(); - cy.wait('@entityTypeControlGroupOptions'); - cy.getByTestSubj('optionsList-control-selection-host').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_host').click(); cy.wait('@getGroups'); cy.getByTestSubj('inventoryGroupTitle_entity.type_host').click(); cy.wait('@getEntities'); cy.contains('server1'); cy.contains('synth-node-trace-logs').should('not.exist'); cy.contains('foo').should('not.exist'); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_host').click(); + cy.getByTestSubj('inventoryGroupTitle_entity.type_host').should('not.exist'); }); it('Filters entities by container type', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); - cy.intercept('POST', 'internal/controls/optionsList/entities-*-latest').as( - 'entityTypeControlGroupOptions' - ); cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.intercept('GET', '/internal/inventory/entities/types').as('getEntitiesTypes'); cy.intercept('GET', '/internal/inventory/entities/group_by/**').as('getGroups'); cy.visitKibana('/app/inventory'); + cy.wait('@getEntitiesTypes'); cy.wait('@getEEMStatus'); - cy.getByTestSubj('optionsList-control-entity.type').click(); - cy.wait('@entityTypeControlGroupOptions'); - cy.getByTestSubj('optionsList-control-selection-container').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_container').click(); cy.wait('@getGroups'); cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); cy.wait('@getEntities'); cy.contains('server1').should('not.exist'); cy.contains('synth-node-trace-logs').should('not.exist'); cy.contains('foo'); + cy.getByTestSubj('entityTypes_multiSelect_filter').click(); + cy.getByTestSubj('entityTypes_multiSelect_filter_selection_container').click(); + cy.getByTestSubj('inventoryGroupTitle_entity.type_container').should('not.exist'); }); it('Navigates to discover with actions button in the entities list', () => { cy.intercept('GET', '/internal/entities/managed/enablement', { fixture: 'eem_enabled.json', }).as('getEEMStatus'); + cy.intercept('GET', '/internal/inventory/entities?**').as('getEntities'); cy.visitKibana('/app/inventory'); cy.wait('@getEEMStatus'); cy.contains('container'); cy.getByTestSubj('inventoryGroupTitle_entity.type_container').click(); + cy.wait('@getEntities'); + // cy.getByTestSubj('inventoryEntityActionsButton').click(); cy.getByTestSubj('inventoryEntityActionsButton-foo').click(); - cy.getByTestSubj('inventoryEntityActionOpenInDiscover').click(); - cy.url().should( - 'include', - "query:'container.id:%20%22foo%22%20AND%20entity.definition_id%20:%20builtin*" - ); + cy.getByTestSubj('inventoryEntityActionExploreInDiscover').click(); + cy.url().should('include', "query:'container.id:%20%22foo%22"); }); }); }); diff --git a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts index 6694b50ce9c7..c3462f8b6ff1 100644 --- a/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts +++ b/x-pack/plugins/observability_solution/inventory/e2e/cypress/support/commands.ts @@ -27,23 +27,31 @@ Cypress.Commands.add('loginAsSuperUser', () => { Cypress.Commands.add( 'loginAs', ({ username, password }: { username: string; password: string }) => { - const kibanaUrl = Cypress.env('KIBANA_URL'); - cy.log(`Logging in as ${username} on ${kibanaUrl}`); - cy.visit('/'); - cy.request({ - log: true, - method: 'POST', - url: `${kibanaUrl}/internal/security/login`, - body: { - providerType: 'basic', - providerName: 'basic', - currentURL: `${kibanaUrl}/login`, - params: { username, password }, + cy.session( + username, + () => { + const kibanaUrl = Cypress.env('KIBANA_URL'); + cy.log(`Logging in as ${username} on ${kibanaUrl}`); + cy.visit('/'); + cy.request({ + log: true, + method: 'POST', + url: `${kibanaUrl}/internal/security/login`, + body: { + providerType: 'basic', + providerName: 'basic', + currentURL: `${kibanaUrl}/login`, + params: { username, password }, + }, + headers: { + 'kbn-xsrf': 'e2e_test', + }, + }); + cy.visit('/'); }, - headers: { - 'kbn-xsrf': 'e2e_test', - }, - }); - cy.visit('/'); + { + cacheAcrossSpecs: true, + } + ); } ); diff --git a/x-pack/plugins/observability_solution/inventory/kibana.jsonc b/x-pack/plugins/observability_solution/inventory/kibana.jsonc index e6e7c5f2fa2f..e7cc398c9c65 100644 --- a/x-pack/plugins/observability_solution/inventory/kibana.jsonc +++ b/x-pack/plugins/observability_solution/inventory/kibana.jsonc @@ -21,7 +21,7 @@ "ruleRegistry", "share" ], - "requiredBundles": ["kibanaReact","controls"], + "requiredBundles": ["kibanaReact"], "optionalPlugins": ["spaces", "cloud"], "extraPublicDirs": [] } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx index 5195a35b93f4..1892dd010949 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.test.tsx @@ -15,12 +15,10 @@ const useKibanaMock = useKibana as jest.Mock; const commonEntityFields: Partial<InventoryEntity> = { entityLastSeenTimestamp: 'foo', - entityId: '1', + entityId: 'entity1', }; describe('AlertsBadge', () => { - const mockAsKqlFilter = jest.fn(); - beforeEach(() => { jest.clearAllMocks(); @@ -31,11 +29,6 @@ describe('AlertsBadge', () => { prepend: (path: string) => path, }, }, - entityManager: { - entityClient: { - asKqlFilter: mockAsKqlFilter, - }, - }, }, }); }); @@ -59,11 +52,10 @@ describe('AlertsBadge', () => { provider: null, }, }; - mockAsKqlFilter.mockReturnValue('host.name: foo'); render(<AlertsBadge entity={entity} />); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - "/app/observability/alerts?_a=(kuery:'host.name: foo',status:active)" + `/app/observability/alerts?_a=(kuery:\"entity1\",status:active)` ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('1'); }); @@ -86,40 +78,11 @@ describe('AlertsBadge', () => { alertsCount: 5, }; - mockAsKqlFilter.mockReturnValue('service.name: bar'); render(<AlertsBadge entity={entity} />); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - "/app/observability/alerts?_a=(kuery:'service.name: bar',status:active)" + `/app/observability/alerts?_a=(kuery:\"entity1\",status:active)` ); expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('5'); }); - it('render alerts badge for a service entity with multiple identity fields', () => { - const entity: InventoryEntity = { - ...(commonEntityFields as InventoryEntity), - entityType: 'service', - entityDisplayName: 'foo', - entityIdentityFields: ['service.name', 'service.environment'], - entityDefinitionId: 'service', - service: { - name: 'bar', - environment: 'prod', - }, - agent: { - name: 'node', - }, - cloud: { - provider: null, - }, - alertsCount: 2, - }; - - mockAsKqlFilter.mockReturnValue('service.name: bar AND service.environment: prod'); - - render(<AlertsBadge entity={entity} />); - expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.getAttribute('href')).toEqual( - "/app/observability/alerts?_a=(kuery:'service.name: bar AND service.environment: prod',status:active)" - ); - expect(screen.queryByTestId('inventoryAlertsBadgeLink')?.textContent).toEqual('2'); - }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx index ed873bdb68c2..228cd3d8bbfd 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/alerts_badge/alerts_badge.tsx @@ -15,21 +15,16 @@ export function AlertsBadge({ entity }: { entity: InventoryEntity }) { const { services: { http: { basePath }, - entityManager, }, } = useKibana(); const activeAlertsHref = basePath.prepend( `/app/observability/alerts?_a=${rison.encode({ - kuery: entityManager.entityClient.asKqlFilter({ - entity: { - identity_fields: entity.entityIdentityFields, - }, - ...entity, - }), + kuery: `"${entity.entityId}"`, status: 'active', })}` ); + return ( <EuiToolTip position="bottom" diff --git a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx index f3c518ef49b1..dfde850b36b6 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/badge_filter_with_popover.test.tsx @@ -27,7 +27,7 @@ describe('BadgeFilterWithPopover', () => { }); it('opens the popover when the badge is clicked', () => { - render(<BadgeFilterWithPopover field={field} value={value} />); + render(<BadgeFilterWithPopover field={field} value={value} onFilter={jest.fn()} />); expect(screen.queryByTestId(popoverContentDataTestId)).not.toBeInTheDocument(); fireEvent.click(screen.getByText(value)); expect(screen.queryByTestId(popoverContentDataTestId)).toBeInTheDocument(); @@ -35,9 +35,25 @@ describe('BadgeFilterWithPopover', () => { }); it('copies value to clipboard when the "Copy value" button is clicked', () => { - render(<BadgeFilterWithPopover field={field} value={value} />); + render(<BadgeFilterWithPopover field={field} value={value} onFilter={jest.fn()} />); fireEvent.click(screen.getByText(value)); fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverCopyValueButton')); expect(copyToClipboard).toHaveBeenCalledWith(value); }); + + it('Filter for an entity', () => { + const handleFilter = jest.fn(); + render(<BadgeFilterWithPopover field={field} value={value} onFilter={handleFilter} />); + fireEvent.click(screen.getByText(value)); + fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverFilterForButton')); + expect(handleFilter).toHaveBeenCalledWith(value, 'on'); + }); + + it('Filter out an entity', () => { + const handleFilter = jest.fn(); + render(<BadgeFilterWithPopover field={field} value={value} onFilter={handleFilter} />); + fireEvent.click(screen.getByText(value)); + fireEvent.click(screen.getByTestId('inventoryBadgeFilterWithPopoverFilterOutButton')); + expect(handleFilter).toHaveBeenCalledWith(value, 'off'); + }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx index 83e0bb02e6d8..ea85754dcbf7 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/badge_filter_with_popover/index.tsx @@ -18,19 +18,18 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import React, { useState } from 'react'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; +import type { EntityTypeCheckOptions } from '../../../common/rt_types'; interface Props { field: string; value: string; + onFilter: (value: string, checked: EntityTypeCheckOptions) => void; } -export function BadgeFilterWithPopover({ field, value }: Props) { +export function BadgeFilterWithPopover({ field, value, onFilter }: Props) { const [isOpen, setIsOpen] = useState(false); const theme = useEuiTheme(); - const { addFilter } = useUnifiedSearchContext(); return ( <EuiPopover @@ -82,7 +81,7 @@ export function BadgeFilterWithPopover({ field, value }: Props) { data-test-subj="inventoryBadgeFilterWithPopoverFilterForButton" iconType="plusInCircle" onClick={() => { - addFilter({ fieldName: ENTITY_TYPE, operation: '+', value }); + onFilter(value, 'on'); }} > {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', { @@ -92,10 +91,10 @@ export function BadgeFilterWithPopover({ field, value }: Props) { </EuiFlexItem> <EuiFlexItem> <EuiButtonEmpty - data-test-subj="inventoryBadgeFilterWithPopoverFilterForButton" + data-test-subj="inventoryBadgeFilterWithPopoverFilterOutButton" iconType="minusInCircle" onClick={() => { - addFilter({ fieldName: ENTITY_TYPE, operation: '-', value }); + onFilter(value, 'off'); }} > {i18n.translate('xpack.inventory.badgeFilterWithPopover.filterForButtonEmptyLabel', { diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx index ae80bf09ecae..b5e9287a836d 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/entities_grid.stories.tsx @@ -77,6 +77,7 @@ export const Grid: Story<EntityGridStoriesArgs> = (args) => { onChangePage={setPageIndex} onChangeSort={setSort} pageIndex={pageIndex} + onFilterByType={() => {}} /> </EuiFlexItem> </EuiFlexGroup> @@ -99,6 +100,7 @@ export const EmptyGrid: Story<EntityGridStoriesArgs> = (args) => { onChangePage={setPageIndex} onChangeSort={setSort} pageIndex={pageIndex} + onFilterByType={() => {}} /> ); }; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx index dd421d30a3a9..b26676494833 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_grid/index.tsx @@ -14,7 +14,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedDate, FormattedMessage, FormattedTime } from '@kbn/i18n-react'; import { last } from 'lodash'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import { EntityColumnIds, InventoryEntity } from '../../../common/entities'; import { BadgeFilterWithPopover } from '../badge_filter_with_popover'; @@ -22,7 +22,7 @@ import { getColumns } from './grid_columns'; import { AlertsBadge } from '../alerts_badge/alerts_badge'; import { EntityName } from './entity_name'; import { EntityActions } from '../entity_actions'; -import { useDiscoverRedirect } from '../../hooks/use_discover_redirect'; +import { type EntityTypeCheckOptions } from '../../../common/rt_types'; interface Props { loading: boolean; @@ -32,6 +32,7 @@ interface Props { pageIndex: number; onChangeSort: (sorting: EuiDataGridSorting['columns'][0]) => void; onChangePage: (nextPage: number) => void; + onFilterByType: (value: string, checked: EntityTypeCheckOptions) => void; } const PAGE_SIZE = 20; @@ -44,8 +45,9 @@ export function EntitiesGrid({ pageIndex, onChangePage, onChangeSort, + onFilterByType, }: Props) { - const { getDiscoverRedirectUrl } = useDiscoverRedirect(); + const [showActions, setShowActions] = useState<boolean>(true); const onSort: EuiDataGridSorting['onSort'] = useCallback( (newSortingColumns) => { @@ -62,8 +64,6 @@ export function EntitiesGrid({ [entities] ); - const showActions = useMemo(() => !!getDiscoverRedirectUrl(), [getDiscoverRedirectUrl]); - const columnVisibility = useMemo( () => ({ visibleColumns: getColumns({ showAlertsColumn, showActions }).map(({ id }) => id), @@ -81,14 +81,19 @@ export function EntitiesGrid({ const columnEntityTableId = columnId as EntityColumnIds; const entityType = entity.entityType; - const discoverUrl = getDiscoverRedirectUrl(entity); switch (columnEntityTableId) { case 'alertsCount': return entity?.alertsCount ? <AlertsBadge entity={entity} /> : null; case 'entityType': - return <BadgeFilterWithPopover field={ENTITY_TYPE} value={entityType} />; + return ( + <BadgeFilterWithPopover + field={ENTITY_TYPE} + value={entityType} + onFilter={onFilterByType} + /> + ); case 'entityLastSeenTimestamp': return ( @@ -119,19 +124,12 @@ export function EntitiesGrid({ case 'entityDisplayName': return <EntityName entity={entity} />; case 'actions': - return ( - discoverUrl && ( - <EntityActions - discoverUrl={discoverUrl} - entityIdentifyingValue={entity.entityDisplayName} - /> - ) - ); + return <EntityActions entity={entity} setShowActions={setShowActions} />; default: return null; } }, - [entities, getDiscoverRedirectUrl] + [entities, onFilterByType] ); if (loading) { diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/entities_summary.test.tsx similarity index 72% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entities_summary/entities_summary.test.tsx index 63583e60b0ed..9f4a5df76e0d 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/entities_summary.test.tsx @@ -9,12 +9,7 @@ import React from 'react'; import { render, screen } from '@testing-library/react'; import { EuiThemeProvider } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n-react'; -import { InventorySummary } from './inventory_summary'; - -// Do not test the GroupSelector, as it needs a lot more complicated setup -jest.mock('./group_selector', () => ({ - GroupSelector: () => <>Selector</>, -})); +import { EntitiesSummary } from '.'; function MockEnvWrapper({ children }: { children?: React.ReactNode }) { return ( @@ -24,19 +19,19 @@ function MockEnvWrapper({ children }: { children?: React.ReactNode }) { ); } -describe('InventorySummary', () => { +describe('EntitiesSummary', () => { it('renders the total entities without any group totals', () => { - render(<InventorySummary totalEntities={10} />, { wrapper: MockEnvWrapper }); + render(<EntitiesSummary totalEntities={10} />, { wrapper: MockEnvWrapper }); expect(screen.getByText('10 Entities')).toBeInTheDocument(); expect(screen.queryByTestId('inventorySummaryGroupsTotal')).not.toBeInTheDocument(); }); it('renders the total entities with group totals', () => { - render(<InventorySummary totalEntities={15} totalGroups={3} />, { wrapper: MockEnvWrapper }); + render(<EntitiesSummary totalEntities={15} totalGroups={3} />, { wrapper: MockEnvWrapper }); expect(screen.getByText('15 Entities')).toBeInTheDocument(); expect(screen.queryByText('3 Groups')).toBeInTheDocument(); }); it("won't render either totals when not provided anything", () => { - render(<InventorySummary />, { wrapper: MockEnvWrapper }); + render(<EntitiesSummary />, { wrapper: MockEnvWrapper }); expect(screen.queryByTestId('inventorySummaryEntitiesTotal')).not.toBeInTheDocument(); expect(screen.queryByTestId('inventorySummaryGroupsTotal')).not.toBeInTheDocument(); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/index.tsx new file mode 100644 index 000000000000..8388ad64407a --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/entities_summary/index.tsx @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/react'; +import { FormattedMessage } from '@kbn/i18n-react'; + +export function EntitiesSummary({ + totalEntities, + totalGroups, +}: { + totalEntities?: number; + totalGroups?: number; +}) { + const { euiTheme } = useEuiTheme(); + + const isGrouped = totalGroups !== undefined; + + return ( + <EuiFlexGroup + gutterSize="none" + css={css` + font-weight: ${euiTheme.font.weight.semiBold}; + `} + > + {totalEntities !== undefined && ( + <EuiFlexItem grow={false}> + <span + data-test-subj="inventorySummaryEntitiesTotal" + css={css` + border-right: ${isGrouped ? euiTheme.border.thin : 'none'}; + margin-right: ${euiTheme.size.base}; + padding-right: ${euiTheme.size.base}; + `} + > + <FormattedMessage + id="xpack.inventory.groupedInventoryPage.entitiesTotalLabel" + defaultMessage="{total} Entities" + values={{ total: totalEntities }} + /> + </span> + </EuiFlexItem> + )} + {isGrouped ? ( + <EuiFlexItem grow={false}> + <span data-test-subj="inventorySummaryGroupsTotal"> + <FormattedMessage + id="xpack.inventory.groupedInventoryPage.groupsTotalLabel" + defaultMessage="{total} Groups" + values={{ total: totalGroups }} + /> + </span> + </EuiFlexItem> + ) : null} + </EuiFlexGroup> + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx index 95a4050fba4e..691ba4388ac6 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_actions/index.tsx @@ -7,56 +7,70 @@ import { EuiButtonIcon, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { type SetStateAction } from 'react'; import { useBoolean } from '@kbn/react-hooks'; +import type { Dispatch } from '@kbn/kibana-utils-plugin/common'; +import type { InventoryEntity } from '../../../common/entities'; +import { useDiscoverRedirect } from '../../hooks/use_discover_redirect'; interface Props { - discoverUrl: string; - entityIdentifyingValue?: string; + entity: InventoryEntity; + setShowActions: Dispatch<SetStateAction<boolean>>; } -export const EntityActions = ({ discoverUrl, entityIdentifyingValue }: Props) => { +export const EntityActions = ({ entity, setShowActions }: Props) => { const [isPopoverOpen, { toggle: togglePopover, off: closePopover }] = useBoolean(false); - const actionButtonTestSubject = entityIdentifyingValue - ? `inventoryEntityActionsButton-${entityIdentifyingValue}` + const actionButtonTestSubject = entity.entityDisplayName + ? `inventoryEntityActionsButton-${entity.entityDisplayName}` : 'inventoryEntityActionsButton'; - const actions = [ - <EuiContextMenuItem - data-test-subj="inventoryEntityActionOpenInDiscover" - key={`openInDiscover-${entityIdentifyingValue}`} - color="text" - icon="discoverApp" - href={discoverUrl} - > - {i18n.translate('xpack.inventory.entityActions.discoverLink', { - defaultMessage: 'Open in discover', - })} - </EuiContextMenuItem>, - ]; + const { getDiscoverEntitiesRedirectUrl, isEntityDefinitionLoading } = useDiscoverRedirect(entity); + const discoverUrl = getDiscoverEntitiesRedirectUrl(); - return ( - <> - <EuiPopover - isOpen={isPopoverOpen} - panelPaddingSize="none" - anchorPosition="upCenter" - button={ - <EuiButtonIcon - data-test-subj={actionButtonTestSubject} - aria-label={i18n.translate( - 'xpack.inventory.entityActions.euiButtonIcon.showActionsLabel', - { defaultMessage: 'Show actions' } - )} - iconType="boxesHorizontal" - color="text" - onClick={togglePopover} - /> - } - closePopover={closePopover} + const actions: React.ReactElement[] = []; + + if (!discoverUrl && !isEntityDefinitionLoading) { + setShowActions(false); + return null; + } + + if (!isEntityDefinitionLoading) { + actions.push( + <EuiContextMenuItem + data-test-subj="inventoryEntityActionExploreInDiscover" + key={`exploreInDiscover-${entity.entityDisplayName}`} + color="text" + icon="discoverApp" + href={discoverUrl} > - <EuiContextMenuPanel items={actions} size="s" /> - </EuiPopover> - </> + {i18n.translate('xpack.inventory.entityActions.exploreInDiscoverLink', { + defaultMessage: 'Explore in Discover', + })} + </EuiContextMenuItem> + ); + } + + return ( + <EuiPopover + isOpen={isPopoverOpen} + panelPaddingSize="none" + anchorPosition="upCenter" + button={ + <EuiButtonIcon + data-test-subj={actionButtonTestSubject} + aria-label={i18n.translate( + 'xpack.inventory.entityActions.euiButtonIcon.showActionsLabel', + { defaultMessage: 'Show actions' } + )} + iconType="boxesHorizontal" + color="text" + onClick={togglePopover} + isLoading={isEntityDefinitionLoading} + /> + } + closePopover={closePopover} + > + <EuiContextMenuPanel items={actions} size="s" /> + </EuiPopover> ); }; diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_count_badge.tsx similarity index 95% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_count_badge.tsx index 43db1c39154b..a0c9a2a18c4a 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_panel_badge.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_count_badge.tsx @@ -7,7 +7,7 @@ import { EuiBadge, EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui'; import React from 'react'; -export function InventoryPanelBadge({ +export function EntityCountBadge({ name, value, 'data-test-subj': dataTestSubj, diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_group_accordion.test.tsx similarity index 80% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_group_accordion.test.tsx index bf0b7064033f..747124808df2 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.test.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/entity_group_accordion.test.tsx @@ -7,10 +7,9 @@ import React from 'react'; import { render, screen, within } from '@testing-library/react'; +import { EntityGroupAccordion } from '.'; -import { InventoryGroupAccordion } from './inventory_group_accordion'; - -describe('Grouped Inventory Accordion', () => { +describe('EntityGroupAccordion', () => { it('renders with correct values', () => { const props = { groupBy: 'entity.type', @@ -26,14 +25,14 @@ describe('Grouped Inventory Accordion', () => { ], }; render( - <InventoryGroupAccordion + <EntityGroupAccordion groupValue={props.groups[0]['entity.type']} groupCount={props.groups[0].count} groupBy={props.groupBy} /> ); expect(screen.getByText(props.groups[0]['entity.type'])).toBeInTheDocument(); - const container = screen.getByTestId('inventoryPanelBadgeEntitiesCount_entity.type_host'); + const container = screen.getByTestId('entityCountBadge_entity.type_host'); expect(within(container).getByText('Entities:')).toBeInTheDocument(); expect(within(container).getByText(props.groups[0].count)).toBeInTheDocument(); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/grouped_entities_grid.tsx similarity index 67% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/grouped_entities_grid.tsx index 911e99740102..5dde32cbb4aa 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/grouped_entities_grid.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/grouped_entities_grid.tsx @@ -5,15 +5,16 @@ * 2.0. */ import { EuiDataGridSorting } from '@elastic/eui'; -import { decodeOrThrow } from '@kbn/io-ts-utils'; import React from 'react'; import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { type EntityColumnIds } from '../../../common/entities'; import { + type EntityTypeCheckOptions, entityPaginationRt, - type EntityColumnIds, - type EntityPagination, -} from '../../../common/entities'; + entityTypesRt, +} from '../../../common/rt_types'; import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryDecodedQueryParams } from '../../hooks/use_inventory_decoded_query_params'; import { useInventoryParams } from '../../hooks/use_inventory_params'; import { useInventoryRouter } from '../../hooks/use_inventory_router'; import { useKibana } from '../../hooks/use_kibana'; @@ -24,29 +25,14 @@ interface Props { groupValue: string; } -const paginationDecoder = decodeOrThrow(entityPaginationRt); - export function GroupedEntitiesGrid({ groupValue }: Props) { const { query } = useInventoryParams('/'); - const { sortField, sortDirection, pagination: paginationQuery } = query; + const { sortField, sortDirection, kuery } = query; + const { pagination, entityTypes } = useInventoryDecodedQueryParams(); const inventoryRoute = useInventoryRouter(); - let pagination: EntityPagination | undefined = {}; - const { stringifiedEsQuery } = useUnifiedSearchContext(); - try { - pagination = paginationDecoder(paginationQuery); - } catch (error) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - pagination: undefined, - }, - }); - window.location.reload(); - } const pageIndex = pagination?.[groupValue] ?? 0; - const { refreshSubject$, isControlPanelsInitiated } = useUnifiedSearchContext(); + const { refreshSubject$ } = useUnifiedSearchContext(); const { services: { inventoryAPIClient }, } = useKibana(); @@ -57,28 +43,19 @@ export function GroupedEntitiesGrid({ groupValue }: Props) { refresh, } = useInventoryAbortableAsync( ({ signal }) => { - if (isControlPanelsInitiated) { - return inventoryAPIClient.fetch('GET /internal/inventory/entities', { - params: { - query: { - sortDirection, - sortField, - esQuery: stringifiedEsQuery, - entityTypes: groupValue?.length ? JSON.stringify([groupValue]) : undefined, - }, + return inventoryAPIClient.fetch('GET /internal/inventory/entities', { + params: { + query: { + sortDirection, + sortField, + kuery, + entityTypes: groupValue?.length ? JSON.stringify([groupValue]) : undefined, }, - signal, - }); - } + }, + signal, + }); }, - [ - groupValue, - inventoryAPIClient, - sortDirection, - sortField, - isControlPanelsInitiated, - stringifiedEsQuery, - ] + [groupValue, inventoryAPIClient, sortDirection, sortField, kuery] ); useEffectOnce(() => { @@ -111,6 +88,16 @@ export function GroupedEntitiesGrid({ groupValue }: Props) { }); } + function handleEntityTypeFilter(entityType: string, checkOption: EntityTypeCheckOptions) { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + entityTypes: entityTypesRt.encode({ ...entityTypes, [entityType]: checkOption }), + }, + }); + } + return ( <EntitiesGrid entities={value.entities} @@ -120,6 +107,7 @@ export function GroupedEntitiesGrid({ groupValue }: Props) { onChangePage={handlePageChange} onChangeSort={handleSortChange} pageIndex={pageIndex} + onFilterByType={handleEntityTypeFilter} /> ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/index.tsx similarity index 85% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/index.tsx index 0b4e9a46d428..fa365625474b 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_group_accordion.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/index.tsx @@ -8,27 +8,22 @@ import { EuiAccordion, EuiPanel, EuiSpacer, EuiTitle, useEuiTheme } from '@elast import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import React, { useCallback, useState } from 'react'; +import { EntityCountBadge } from './entity_count_badge'; import { GroupedEntitiesGrid } from './grouped_entities_grid'; -import { InventoryPanelBadge } from './inventory_panel_badge'; const ENTITIES_COUNT_BADGE = i18n.translate( 'xpack.inventory.inventoryGroupPanel.entitiesBadgeLabel', { defaultMessage: 'Entities' } ); -export interface InventoryGroupAccordionProps { +export interface Props { groupBy: string; groupValue: string; groupCount: number; isLoading?: boolean; } -export function InventoryGroupAccordion({ - groupBy, - groupValue, - groupCount, - isLoading, -}: InventoryGroupAccordionProps) { +export function EntityGroupAccordion({ groupBy, groupValue, groupCount, isLoading }: Props) { const { euiTheme } = useEuiTheme(); const [open, setOpen] = useState(false); @@ -55,8 +50,8 @@ export function InventoryGroupAccordion({ } buttonElement="div" extraAction={ - <InventoryPanelBadge - data-test-subj={`inventoryPanelBadgeEntitiesCount_${groupBy}_${groupValue}`} + <EntityCountBadge + data-test-subj={`entityCountBadge_${groupBy}_${groupValue}`} name={ENTITIES_COUNT_BADGE} value={groupCount} /> diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/mock/inventory_component_wrapper_mock.tsx similarity index 100% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/mock/inventory_component_wrapper_mock.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/entity_group_accordion/mock/inventory_component_wrapper_mock.tsx diff --git a/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx index 4da8fd3103c4..239d441b5d4e 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/entity_icon/index.tsx @@ -45,7 +45,7 @@ export function EntityIcon({ entity }: EntityIconProps) { return <AgentIcon agentName={castArray(entity.agent?.name)[0]} role="presentation" />; } - if (entity.entityType.startsWith('kubernetes')) { + if (entity.entityType.startsWith('k8s')) { return <EuiIcon type="logoKubernetes" size="l" />; } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/group_by_selector.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/group_by_selector.test.tsx new file mode 100644 index 000000000000..6f504715e99c --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/group_by_selector.test.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { GroupBySelector } from '.'; +import { InventoryComponentWrapperMock } from '../entity_group_accordion/mock/inventory_component_wrapper_mock'; + +describe('GroupBySelector', () => { + beforeEach(() => { + render( + <InventoryComponentWrapperMock> + <GroupBySelector /> + </InventoryComponentWrapperMock> + ); + }); + it('Should default to Type', async () => { + expect(await screen.findByText('Group entities by: Type')).toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/index.tsx similarity index 50% rename from x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx rename to x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/index.tsx index 95264f3c8130..b9aa28d3f298 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/group_by_selector/index.tsx @@ -5,49 +5,17 @@ * 2.0. */ -import { EuiPopover, EuiContextMenu, EuiButtonEmpty } from '@elastic/eui'; -import React, { useCallback, useState } from 'react'; +import { EuiButtonEmpty, EuiContextMenu, EuiPopover } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { EntityView } from '../../../common/entities'; -import { useInventoryParams } from '../../hooks/use_inventory_params'; -import { useInventoryRouter } from '../../hooks/use_inventory_router'; +import React, { useCallback, useState } from 'react'; -const GROUP_LABELS: Record<EntityView, string> = { - unified: i18n.translate('xpack.inventory.groupedInventoryPage.noneLabel', { - defaultMessage: 'None', - }), - grouped: i18n.translate('xpack.inventory.groupedInventoryPage.typeLabel', { - defaultMessage: 'Type', - }), -}; +const ENTITY_TYPE_LABEL = i18n.translate('xpack.inventory.groupedInventoryPage.typeLabel', { + defaultMessage: 'Type', +}); -export interface GroupedSelectorProps { - groupSelected: string; - onGroupChange: (groupSelection: string) => void; -} - -export function GroupSelector() { - const { query } = useInventoryParams('/'); - const inventoryRoute = useInventoryRouter(); +export function GroupBySelector() { const [isPopoverOpen, setIsPopoverOpen] = useState(false); - const groupBy = query.view ?? 'grouped'; - - const onGroupChange = (selected: EntityView) => { - const { pagination: _, ...rest } = query; - - inventoryRoute.push('/', { - path: {}, - query: { - ...rest, - view: groupBy === selected ? 'unified' : selected, - }, - }); - }; - - const isGroupSelected = (groupKey: EntityView) => { - return groupBy === groupKey; - }; const panels = [ { @@ -56,17 +24,10 @@ export function GroupSelector() { defaultMessage: 'Select grouping', }), items: [ - { - 'data-test-subj': 'panelUnified', - name: GROUP_LABELS.unified, - icon: isGroupSelected('unified') ? 'check' : 'empty', - onClick: () => onGroupChange('unified'), - }, { 'data-test-subj': 'panelType', - name: GROUP_LABELS.grouped, - icon: isGroupSelected('grouped') ? 'check' : 'empty', - onClick: () => onGroupChange('grouped'), + name: ENTITY_TYPE_LABEL, + icon: 'check', }, ], }, @@ -83,13 +44,13 @@ export function GroupSelector() { iconSize="s" iconType="arrowDown" onClick={onButtonClick} - title={GROUP_LABELS[groupBy]} + title={ENTITY_TYPE_LABEL} size="s" > <FormattedMessage id="xpack.inventory.groupedInventoryPage.groupedByLabel" defaultMessage={`Group entities by: {grouping}`} - values={{ grouping: GROUP_LABELS[groupBy] }} + values={{ grouping: ENTITY_TYPE_LABEL }} /> </EuiButtonEmpty> ); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx deleted file mode 100644 index 23cbb5b43c43..000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/group_selector.test.tsx +++ /dev/null @@ -1,45 +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 { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; - -import { GroupSelector } from './group_selector'; - -import { InventoryComponentWrapperMock } from './mock/inventory_component_wrapper_mock'; - -describe('GroupSelector', () => { - beforeEach(() => { - render( - <InventoryComponentWrapperMock> - <GroupSelector /> - </InventoryComponentWrapperMock> - ); - }); - it('Should default to Type', async () => { - expect(await screen.findByText('Group entities by: Type')).toBeInTheDocument(); - }); - - it.skip('Should change to None', async () => { - const user = userEvent.setup(); - - const selector = screen.getByText('Group entities by: Type'); - - expect(selector).toBeInTheDocument(); - - await user.click(selector); - - const noneOption = screen.getByTestId('panelUnified'); - - expect(noneOption).toBeInTheDocument(); - - await user.click(noneOption); - - expect(await screen.findByText('Group entities by: None')).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx deleted file mode 100644 index 6cfdc079be29..000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { EuiSpacer } from '@elastic/eui'; -import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; -import React from 'react'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { flattenObject } from '@kbn/observability-utils-common/object/flatten_object'; -import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; -import { useKibana } from '../../hooks/use_kibana'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; -import { InventoryGroupAccordion } from './inventory_group_accordion'; -import { InventorySummary } from './inventory_summary'; - -export function GroupedInventory() { - const { - services: { inventoryAPIClient }, - } = useKibana(); - const { refreshSubject$, isControlPanelsInitiated, stringifiedEsQuery } = - useUnifiedSearchContext(); - - const { - value = { groupBy: ENTITY_TYPE, groups: [], entitiesCount: 0 }, - refresh, - loading, - } = useInventoryAbortableAsync( - ({ signal }) => { - if (isControlPanelsInitiated) { - return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', { - params: { - path: { - field: ENTITY_TYPE, - }, - query: { esQuery: stringifiedEsQuery }, - }, - signal, - }); - } - }, - [inventoryAPIClient, stringifiedEsQuery, isControlPanelsInitiated] - ); - - useEffectOnce(() => { - const refreshSubscription = refreshSubject$.subscribe(refresh); - - return () => refreshSubscription.unsubscribe(); - }); - - return ( - <> - <InventorySummary totalEntities={value.entitiesCount} totalGroups={value.groups.length} /> - <EuiSpacer size="m" /> - {value.groups.map((group) => { - const groupValue = flattenObject(group)[value.groupBy]; - return ( - <InventoryGroupAccordion - key={`${value.groupBy}-${groupValue}`} - groupBy={value.groupBy} - groupValue={groupValue} - groupCount={group.count} - isLoading={loading} - /> - ); - })} - </> - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx b/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx deleted file mode 100644 index 55697790c4ee..000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/grouped_inventory/inventory_summary.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, useEuiTheme } from '@elastic/eui'; -import { css } from '@emotion/react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { GroupSelector } from './group_selector'; - -export function InventorySummary({ - totalEntities, - totalGroups, -}: { - totalEntities?: number; - totalGroups?: number; -}) { - const { euiTheme } = useEuiTheme(); - - const isGrouped = totalGroups !== undefined; - - return ( - <EuiFlexGroup gutterSize="none" justifyContent="spaceBetween" alignItems="center"> - <EuiFlexItem grow={false}> - <EuiFlexGroup - gutterSize="none" - css={css` - font-weight: ${euiTheme.font.weight.semiBold}; - `} - > - {totalEntities !== undefined && ( - <EuiFlexItem grow={false}> - <span - data-test-subj="inventorySummaryEntitiesTotal" - css={css` - border-right: ${isGrouped ? euiTheme.border.thin : 'none'}; - margin-right: ${euiTheme.size.base}; - padding-right: ${euiTheme.size.base}; - `} - > - <FormattedMessage - id="xpack.inventory.groupedInventoryPage.entitiesTotalLabel" - defaultMessage="{total} Entities" - values={{ total: totalEntities }} - /> - </span> - </EuiFlexItem> - )} - {isGrouped ? ( - <EuiFlexItem grow={false}> - <span data-test-subj="inventorySummaryGroupsTotal"> - <FormattedMessage - id="xpack.inventory.groupedInventoryPage.groupsTotalLabel" - defaultMessage="{total} Groups" - values={{ total: totalGroups }} - /> - </span> - </EuiFlexItem> - ) : null} - </EuiFlexGroup> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <GroupSelector /> - </EuiFlexItem> - </EuiFlexGroup> - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx deleted file mode 100644 index 9c263e39562f..000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/control_groups.tsx +++ /dev/null @@ -1,98 +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 { - ControlGroupRenderer, - ControlGroupRendererApi, - ControlGroupRuntimeState, -} from '@kbn/controls-plugin/public'; -import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; -import { ControlPanels, useControlPanels } from '@kbn/observability-shared-plugin/public'; -import React, { useCallback, useEffect, useRef } from 'react'; -import { skip, Subscription } from 'rxjs'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; - -const controlPanelDefinitions: ControlPanels = { - [ENTITY_TYPE]: { - order: 0, - type: 'optionsListControl', - fieldName: ENTITY_TYPE, - width: 'small', - grow: false, - title: 'Type', - }, -}; - -export function ControlGroups() { - const { - isControlPanelsInitiated, - setIsControlPanelsInitiated, - dataView, - searchState, - onPanelFiltersChange, - } = useUnifiedSearchContext(); - const [controlPanels, setControlPanels] = useControlPanels(controlPanelDefinitions, dataView); - const subscriptions = useRef<Subscription>(new Subscription()); - - const getInitialInput = useCallback( - () => async () => { - const initialInput: Partial<ControlGroupRuntimeState> = { - chainingSystem: 'HIERARCHICAL', - labelPosition: 'oneLine', - initialChildControlState: controlPanels, - }; - - return { initialState: initialInput }; - }, - [controlPanels] - ); - - const loadCompleteHandler = useCallback( - (controlGroup: ControlGroupRendererApi) => { - if (!controlGroup) return; - - subscriptions.current.add( - controlGroup.filters$.pipe(skip(1)).subscribe((newFilters = []) => { - onPanelFiltersChange(newFilters); - }) - ); - - subscriptions.current.add( - controlGroup.getInput$().subscribe(({ initialChildControlState }) => { - if (!isControlPanelsInitiated) { - setIsControlPanelsInitiated(true); - } - setControlPanels(initialChildControlState); - }) - ); - }, - [isControlPanelsInitiated, onPanelFiltersChange, setControlPanels, setIsControlPanelsInitiated] - ); - - useEffect(() => { - const currentSubscriptions = subscriptions.current; - return () => { - currentSubscriptions.unsubscribe(); - }; - }, []); - - if (!dataView) { - return null; - } - - return ( - <div> - <ControlGroupRenderer - getCreationOptions={getInitialInput()} - onApiAvailable={loadCompleteHandler} - query={searchState.query} - compressed={false} - filters={searchState.filters} - /> - </div> - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_multi_select.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_multi_select.tsx new file mode 100644 index 000000000000..0b4853e82a47 --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/entity_types_multi_select.tsx @@ -0,0 +1,146 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiFilterButton, + EuiFilterGroup, + EuiPopover, + EuiPopoverTitle, + EuiSelectable, + EuiSelectableOption, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React, { useCallback, useMemo, useState } from 'react'; +import { entityTypesRt, type EntityType } from '../../../common/rt_types'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryDecodedQueryParams } from '../../hooks/use_inventory_decoded_query_params'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; +import { useKibana } from '../../hooks/use_kibana'; +import { groupEntityTypesByStatus } from '../../utils/group_entity_types_by_status'; + +export function EntityTypesMultiSelect() { + const inventoryRoute = useInventoryRouter(); + const { query } = useInventoryParams('/*'); + const { entityTypes: selectedEntityTypes } = useInventoryDecodedQueryParams(); + + const { + services: { inventoryAPIClient, telemetry }, + } = useKibana(); + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + const { value, loading } = useInventoryAbortableAsync( + ({ signal }) => inventoryAPIClient.fetch('GET /internal/inventory/entities/types', { signal }), + [inventoryAPIClient] + ); + + const items = useMemo( + () => + value?.entityTypes.map((type): EuiSelectableOption => { + const checked = selectedEntityTypes?.[type]; + return { + label: type, + checked, + 'data-test-subj': `entityTypes_multiSelect_filter_selection_${type}`, + }; + }) || [], + [selectedEntityTypes, value?.entityTypes] + ); + + const registerEntityTypeFilteredEvent = useCallback( + ({ filterEntityTypes }: { filterEntityTypes: EntityType }) => { + const { entityTypesOff, entityTypesOn } = groupEntityTypesByStatus(filterEntityTypes); + + telemetry.reportEntityInventoryEntityTypeFiltered({ + include_entity_types: entityTypesOn, + exclude_entity_types: entityTypesOff, + }); + }, + [telemetry] + ); + + function handleEntityTypeChecked(nextItems: EntityType) { + registerEntityTypeFilteredEvent({ filterEntityTypes: nextItems }); + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + entityTypes: entityTypesRt.encode(nextItems), + }, + }); + } + + return ( + <EuiFilterGroup> + <EuiPopover + id="entityTypeMultiSelector" + button={ + <EuiFilterButton + data-test-subj="entityTypes_multiSelect_filter" + iconType="arrowDown" + badgeColor="success" + onClick={() => setIsPopoverOpen((state) => !state)} + isSelected={isPopoverOpen} + numFilters={items.filter((item) => item.checked !== 'off').length} + hasActiveFilters={!!items.find((item) => item.checked === 'on')} + numActiveFilters={items.filter((item) => item.checked === 'on').length} + > + {i18n.translate('xpack.inventory.entityTypesMultSelect.typeFilterButtonLabel', { + defaultMessage: 'Type', + })} + </EuiFilterButton> + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + panelPaddingSize="none" + > + <EuiSelectable + allowExclusions + searchable + searchProps={{ + placeholder: i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.placeholder', + { defaultMessage: 'Filter types' } + ), + compressed: true, + }} + aria-label={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.typeLabel', + { defaultMessage: 'Entity type' } + )} + options={items} + onChange={(newOptions) => { + handleEntityTypeChecked( + newOptions + .filter((item) => item.checked) + .reduce<EntityType>((acc, curr) => ({ ...acc, [curr.label]: curr.checked! }), {}) + ); + }} + isLoading={loading} + loadingMessage={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.loading', + { defaultMessage: 'Loading types' } + )} + emptyMessage={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.empty', + { defaultMessage: 'No types available' } + )} + noMatchesMessage={i18n.translate( + 'xpack.inventory.entityTypesMultSelect.euiSelectable.notFound', + { defaultMessage: 'No types found' } + )} + > + {(list, search) => ( + <div style={{ width: 300 }}> + <EuiPopoverTitle paddingSize="s">{search}</EuiPopoverTitle> + {list} + </div> + )} + </EuiSelectable> + </EuiPopover> + </EuiFilterGroup> + ); +} diff --git a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx index 3464c5749dbc..16df0927df35 100644 --- a/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/components/search_bar/index.tsx @@ -4,19 +4,24 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { Query } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import type { SearchBarOwnProps } from '@kbn/unified-search-plugin/public/search_bar'; import deepEqual from 'fast-deep-equal'; import React, { useCallback, useEffect } from 'react'; +import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useInventoryRouter } from '../../hooks/use_inventory_router'; import { useKibana } from '../../hooks/use_kibana'; import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; import { getKqlFieldsWithFallback } from '../../utils/get_kql_field_names_with_fallback'; -import { ControlGroups } from './control_groups'; +import { EntityTypesMultiSelect } from './entity_types_multi_select'; export function SearchBar() { - const { refreshSubject$, dataView, searchState, onQueryChange } = useUnifiedSearchContext(); - + const { refreshSubject$, dataView } = useUnifiedSearchContext(); + const inventoryRoute = useInventoryRouter(); + const { + query, + query: { kuery }, + } = useInventoryParams('/*'); const { services: { unifiedSearch, @@ -30,44 +35,40 @@ export function SearchBar() { const { SearchBar: UnifiedSearchBar } = unifiedSearch.ui; const syncSearchBarWithUrl = useCallback(() => { - const query = searchState.query; - if (query && !deepEqual(queryStringService.getQuery(), query)) { - queryStringService.setQuery(query); + const _query = kuery ? { query: kuery, language: 'kuery' } : undefined; + if (_query && !deepEqual(queryStringService.getQuery(), _query)) { + queryStringService.setQuery(_query); } - if (!query) { + if (!_query) { queryStringService.clearQuery(); } - }, [searchState.query, queryStringService]); + }, [kuery, queryStringService]); useEffect(() => { syncSearchBarWithUrl(); }, [syncSearchBarWithUrl]); - const registerSearchSubmittedEvent = useCallback( - ({ searchQuery, searchIsUpdate }: { searchQuery?: Query; searchIsUpdate?: boolean }) => { - telemetry.reportEntityInventorySearchQuerySubmitted({ - kuery_fields: getKqlFieldsWithFallback(searchQuery?.query as string), - action: searchIsUpdate ? 'submit' : 'refresh', + const handleQuerySubmit = useCallback<NonNullable<SearchBarOwnProps['onQuerySubmit']>>( + ({ query: _query = { language: 'kuery', query: '' } }, isUpdate) => { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + kuery: _query?.query as string, + }, }); - }, - [telemetry] - ); - const handleQuerySubmit = useCallback<NonNullable<SearchBarOwnProps['onQuerySubmit']>>( - ({ query = { language: 'kuery', query: '' } }, isUpdate) => { - if (isUpdate) { - onQueryChange(query); - } else { + if (!isUpdate) { refreshSubject$.next(); } - registerSearchSubmittedEvent({ - searchQuery: query, - searchIsUpdate: isUpdate, + telemetry.reportEntityInventorySearchQuerySubmitted({ + kuery_fields: getKqlFieldsWithFallback(_query?.query as string), + action: isUpdate ? 'submit' : 'refresh', }); }, - [registerSearchSubmittedEvent, onQueryChange, refreshSubject$] + [inventoryRoute, query, telemetry, refreshSubject$] ); return ( @@ -75,16 +76,14 @@ export function SearchBar() { appName="Inventory" displayStyle="inPage" indexPatterns={dataView ? [dataView] : undefined} - renderQueryInputAppend={() => <ControlGroups />} + renderQueryInputAppend={() => <EntityTypesMultiSelect />} onQuerySubmit={handleQuerySubmit} placeholder={i18n.translate('xpack.inventory.searchBar.placeholder', { defaultMessage: 'Search for your entities by name or its metadata (e.g. entity.type : service)', })} showDatePicker={false} - showFilterBar - showQueryInput - showQueryMenu + showFilterBar={false} /> ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx deleted file mode 100644 index 1bec6dee990d..000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/components/unified_inventory/index.tsx +++ /dev/null @@ -1,117 +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 { EuiDataGridSorting } from '@elastic/eui'; -import { decodeOrThrow } from '@kbn/io-ts-utils'; -import React from 'react'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { - entityPaginationRt, - type EntityColumnIds, - type EntityPagination, -} from '../../../common/entities'; -import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; -import { useInventoryParams } from '../../hooks/use_inventory_params'; -import { useInventoryRouter } from '../../hooks/use_inventory_router'; -import { useKibana } from '../../hooks/use_kibana'; -import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; -import { EntitiesGrid } from '../entities_grid'; -import { InventorySummary } from '../grouped_inventory/inventory_summary'; - -const paginationDecoder = decodeOrThrow(entityPaginationRt); - -export function UnifiedInventory() { - const { - services: { inventoryAPIClient }, - } = useKibana(); - const { refreshSubject$, isControlPanelsInitiated, stringifiedEsQuery } = - useUnifiedSearchContext(); - const { query } = useInventoryParams('/'); - const { sortDirection, sortField, pagination: paginationQuery } = query; - - let pagination: EntityPagination | undefined = {}; - const inventoryRoute = useInventoryRouter(); - try { - pagination = paginationDecoder(paginationQuery); - } catch (error) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - pagination: undefined, - }, - }); - window.location.reload(); - } - - const pageIndex = pagination?.unified ?? 0; - - const { - value = { entities: [] }, - loading, - refresh, - } = useInventoryAbortableAsync( - ({ signal }) => { - if (isControlPanelsInitiated) { - return inventoryAPIClient.fetch('GET /internal/inventory/entities', { - params: { - query: { - sortDirection, - sortField, - esQuery: stringifiedEsQuery, - }, - }, - signal, - }); - } - }, - [inventoryAPIClient, sortDirection, sortField, isControlPanelsInitiated, stringifiedEsQuery] - ); - - useEffectOnce(() => { - const refreshSubscription = refreshSubject$.subscribe(refresh); - return () => refreshSubscription.unsubscribe(); - }); - - function handlePageChange(nextPage: number) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - pagination: entityPaginationRt.encode({ - ...pagination, - unified: nextPage, - }), - }, - }); - } - - function handleSortChange(sorting: EuiDataGridSorting['columns'][0]) { - inventoryRoute.push('/', { - path: {}, - query: { - ...query, - sortField: sorting.id as EntityColumnIds, - sortDirection: sorting.direction, - }, - }); - } - - return ( - <> - <InventorySummary /> - <EntitiesGrid - entities={value.entities} - loading={loading} - sortDirection={sortDirection} - sortField={sortField} - onChangePage={handlePageChange} - onChangeSort={handleSortChange} - pageIndex={pageIndex} - /> - </> - ); -} diff --git a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx index f5a71e80bd9a..d43cba80dd17 100644 --- a/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/context/inventory_search_bar_context_provider/index.tsx @@ -7,7 +7,8 @@ import React, { createContext, useContext, type ReactChild } from 'react'; import { Subject } from 'rxjs'; import { DataView } from '@kbn/data-views-plugin/common'; -import { useAdHocInventoryDataView } from '../../hooks/use_adhoc_inventory_data_view'; +import { ENTITIES_LATEST_ALIAS } from '../../../common/entities'; +import { useAdHocDataView } from '../../hooks/use_adhoc_data_view'; interface InventorySearchBarContextType { searchBarContentSubject$: Subject<{ @@ -24,7 +25,7 @@ const InventorySearchBarContext = createContext<InventorySearchBarContextType>({ }); export function InventorySearchBarContextProvider({ children }: { children: ReactChild }) { - const { dataView } = useAdHocInventoryDataView(); + const { dataView } = useAdHocDataView(ENTITIES_LATEST_ALIAS); return ( <InventorySearchBarContext.Provider value={{ diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_adhoc_inventory_data_view.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_adhoc_data_view.ts similarity index 82% rename from x-pack/plugins/observability_solution/inventory/public/hooks/use_adhoc_inventory_data_view.ts rename to x-pack/plugins/observability_solution/inventory/public/hooks/use_adhoc_data_view.ts index ea7b337da37c..d648449f6d0a 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_adhoc_inventory_data_view.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_adhoc_data_view.ts @@ -9,9 +9,8 @@ import { DataView } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; import { useEffect, useState } from 'react'; import { useKibana } from './use_kibana'; -import { ENTITIES_LATEST_ALIAS } from '../../common/entities'; -export function useAdHocInventoryDataView() { +export function useAdHocDataView(title: string) { const { services: { dataViews, notifications }, } = useKibana(); @@ -21,7 +20,7 @@ export function useAdHocInventoryDataView() { async function fetchDataView() { try { const displayError = false; - return await dataViews.create({ title: ENTITIES_LATEST_ALIAS }, undefined, displayError); + return await dataViews.create({ title }, undefined, displayError); } catch (e) { const noDataScreen = e.message.includes('No matching indices found'); if (noDataScreen) { @@ -40,7 +39,7 @@ export function useAdHocInventoryDataView() { } fetchDataView().then(setDataView); - }, [dataViews, notifications.toasts]); + }, [dataViews, title, notifications.toasts]); return { dataView }; } diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts index 233c1a1076b7..f05cdcf21cb2 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.test.ts @@ -5,12 +5,12 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useDetailViewRedirect } from './use_detail_view_redirect'; import { useKibana } from './use_kibana'; import { CONTAINER_ID, - ENTITY_TYPES, + BUILT_IN_ENTITY_TYPES, HOST_NAME, SERVICE_NAME, } from '@kbn/observability-shared-plugin/common'; @@ -129,20 +129,34 @@ describe('useDetailViewRedirect', () => { expect(url).toBe('service-overview-url'); expect(mockGetRedirectUrl).toHaveBeenCalledWith({ serviceName: 'service-1', - environment: 'prod', }); }); [ - [ENTITY_TYPES.KUBERNETES.CLUSTER.ecs, 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c'], - [ENTITY_TYPES.KUBERNETES.CLUSTER.semconv, 'kubernetes_otel-cluster-overview'], - [ENTITY_TYPES.KUBERNETES.CRONJOB.ecs, 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013'], - [ENTITY_TYPES.KUBERNETES.DAEMONSET.ecs, 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013'], - [ENTITY_TYPES.KUBERNETES.DEPLOYMENT.ecs, 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013'], - [ENTITY_TYPES.KUBERNETES.JOB.ecs, 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013'], - [ENTITY_TYPES.KUBERNETES.NODE.ecs, 'kubernetes-b945b7b0-bcb1-11ec-b64f-7dd6e8e82013'], - [ENTITY_TYPES.KUBERNETES.POD.ecs, 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013'], - [ENTITY_TYPES.KUBERNETES.STATEFULSET.ecs, 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013'], + [ + BUILT_IN_ENTITY_TYPES.KUBERNETES.CLUSTER.ecs, + 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c', + ], + [BUILT_IN_ENTITY_TYPES.KUBERNETES.CLUSTER.semconv, 'kubernetes_otel-cluster-overview'], + [ + BUILT_IN_ENTITY_TYPES.KUBERNETES.CRONJOB.ecs, + 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013', + ], + [ + BUILT_IN_ENTITY_TYPES.KUBERNETES.DAEMONSET.ecs, + 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013', + ], + [ + BUILT_IN_ENTITY_TYPES.KUBERNETES.DEPLOYMENT.ecs, + 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013', + ], + [BUILT_IN_ENTITY_TYPES.KUBERNETES.JOB.ecs, 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013'], + [BUILT_IN_ENTITY_TYPES.KUBERNETES.NODE.ecs, 'kubernetes-b945b7b0-bcb1-11ec-b64f-7dd6e8e82013'], + [BUILT_IN_ENTITY_TYPES.KUBERNETES.POD.ecs, 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013'], + [ + BUILT_IN_ENTITY_TYPES.KUBERNETES.STATEFULSET.ecs, + 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013', + ], ].forEach(([entityType, dashboardId]) => { it(`getEntityRedirectUrl should return the correct URL for ${entityType} entity`, () => { const entity: InventoryEntity = { diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts index 36fa622e7466..ec193ae9dfca 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_detail_view_redirect.ts @@ -6,7 +6,7 @@ */ import { ASSET_DETAILS_LOCATOR_ID, - ENTITY_TYPES, + BUILT_IN_ENTITY_TYPES, SERVICE_OVERVIEW_LOCATOR_ID, type AssetDetailsLocatorParams, type ServiceOverviewParams, @@ -20,15 +20,19 @@ import type { InventoryEntity } from '../../common/entities'; import { useKibana } from './use_kibana'; const KUBERNETES_DASHBOARDS_IDS: Record<string, string> = { - [ENTITY_TYPES.KUBERNETES.CLUSTER.ecs]: 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c', - [ENTITY_TYPES.KUBERNETES.CLUSTER.semconv]: 'kubernetes_otel-cluster-overview', - [ENTITY_TYPES.KUBERNETES.CRONJOB.ecs]: 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013', - [ENTITY_TYPES.KUBERNETES.DAEMONSET.ecs]: 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013', - [ENTITY_TYPES.KUBERNETES.DEPLOYMENT.ecs]: 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013', - [ENTITY_TYPES.KUBERNETES.JOB.ecs]: 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013', - [ENTITY_TYPES.KUBERNETES.NODE.ecs]: 'kubernetes-b945b7b0-bcb1-11ec-b64f-7dd6e8e82013', - [ENTITY_TYPES.KUBERNETES.POD.ecs]: 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013', - [ENTITY_TYPES.KUBERNETES.STATEFULSET.ecs]: 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.CLUSTER.ecs]: 'kubernetes-f4dc26db-1b53-4ea2-a78b-1bfab8ea267c', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.CLUSTER.semconv]: 'kubernetes_otel-cluster-overview', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.CRONJOB.ecs]: 'kubernetes-0a672d50-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.DAEMONSET.ecs]: + 'kubernetes-85879010-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.DEPLOYMENT.ecs]: + 'kubernetes-5be46210-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.JOB.ecs]: 'kubernetes-9bf990a0-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.NODE.ecs]: 'kubernetes-b945b7b0-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.POD.ecs]: 'kubernetes-3d4d9290-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.SERVICE.ecs]: 'kubernetes-ff1b3850-bcb1-11ec-b64f-7dd6e8e82013', + [BUILT_IN_ENTITY_TYPES.KUBERNETES.STATEFULSET.ecs]: + 'kubernetes-21694370-bcb2-11ec-b64f-7dd6e8e82013', }; export const useDetailViewRedirect = () => { @@ -61,9 +65,6 @@ export const useDetailViewRedirect = () => { if (isBuiltinEntityOfType('service', entity)) { return serviceOverviewLocator?.getRedirectUrl({ serviceName: identityFieldsValue[identityFields[0]], - environment: entity.service?.environment - ? castArray(entity.service?.environment)[0] - : undefined, }); } diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts index 33758c9df449..dc9f5bf4a474 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_discover_redirect.ts @@ -4,74 +4,55 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { - ENTITY_DEFINITION_ID, - ENTITY_DISPLAY_NAME, - ENTITY_LAST_SEEN, - ENTITY_TYPE, -} from '@kbn/observability-shared-plugin/common'; -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import type { InventoryEntity } from '../../common/entities'; +import { useAdHocDataView } from './use_adhoc_data_view'; +import { useFetchEntityDefinition } from './use_fetch_entity_definition'; import { useKibana } from './use_kibana'; -import { useUnifiedSearchContext } from './use_unified_search_context'; -const ACTIVE_COLUMNS = [ENTITY_DISPLAY_NAME, ENTITY_TYPE, ENTITY_LAST_SEEN]; - -export const useDiscoverRedirect = () => { +export const useDiscoverRedirect = (entity: InventoryEntity) => { const { services: { share, application, entityManager }, } = useKibana(); - - const { - dataView, - searchState: { query, filters, panelFilters }, - } = useUnifiedSearchContext(); - - const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR'); - - const getDiscoverEntitiesRedirectUrl = useCallback( - (entity?: InventoryEntity) => { - const entityKqlFilter = entity - ? entityManager.entityClient.asKqlFilter({ - entity: { - identity_fields: entity.entityIdentityFields, - }, - ...entity, - }) - : ''; - - const kueryWithEntityDefinitionFilters = [ - query.query, - entityKqlFilter, - `${ENTITY_DEFINITION_ID} : builtin*`, - ] - .filter(Boolean) - .join(' AND '); - - return application.capabilities.discover?.show - ? discoverLocator?.getRedirectUrl({ - indexPatternId: dataView?.id ?? '', - columns: ACTIVE_COLUMNS, - query: { query: kueryWithEntityDefinitionFilters, language: 'kuery' }, - filters: [...filters, ...panelFilters], - }) - : undefined; - }, - [ - application.capabilities.discover?.show, - dataView?.id, - discoverLocator, - entityManager.entityClient, - filters, - panelFilters, - query.query, - ] + const { entityDefinitions, isEntityDefinitionLoading } = useFetchEntityDefinition( + entity.entityDefinitionId ); - const getDiscoverRedirectUrl = useCallback( - (entity?: InventoryEntity) => getDiscoverEntitiesRedirectUrl(entity), - [getDiscoverEntitiesRedirectUrl] + const title = useMemo( + () => + !isEntityDefinitionLoading && entityDefinitions && entityDefinitions?.length > 0 + ? entityDefinitions[0]?.indexPatterns?.join(',') + : '', + [entityDefinitions, isEntityDefinitionLoading] ); - return { getDiscoverRedirectUrl }; + const { dataView } = useAdHocDataView(title); + + const discoverLocator = share.url.locators.get('DISCOVER_APP_LOCATOR'); + + const getDiscoverEntitiesRedirectUrl = useCallback(() => { + const entityKqlFilter = entity + ? entityManager.entityClient.asKqlFilter({ + entity: { + identity_fields: entity.entityIdentityFields, + }, + ...entity, + }) + : ''; + + return application.capabilities.discover?.show + ? discoverLocator?.getRedirectUrl({ + indexPatternId: dataView?.id ?? '', + query: { query: entityKqlFilter, language: 'kuery' }, + }) + : undefined; + }, [ + application.capabilities.discover?.show, + dataView?.id, + discoverLocator, + entity, + entityManager.entityClient, + ]); + + return { getDiscoverEntitiesRedirectUrl, isEntityDefinitionLoading }; }; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts new file mode 100644 index 000000000000..9f6a0232891b --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_fetch_entity_definition.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useAbortableAsync } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import { useKibana } from './use_kibana'; + +export const useFetchEntityDefinition = (id: string) => { + const { + services: { entityManager }, + } = useKibana(); + + const { value, loading } = useAbortableAsync( + ({ signal }) => { + return entityManager.entityClient.getEntityDefinition(id); + }, + [entityManager.entityClient, id] + ); + + return { + entityDefinitions: value?.definitions, + isEntityDefinitionLoading: loading, + }; +}; diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_decoded_query_params.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_decoded_query_params.ts new file mode 100644 index 000000000000..c02a33a8c06f --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_decoded_query_params.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { decodeOrThrow } from '@kbn/io-ts-utils'; +import { useCallback, useMemo } from 'react'; +import { + entityPaginationRt, + entityTypesRt, + type EntityPagination, + type EntityType, +} from '../../common/rt_types'; +import { useInventoryParams } from './use_inventory_params'; +import { useInventoryRouter } from './use_inventory_router'; + +const entityTypeDecoder = decodeOrThrow(entityTypesRt); +const paginationDecoder = decodeOrThrow(entityPaginationRt); + +export function useInventoryDecodedQueryParams() { + const inventoryRoute = useInventoryRouter(); + const { + query, + query: { entityTypes, pagination }, + } = useInventoryParams('/*'); + + const resetUrlParam = useCallback( + (queryParamName: string) => { + inventoryRoute.push('/', { + path: {}, + query: { + ...query, + [queryParamName]: undefined, + }, + }); + }, + [inventoryRoute, query] + ); + + const selectedEntityTypes: EntityType = useMemo(() => { + try { + return entityTypeDecoder(entityTypes) || {}; + } catch (e) { + resetUrlParam('entityTypes'); + return {}; + } + }, [entityTypes, resetUrlParam]); + + const selectedPagination: EntityPagination = useMemo(() => { + try { + return paginationDecoder(pagination) || {}; + } catch (error) { + resetUrlParam('pagination'); + return {}; + } + }, [pagination, resetUrlParam]); + + return { entityTypes: selectedEntityTypes, pagination: selectedPagination }; +} diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_router.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_router.ts index a917daf576de..34aaf0b319d9 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_router.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_inventory_router.ts @@ -47,7 +47,7 @@ export function useInventoryRouter(): StatefulInventoryRouter { navigateToApp('inventory', { path: next, replace: true }); }, link: (path, ...args) => { - return http.basePath.prepend('/app/observability/inventory' + link(path, ...args)); + return http.basePath.prepend('/app/inventory' + link(path, ...args)); }, }), [navigateToApp, http.basePath] diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_is_loading_complete.test.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_is_loading_complete.test.ts index 61306a0b66a3..4706301eb0fc 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_is_loading_complete.test.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_is_loading_complete.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useIsLoadingComplete } from './use_is_loading_complete'; describe('useIsLoadingComplete', () => { diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts index 94df3a035f3b..c5715fb1d50b 100644 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts +++ b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_context.ts @@ -4,161 +4,19 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { buildEsQuery, type Filter, fromKueryExpression, type Query } from '@kbn/es-query'; import createContainer from 'constate'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { map, Subject, Subscription, tap } from 'rxjs'; -import { generateFilters } from '@kbn/data-plugin/public'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import deepEqual from 'fast-deep-equal'; -import { i18n } from '@kbn/i18n'; -import { useKibanaQuerySettings } from '@kbn/observability-shared-plugin/public'; -import { useAdHocInventoryDataView } from './use_adhoc_inventory_data_view'; -import { useUnifiedSearchUrl } from './use_unified_search_url'; -import { useKibana } from './use_kibana'; +import { useState } from 'react'; +import { Subject } from 'rxjs'; +import { ENTITIES_LATEST_ALIAS } from '../../common/entities'; +import { useAdHocDataView } from './use_adhoc_data_view'; function useUnifiedSearch() { - const [isControlPanelsInitiated, setIsControlPanelsInitiated] = useState(false); - const { dataView } = useAdHocInventoryDataView(); + const { dataView } = useAdHocDataView(ENTITIES_LATEST_ALIAS); const [refreshSubject$] = useState<Subject<void>>(new Subject()); - const { searchState, setSearchState } = useUnifiedSearchUrl(); - const kibanaQuerySettings = useKibanaQuerySettings(); - const { - services: { - data: { - query: { filterManager: filterManagerService, queryString: queryStringService }, - }, - notifications, - }, - } = useKibana(); - - useEffectOnce(() => { - if (!deepEqual(filterManagerService.getFilters(), searchState.filters)) { - filterManagerService.setFilters( - searchState.filters.map((item) => ({ - ...item, - meta: { ...item.meta, index: dataView?.id }, - })) - ); - } - - if (!deepEqual(queryStringService.getQuery(), searchState.query)) { - queryStringService.setQuery(searchState.query); - } - }); - - useEffect(() => { - const subscription = new Subscription(); - subscription.add( - filterManagerService - .getUpdates$() - .pipe( - map(() => filterManagerService.getFilters()), - tap((filters) => setSearchState({ type: 'SET_FILTERS', filters })) - ) - .subscribe() - ); - - subscription.add( - queryStringService - .getUpdates$() - .pipe( - map(() => queryStringService.getQuery() as Query), - tap((query) => setSearchState({ type: 'SET_QUERY', query })) - ) - .subscribe() - ); - - return () => { - subscription.unsubscribe(); - }; - }, [filterManagerService, queryStringService, setSearchState]); - - const validateQuery = useCallback( - (query: Query) => { - fromKueryExpression(query.query, kibanaQuerySettings); - }, - [kibanaQuerySettings] - ); - - const onQueryChange = useCallback( - (query: Query) => { - try { - validateQuery(query); - setSearchState({ type: 'SET_QUERY', query }); - } catch (e) { - const err = e as Error; - notifications.toasts.addDanger({ - title: i18n.translate('xpack.inventory.unifiedSearchContext.queryError', { - defaultMessage: 'Error while updating the new query', - }), - text: err.message, - }); - } - }, - [validateQuery, setSearchState, notifications.toasts] - ); - - const onPanelFiltersChange = useCallback( - (panelFilters: Filter[]) => { - setSearchState({ type: 'SET_PANEL_FILTERS', panelFilters }); - }, - [setSearchState] - ); - - const onFiltersChange = useCallback( - (filters: Filter[]) => { - setSearchState({ type: 'SET_FILTERS', filters }); - }, - [setSearchState] - ); - - const addFilter = useCallback( - ({ - fieldName, - operation, - value, - }: { - fieldName: string; - value: string; - operation: '+' | '-'; - }) => { - if (dataView) { - const newFilters = generateFilters( - filterManagerService, - fieldName, - value, - operation, - dataView - ); - setSearchState({ type: 'SET_FILTERS', filters: [...newFilters, ...searchState.filters] }); - } - }, - [dataView, filterManagerService, searchState.filters, setSearchState] - ); - - const stringifiedEsQuery = useMemo(() => { - if (dataView) { - return JSON.stringify( - buildEsQuery(dataView, searchState.query, [ - ...searchState.panelFilters, - ...searchState.filters, - ]) - ); - } - }, [dataView, searchState.panelFilters, searchState.filters, searchState.query]); return { - isControlPanelsInitiated, - setIsControlPanelsInitiated, dataView, refreshSubject$, - searchState, - addFilter, - stringifiedEsQuery, - onQueryChange, - onPanelFiltersChange, - onFiltersChange, }; } diff --git a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts b/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts deleted file mode 100644 index 17cf0ef0d959..000000000000 --- a/x-pack/plugins/observability_solution/inventory/public/hooks/use_unified_search_url.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { FilterStateStore } from '@kbn/es-query'; -import { useUrlState } from '@kbn/observability-shared-plugin/public'; -import { enumeration } from '@kbn/securitysolution-io-ts-types'; -import { fold } from 'fp-ts/lib/Either'; -import { constant, identity } from 'fp-ts/lib/function'; -import { pipe } from 'fp-ts/lib/pipeable'; -import * as t from 'io-ts'; -import { useReducer } from 'react'; -import deepEqual from 'fast-deep-equal'; - -const FilterRT = t.intersection([ - t.type({ - meta: t.partial({ - alias: t.union([t.null, t.string]), - disabled: t.boolean, - negate: t.boolean, - controlledBy: t.string, - group: t.string, - index: t.string, - isMultiIndex: t.boolean, - type: t.string, - key: t.string, - params: t.any, - value: t.any, - }), - }), - t.partial({ - query: t.record(t.string, t.any), - $state: t.type({ - store: enumeration('FilterStateStore', FilterStateStore), - }), - }), -]); -const FiltersRT = t.array(FilterRT); - -const QueryStateRT = t.type({ - language: t.string, - query: t.union([t.string, t.record(t.string, t.any)]), -}); - -const SearchStateRT = t.type({ - panelFilters: FiltersRT, - filters: FiltersRT, - query: QueryStateRT, -}); - -const encodeUrlState = SearchStateRT.encode; -const decodeUrlState = (value: unknown) => { - return pipe(SearchStateRT.decode(value), fold(constant(undefined), identity)); -}; - -type SearchState = t.TypeOf<typeof SearchStateRT>; - -const INITIAL_VALUE: SearchState = { - query: { language: 'kuery', query: '' }, - panelFilters: [], - filters: [], -}; - -export type StateAction = - | { type: 'SET_FILTERS'; filters: SearchState['filters'] } - | { type: 'SET_QUERY'; query: SearchState['query'] } - | { type: 'SET_PANEL_FILTERS'; panelFilters: SearchState['panelFilters'] }; - -const reducer = (state: SearchState, action: StateAction): SearchState => { - switch (action.type) { - case 'SET_FILTERS': - return { ...state, filters: action.filters }; - case 'SET_QUERY': - return { ...state, query: action.query }; - case 'SET_PANEL_FILTERS': - return { ...state, panelFilters: action.panelFilters }; - default: - return state; - } -}; - -export function useUnifiedSearchUrl() { - const [urlState, setUrlState] = useUrlState<SearchState>({ - defaultState: INITIAL_VALUE, - decodeUrlState, - encodeUrlState, - urlStateKey: '_a', - writeDefaultState: true, - }); - - const [searchState, setSearchState] = useReducer(reducer, urlState); - - if (!deepEqual(searchState, urlState)) { - setUrlState(searchState); - } - - return { searchState, setSearchState }; -} diff --git a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx index f34df1a3c8b3..6eab905a4069 100644 --- a/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/pages/inventory_page/index.tsx @@ -4,12 +4,83 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; +import { flattenObject } from '@kbn/observability-utils-common/object/flatten_object'; import React from 'react'; -import { GroupedInventory } from '../../components/grouped_inventory'; -import { UnifiedInventory } from '../../components/unified_inventory'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { EntitiesSummary } from '../../components/entities_summary'; +import { EntityGroupAccordion } from '../../components/entity_group_accordion'; +import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async'; +import { useInventoryDecodedQueryParams } from '../../hooks/use_inventory_decoded_query_params'; import { useInventoryParams } from '../../hooks/use_inventory_params'; +import { useKibana } from '../../hooks/use_kibana'; +import { useUnifiedSearchContext } from '../../hooks/use_unified_search_context'; +import { GroupBySelector } from '../../components/group_by_selector'; +import { groupEntityTypesByStatus } from '../../utils/group_entity_types_by_status'; export function InventoryPage() { - const { query } = useInventoryParams('/'); - return query.view === 'unified' ? <UnifiedInventory /> : <GroupedInventory />; + const { + services: { inventoryAPIClient }, + } = useKibana(); + const { refreshSubject$ } = useUnifiedSearchContext(); + const { + query: { kuery }, + } = useInventoryParams('/'); + const { entityTypes } = useInventoryDecodedQueryParams(); + + const { + value = { groupBy: ENTITY_TYPE, groups: [], entitiesCount: 0 }, + refresh, + loading, + } = useInventoryAbortableAsync( + ({ signal }) => { + const { entityTypesOff, entityTypesOn } = groupEntityTypesByStatus(entityTypes); + return inventoryAPIClient.fetch('GET /internal/inventory/entities/group_by/{field}', { + params: { + path: { + field: ENTITY_TYPE, + }, + query: { + includeEntityTypes: entityTypesOn.length ? JSON.stringify(entityTypesOn) : undefined, + excludeEntityTypes: entityTypesOff.length ? JSON.stringify(entityTypesOff) : undefined, + kuery, + }, + }, + signal, + }); + }, + [entityTypes, inventoryAPIClient, kuery] + ); + + useEffectOnce(() => { + const refreshSubscription = refreshSubject$.subscribe(refresh); + return () => refreshSubscription.unsubscribe(); + }); + + return ( + <> + <EuiFlexGroup gutterSize="none" justifyContent="spaceBetween" alignItems="center"> + <EuiFlexItem grow={false}> + <EntitiesSummary totalEntities={value.entitiesCount} totalGroups={value.groups.length} /> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <GroupBySelector /> + </EuiFlexItem> + </EuiFlexGroup> + <EuiSpacer size="m" /> + {value.groups.map((group) => { + const groupValue = flattenObject(group)[value.groupBy]; + return ( + <EntityGroupAccordion + key={`${value.groupBy}-${groupValue}`} + groupBy={value.groupBy} + groupValue={groupValue} + groupCount={group.count} + isLoading={loading} + /> + ); + })} + </> + ); } diff --git a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx index bf5f8324aab2..32db48130a89 100644 --- a/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx +++ b/x-pack/plugins/observability_solution/inventory/public/routes/config.tsx @@ -7,9 +7,9 @@ import { Outlet, createRouter } from '@kbn/typed-react-router-config'; import * as t from 'io-ts'; import React from 'react'; +import { defaultEntitySortField, entityColumnIdsRt } from '../../common/entities'; import { InventoryPageTemplate } from '../components/inventory_page_template'; import { InventoryPage } from '../pages/inventory_page'; -import { defaultEntitySortField, entityColumnIdsRt, entityViewRt } from '../../common/entities'; /** * The array of route definitions to be used when the application @@ -29,10 +29,9 @@ const inventoryRoutes = { sortDirection: t.union([t.literal('asc'), t.literal('desc')]), }), t.partial({ - view: entityViewRt, pagination: t.string, - _a: t.string, - controlPanels: t.string, + entityTypes: t.string, + kuery: t.string, }), ]), }), @@ -40,7 +39,6 @@ const inventoryRoutes = { query: { sortField: defaultEntitySortField, sortDirection: 'desc', - view: 'grouped', }, }, children: { diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts index c4c238fba5f8..d7806c2f6cb2 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_client.ts @@ -14,6 +14,7 @@ import { type EntityInventoryViewedParams, type EntityInventorySearchQuerySubmittedParams, type EntityViewClickedParams, + type EntityInventoryEntityTypeFilteredParams, } from './types'; export class TelemetryClient implements ITelemetryClient { @@ -36,4 +37,10 @@ export class TelemetryClient implements ITelemetryClient { public reportEntityViewClicked = (params: EntityViewClickedParams) => { this.analytics.reportEvent(TelemetryEventTypes.ENTITY_VIEW_CLICKED, params); }; + + public reportEntityInventoryEntityTypeFiltered = ( + params: EntityInventoryEntityTypeFilteredParams + ) => { + this.analytics.reportEvent(TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, params); + }; } diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts index ec2623fe2a2c..707852f9f3cd 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_events.ts @@ -58,6 +58,30 @@ const searchQuerySubmittedEventType: TelemetryEvent = { }, }; +const entityInventoryEntityTypeFilteredEventType: TelemetryEvent = { + eventType: TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, + schema: { + include_entity_types: { + type: 'array', + items: { + type: 'keyword', + _meta: { + description: 'List of Entity types used to filter for.', + }, + }, + }, + exclude_entity_types: { + type: 'array', + items: { + type: 'keyword', + _meta: { + description: 'List of Entity types used to filter out.', + }, + }, + }, + }, +}; + const entityViewClickedEventType: TelemetryEvent = { eventType: TelemetryEventTypes.ENTITY_VIEW_CLICKED, schema: { @@ -81,4 +105,5 @@ export const inventoryTelemetryEventBasedTypes = [ entityInventoryViewedEventType, searchQuerySubmittedEventType, entityViewClickedEventType, + entityInventoryEntityTypeFilteredEventType, ]; diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts index 639b771788f5..6a4854f75483 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/telemetry_service.test.ts @@ -13,6 +13,7 @@ import { type EntityViewClickedParams, type EntityInventorySearchQuerySubmittedParams, TelemetryEventTypes, + EntityInventoryEntityTypeFilteredParams, } from './types'; describe('TelemetryService', () => { @@ -145,4 +146,24 @@ describe('TelemetryService', () => { ); }); }); + + describe('#reportEntityInventoryEntityTypeFiltered', () => { + it('should report entity type filtered with properties', async () => { + const setupParams = getSetupParams(); + service.setup(setupParams); + const telemetry = service.start(); + const params: EntityInventoryEntityTypeFilteredParams = { + include_entity_types: ['container'], + exclude_entity_types: ['service'], + }; + + telemetry.reportEntityInventoryEntityTypeFiltered(params); + + expect(setupParams.analytics.reportEvent).toHaveBeenCalledTimes(1); + expect(setupParams.analytics.reportEvent).toHaveBeenCalledWith( + TelemetryEventTypes.ENTITY_INVENTORY_ENTITY_TYPE_FILTERED, + params + ); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts index 0d56f44c2c2f..e8ce3eb94e9b 100644 --- a/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts +++ b/x-pack/plugins/observability_solution/inventory/public/services/telemetry/types.ts @@ -30,6 +30,11 @@ export interface EntityInventorySearchQuerySubmittedParams { action: 'submit' | 'refresh'; } +export interface EntityInventoryEntityTypeFilteredParams { + include_entity_types: string[]; + exclude_entity_types: string[]; +} + export interface EntityViewClickedParams { entity_type: string; view_type: 'detail' | 'flyout'; @@ -39,7 +44,8 @@ export type TelemetryEventParams = | InventoryAddDataParams | EntityInventoryViewedParams | EntityInventorySearchQuerySubmittedParams - | EntityViewClickedParams; + | EntityViewClickedParams + | EntityInventoryEntityTypeFilteredParams; export interface ITelemetryClient { reportInventoryAddData(params: InventoryAddDataParams): void; @@ -48,6 +54,7 @@ export interface ITelemetryClient { params: EntityInventorySearchQuerySubmittedParams ): void; reportEntityViewClicked(params: EntityViewClickedParams): void; + reportEntityInventoryEntityTypeFiltered(params: EntityInventoryEntityTypeFilteredParams): void; } export enum TelemetryEventTypes { diff --git a/x-pack/plugins/observability_solution/inventory/public/utils/group_entity_types_by_status.ts b/x-pack/plugins/observability_solution/inventory/public/utils/group_entity_types_by_status.ts new file mode 100644 index 000000000000..f842663dd56e --- /dev/null +++ b/x-pack/plugins/observability_solution/inventory/public/utils/group_entity_types_by_status.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EntityType } from '../../common/rt_types'; + +export function groupEntityTypesByStatus(entityTypes: EntityType) { + const entityTypesKeys = Object.keys(entityTypes); + return { + entityTypesOn: entityTypesKeys.filter((key) => entityTypes[key] === 'on').sort(), + entityTypesOff: entityTypesKeys.filter((key) => entityTypes[key] === 'off').sort(), + }; +} diff --git a/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client.ts/create_alerts_client.ts b/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client/create_alerts_client.ts similarity index 93% rename from x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client.ts/create_alerts_client.ts rename to x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client/create_alerts_client.ts index 150e946fd98d..878abd516e5b 100644 --- a/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client.ts/create_alerts_client.ts +++ b/x-pack/plugins/observability_solution/inventory/server/lib/create_alerts_client/create_alerts_client.ts @@ -8,6 +8,7 @@ import { isEmpty } from 'lodash'; import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { InventoryRouteHandlerResources } from '../../routes/types'; export type AlertsClient = Awaited<ReturnType<typeof createAlertsClient>>; @@ -18,13 +19,7 @@ export async function createAlertsClient({ }: Pick<InventoryRouteHandlerResources, 'plugins' | 'request'>) { const ruleRegistryPluginStart = await plugins.ruleRegistry.start(); const alertsClient = await ruleRegistryPluginStart.getRacClientWithRequest(request); - const alertsIndices = await alertsClient.getAuthorizedAlertsIndices([ - 'logs', - 'infrastructure', - 'apm', - 'slo', - 'observability', - ]); + const alertsIndices = await alertsClient.getAuthorizedAlertsIndices(OBSERVABILITY_RULE_TYPE_IDS); if (!alertsIndices || isEmpty(alertsIndices)) { throw Error('No alert indices exist'); diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts index 87d0c375149e..ead3109060d1 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_groups.ts @@ -5,34 +5,58 @@ * 2.0. */ -import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import { kqlQuery } from '@kbn/observability-plugin/server'; +import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITIES_LATEST_ALIAS, - type EntityGroup, MAX_NUMBER_OF_ENTITIES, + type EntityGroup, } from '../../../common/entities'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; export async function getEntityGroupsBy({ inventoryEsClient, field, - esQuery, + kuery, + includeEntityTypes = [], + excludeEntityTypes = [], }: { inventoryEsClient: ObservabilityElasticsearchClient; field: string; - esQuery?: QueryDslQueryContainer; -}) { + includeEntityTypes?: string[]; + excludeEntityTypes?: string[]; + kuery?: string; +}): Promise<EntityGroup[]> { const from = `FROM ${ENTITIES_LATEST_ALIAS}`; const where = [getBuiltinEntityDefinitionIdESQLWhereClause()]; + const params: ScalarValue[] = []; + + if (includeEntityTypes.length) { + where.push(`WHERE ${ENTITY_TYPE} IN (${includeEntityTypes.map(() => '?').join()})`); + params.push(...includeEntityTypes); + } + + if (excludeEntityTypes.length) { + where.push(`WHERE ${ENTITY_TYPE} NOT IN (${excludeEntityTypes.map(() => '?').join()})`); + params.push(...excludeEntityTypes); + } const group = `STATS count = COUNT(*) by ${field}`; const sort = `SORT ${field} asc`; const limit = `LIMIT ${MAX_NUMBER_OF_ENTITIES}`; const query = [from, ...where, group, sort, limit].join(' | '); - return inventoryEsClient.esql<EntityGroup>('get_entities_groups', { - query, - filter: esQuery, - }); + const { hits } = await inventoryEsClient.esql<EntityGroup, { transform: 'plain' }>( + 'get_entities_groups', + { + query, + filter: { bool: { filter: kqlQuery(kuery) } }, + params, + }, + { transform: 'plain' } + ); + + return hits; } diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts index e944e27379ab..c1f7894a178b 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_entity_types.ts @@ -7,7 +7,6 @@ import { type ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITY_TYPE } from '@kbn/observability-shared-plugin/common'; -import type { EntityInstance } from '@kbn/entities-schema'; import { ENTITIES_LATEST_ALIAS } from '../../../common/entities'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; @@ -16,14 +15,21 @@ export async function getEntityTypes({ }: { inventoryEsClient: ObservabilityElasticsearchClient; }) { - const entityTypesEsqlResponse = await inventoryEsClient.esql<{ - entity: Pick<EntityInstance['entity'], 'type'>; - }>('get_entity_types', { - query: `FROM ${ENTITIES_LATEST_ALIAS} + const entityTypesEsqlResponse = await inventoryEsClient.esql< + { + 'entity.type': string; + }, + { transform: 'plain' } + >( + 'get_entity_types', + { + query: `FROM ${ENTITIES_LATEST_ALIAS} | ${getBuiltinEntityDefinitionIdESQLWhereClause()} | STATS count = COUNT(${ENTITY_TYPE}) BY ${ENTITY_TYPE} `, - }); + }, + { transform: 'plain' } + ); - return entityTypesEsqlResponse.map((response) => response.entity.type); + return entityTypesEsqlResponse.hits.map((response) => response['entity.type']); } diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts index c4bf13c5ec14..83f576220d12 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities.ts @@ -5,19 +5,20 @@ * 2.0. */ -import type { QueryDslQueryContainer, ScalarValue } from '@elastic/elasticsearch/lib/api/types'; -import type { EntityInstance } from '@kbn/entities-schema'; +import type { ScalarValue } from '@elastic/elasticsearch/lib/api/types'; +import { kqlQuery } from '@kbn/observability-plugin/server'; import { ENTITY_DISPLAY_NAME, ENTITY_LAST_SEEN, ENTITY_TYPE, } from '@kbn/observability-shared-plugin/common'; +import { unflattenObject } from '@kbn/observability-utils-common/object/unflatten_object'; import type { ObservabilityElasticsearchClient } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; import { ENTITIES_LATEST_ALIAS, - InventoryEntity, MAX_NUMBER_OF_ENTITIES, type EntityColumnIds, + type InventoryEntity, } from '../../../common/entities'; import { getBuiltinEntityDefinitionIdESQLWhereClause } from './query_helper'; @@ -35,13 +36,13 @@ export async function getLatestEntities({ inventoryEsClient, sortDirection, sortField, - esQuery, + kuery, entityTypes, }: { inventoryEsClient: ObservabilityElasticsearchClient; sortDirection: 'asc' | 'desc'; sortField: EntityColumnIds; - esQuery?: QueryDslQueryContainer; + kuery?: string; entityTypes?: string[]; }): Promise<InventoryEntity[]> { // alertsCount doesn't exist in entities index. Ignore it and sort by entity.lastSeenTimestamp by default. @@ -62,17 +63,38 @@ export async function getLatestEntities({ const query = [from, ...where, sort, limit].join(' | '); - const latestEntitiesEsqlResponse = await inventoryEsClient.esql<EntityInstance>( + const latestEntitiesEsqlResponse = await inventoryEsClient.esql< + { + 'entity.id': string; + 'entity.type': string; + 'entity.definition_id': string; + 'entity.display_name': string; + 'entity.identity_fields': string | string[]; + 'entity.last_seen_timestamp': string; + 'entity.definition_version': string; + 'entity.schema_version': string; + } & Record<string, ScalarValue | ScalarValue[]>, + { transform: 'plain' } + >( 'get_latest_entities', { query, - filter: esQuery, + filter: { bool: { filter: kqlQuery(kuery) } }, params, - } + }, + { transform: 'plain' } ); - return latestEntitiesEsqlResponse.map((lastestEntity) => { - const { entity, ...metadata } = lastestEntity; + return latestEntitiesEsqlResponse.hits.map((latestEntity) => { + Object.keys(latestEntity).forEach((key) => { + const keyOfObject = key as keyof typeof latestEntity; + // strip out multi-field aliases + if (keyOfObject.endsWith('.text') || keyOfObject.endsWith('.keyword')) { + delete latestEntity[keyOfObject]; + } + }); + + const { entity, ...metadata } = unflattenObject(latestEntity); return { entityId: entity.id, diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts index 0f1ace040723..d4c69505a463 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/get_latest_entities_alerts.ts @@ -7,7 +7,7 @@ import { termQuery } from '@kbn/observability-plugin/server'; import { ALERT_STATUS, ALERT_STATUS_ACTIVE } from '@kbn/rule-data-utils'; -import { AlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; +import { AlertsClient } from '../../lib/create_alerts_client/create_alerts_client'; import { getGroupByTermsAgg } from './get_group_by_terms_agg'; import { IdentityFieldsPerEntityType } from './get_identity_fields_per_entity_type'; diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts index 992729a9c1aa..c4a0a21f50eb 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/entities/route.ts @@ -12,7 +12,7 @@ import { createObservabilityEsClient } from '@kbn/observability-utils-server/es/ import * as t from 'io-ts'; import { orderBy } from 'lodash'; import { InventoryEntity, entityColumnIdsRt } from '../../../common/entities'; -import { createAlertsClient } from '../../lib/create_alerts_client.ts/create_alerts_client'; +import { createAlertsClient } from '../../lib/create_alerts_client/create_alerts_client'; import { createInventoryServerRoute } from '../create_inventory_server_route'; import { getEntityGroupsBy } from './get_entity_groups'; import { getEntityTypes } from './get_entity_types'; @@ -47,7 +47,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ sortDirection: t.union([t.literal('asc'), t.literal('desc')]), }), t.partial({ - esQuery: jsonRt.pipe(t.UnknownRecord), + kuery: t.string, entityTypes: jsonRt.pipe(t.array(t.string)), }), ]), @@ -69,7 +69,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ plugin: `@kbn/${INVENTORY_APP_ID}-plugin`, }); - const { sortDirection, sortField, esQuery, entityTypes } = params.query; + const { sortDirection, sortField, kuery, entityTypes } = params.query; const [alertsClient, latestEntities] = await Promise.all([ createAlertsClient({ plugins, request }), @@ -77,7 +77,7 @@ export const listLatestEntitiesRoute = createInventoryServerRoute({ inventoryEsClient, sortDirection, sortField, - esQuery, + kuery, entityTypes, }), ]); @@ -113,7 +113,9 @@ export const groupEntitiesByRoute = createInventoryServerRoute({ t.type({ path: t.type({ field: t.literal(ENTITY_TYPE) }) }), t.partial({ query: t.partial({ - esQuery: jsonRt.pipe(t.UnknownRecord), + includeEntityTypes: jsonRt.pipe(t.array(t.string)), + excludeEntityTypes: jsonRt.pipe(t.array(t.string)), + kuery: t.string, }), }), ]), @@ -129,12 +131,14 @@ export const groupEntitiesByRoute = createInventoryServerRoute({ }); const { field } = params.path; - const { esQuery } = params.query ?? {}; + const { kuery, includeEntityTypes, excludeEntityTypes } = params.query ?? {}; const groups = await getEntityGroupsBy({ inventoryEsClient, field, - esQuery, + kuery, + includeEntityTypes, + excludeEntityTypes, }); const entitiesCount = groups.reduce((acc, group) => acc + group.count, 0); diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts index 2f59478f17c0..c3fd3971f09d 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/has_data/get_has_data.ts @@ -17,14 +17,18 @@ export async function getHasData({ logger: Logger; }) { try { - const esqlResults = await inventoryEsClient.esql<{ _count: number }>('get_has_data', { - query: `FROM ${ENTITIES_LATEST_ALIAS} + const esqlResults = await inventoryEsClient.esql<{ _count: number }, { transform: 'plain' }>( + 'get_has_data', + { + query: `FROM ${ENTITIES_LATEST_ALIAS} | ${getBuiltinEntityDefinitionIdESQLWhereClause()} | STATS _count = COUNT(*) | LIMIT 1`, - }); + }, + { transform: 'plain' } + ); - const totalCount = esqlResults[0]._count; + const totalCount = esqlResults.hits[0]._count; return { hasData: totalCount > 0 }; } catch (e) { diff --git a/x-pack/plugins/observability_solution/inventory/server/routes/types.ts b/x-pack/plugins/observability_solution/inventory/server/routes/types.ts index 397710509dab..646d34888ae9 100644 --- a/x-pack/plugins/observability_solution/inventory/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/inventory/server/routes/types.ts @@ -30,10 +30,8 @@ export interface InventoryRouteHandlerResources { } export interface InventoryRouteCreateOptions { - options: { - timeout?: { - idleSocket?: number; - }; - tags: Array<'access:inventory'>; + timeout?: { + idleSocket?: number; }; + tags: Array<'access:inventory'>; } diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json index 5094201cc297..561ca62eaf97 100644 --- a/x-pack/plugins/observability_solution/inventory/tsconfig.json +++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json @@ -54,11 +54,10 @@ "@kbn/storybook", "@kbn/dashboard-plugin", "@kbn/deeplinks-analytics", - "@kbn/controls-plugin", - "@kbn/securitysolution-io-ts-types", "@kbn/react-hooks", "@kbn/observability-utils-common", "@kbn/observability-utils-browser", - "@kbn/observability-utils-server" + "@kbn/observability-utils-server", + "@kbn/kibana-utils-plugin" ] } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/routes/types.ts b/x-pack/plugins/observability_solution/investigate_app/server/routes/types.ts index afb022cdc9b7..0cee1b701539 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/routes/types.ts @@ -53,10 +53,7 @@ export interface InvestigateAppRouteHandlerResources { } export interface InvestigateAppRouteCreateOptions { - options: { - timeout?: { - idleSocket?: number; - }; - tags: []; + timeout?: { + idleSocket?: number; }; } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts index bf1070307742..c5eaf3f4c3d8 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/get_alerts_client.ts @@ -8,6 +8,7 @@ import { isEmpty } from 'lodash'; import { ESSearchRequest, InferSearchResponseOf } from '@kbn/es-types'; import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { InvestigateAppRouteHandlerResources } from '../routes/types'; export type AlertsClient = Awaited<ReturnType<typeof getAlertsClient>>; @@ -18,14 +19,7 @@ export async function getAlertsClient({ }: Pick<InvestigateAppRouteHandlerResources, 'plugins' | 'request'>) { const ruleRegistryPluginStart = await plugins.ruleRegistry.start(); const alertsClient = await ruleRegistryPluginStart.getRacClientWithRequest(request); - const alertsIndices = await alertsClient.getAuthorizedAlertsIndices([ - 'logs', - 'infrastructure', - 'apm', - 'slo', - 'uptime', - 'observability', - ]); + const alertsIndices = await alertsClient.getAuthorizedAlertsIndices(OBSERVABILITY_RULE_TYPE_IDS); if (!alertsIndices || isEmpty(alertsIndices)) { throw Error('No alert indices exist'); diff --git a/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc index ee8881a4479e..02fcff85404a 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_data_access/kibana.jsonc @@ -1,7 +1,7 @@ { "type": "plugin", "id": "@kbn/logs-data-access-plugin", - "owner": ["@elastic/obs-knowledge-team", "@elastic/obs-ux-logs-team"], + "owner": ["@elastic/obs-ux-logs-team"], "plugin": { "id": "logsDataAccess", "server": true, diff --git a/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts b/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts index f329907f145e..e44b9cadcae0 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts +++ b/x-pack/plugins/observability_solution/logs_data_access/public/services/log_sources_service/index.ts @@ -12,23 +12,32 @@ import { RegisterServicesParams } from '../register_services'; export function createLogSourcesService(params: RegisterServicesParams): LogSourcesService { const { uiSettings } = params.deps; - return { - async getLogSources() { - const logSources = uiSettings.get<string[]>(OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID); - return logSources.map((logSource) => ({ - indexPattern: logSource, - })); - }, - async getFlattenedLogSources() { - const logSources = await this.getLogSources(); - return flattenLogSources(logSources); - }, - async setLogSources(sources: LogSource[]) { - await uiSettings.set( - OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID, - sources.map((source) => source.indexPattern) - ); - return; - }, + + const getLogSources = async () => { + const logSources = uiSettings.get<string[]>(OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID); + return logSources.map((logSource) => ({ + indexPattern: logSource, + })); + }; + + const getFlattenedLogSources = async () => { + const logSources = await getLogSources(); + return flattenLogSources(logSources); + }; + + const setLogSources = async (sources: LogSource[]) => { + await uiSettings.set( + OBSERVABILITY_LOGS_DATA_ACCESS_LOG_SOURCES_ID, + sources.map((source) => source.indexPattern) + ); + return; + }; + + const logSourcesService: LogSourcesService = { + getLogSources, + getFlattenedLogSources, + setLogSources, }; + + return logSourcesService; } diff --git a/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_error_rate_timeseries/get_logs_error_rate_timeseries.ts b/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_error_rate_timeseries/get_logs_error_rate_timeseries.ts index 4766436fdebf..ac4f62932b64 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_error_rate_timeseries/get_logs_error_rate_timeseries.ts +++ b/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_error_rate_timeseries/get_logs_error_rate_timeseries.ts @@ -138,7 +138,7 @@ export function createGetLogErrorRateTimeseries() { const totalErrorsCount = logErrorCount + errorLogLevelErrorsCount; return { x: timeseriesBucket.key, - y: totalErrorsCount, + y: totalErrorsCount / (intervalString / 60), }; }); diff --git a/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_rate_timeseries/get_logs_rate_timeseries.ts b/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_rate_timeseries/get_logs_rate_timeseries.ts index cdcf360405e7..9df26b48db09 100644 --- a/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_rate_timeseries/get_logs_rate_timeseries.ts +++ b/x-pack/plugins/observability_solution/logs_data_access/server/services/get_logs_rate_timeseries/get_logs_rate_timeseries.ts @@ -104,12 +104,10 @@ export function createGetLogsRateTimeseries() { return buckets ? buckets.reduce<LogsRateTimeseriesReturnType>((acc, bucket) => { - const totalCount = bucket.doc_count; - const timeseries = bucket.timeseries.buckets.map((timeseriesBucket) => { return { x: timeseriesBucket.key, - y: timeseriesBucket.doc_count / totalCount, + y: timeseriesBucket.doc_count / (intervalString / 60), }; }); diff --git a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc index f5e9f76c2ace..69539098f246 100644 --- a/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/logs_shared/kibana.jsonc @@ -18,11 +18,13 @@ "observabilityShared", "share", "usageCollection", + "embeddable", ], "optionalPlugins": [ "observabilityAIAssistant", ], - "requiredBundles": ["kibanaUtils", "kibanaReact", "unifiedDocViewer"], + "requiredBundles": ["kibanaUtils", "kibanaReact"], "extraPublicDirs": ["common"] } } + \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx b/x-pack/plugins/observability_solution/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx index 183950edf977..8635df14731a 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/containers/logs/log_summary/log_summary.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; // We are using this inside a `jest.mock` call. Jest requires dynamic dependencies to be prefixed with `mock` import { coreMock as mockCoreMock } from '@kbn/core/public/mocks'; @@ -56,14 +56,14 @@ describe('useLogSummary hook', () => { .mockResolvedValueOnce(firstMockResponse) .mockResolvedValueOnce(secondMockResponse); - const { result, waitForNextUpdate, rerender } = renderHook( + const { result, rerender } = renderHook( ({ logViewReference }) => useLogSummary(logViewReference, startTimestamp, endTimestamp, null), { initialProps: { logViewReference: LOG_VIEW_REFERENCE }, } ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( @@ -75,7 +75,7 @@ describe('useLogSummary hook', () => { expect(result.current.buckets).toEqual(firstMockResponse.data.buckets); rerender({ logViewReference: CHANGED_LOG_VIEW_REFERENCE }); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(2); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( @@ -101,7 +101,7 @@ describe('useLogSummary hook', () => { .mockResolvedValueOnce(firstMockResponse) .mockResolvedValueOnce(secondMockResponse); - const { result, waitForNextUpdate, rerender } = renderHook( + const { result, rerender } = renderHook( ({ filterQuery }) => useLogSummary(LOG_VIEW_REFERENCE, startTimestamp, endTimestamp, filterQuery), { @@ -109,7 +109,7 @@ describe('useLogSummary hook', () => { } ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( @@ -121,7 +121,7 @@ describe('useLogSummary hook', () => { expect(result.current.buckets).toEqual(firstMockResponse.data.buckets); rerender({ filterQuery: 'CHANGED_FILTER_QUERY' }); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(2); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( @@ -139,7 +139,7 @@ describe('useLogSummary hook', () => { .mockResolvedValueOnce(createMockResponse([])); const firstRange = createMockDateRange(); - const { waitForNextUpdate, rerender } = renderHook( + const { rerender } = renderHook( ({ startTimestamp, endTimestamp }) => useLogSummary(LOG_VIEW_REFERENCE, startTimestamp, endTimestamp, null), { @@ -147,7 +147,7 @@ describe('useLogSummary hook', () => { } ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( expect.objectContaining({ @@ -160,7 +160,7 @@ describe('useLogSummary hook', () => { const secondRange = createMockDateRange('now-20s', 'now'); rerender(secondRange); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(2); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( @@ -176,7 +176,7 @@ describe('useLogSummary hook', () => { fetchLogSummaryMock.mockResolvedValueOnce(createMockResponse([])); const firstRange = createMockDateRange(); - const { waitForNextUpdate, rerender } = renderHook( + const { rerender } = renderHook( ({ startTimestamp, endTimestamp }) => useLogSummary(LOG_VIEW_REFERENCE, startTimestamp, endTimestamp, null), { @@ -188,7 +188,7 @@ describe('useLogSummary hook', () => { // intentionally don't wait for an update to test the throttling rerender(secondRange); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchLogSummaryMock).toHaveBeenCalledTimes(1); expect(fetchLogSummaryMock).toHaveBeenLastCalledWith( diff --git a/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx index 0321651607ed..e6ec419ae8b0 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/plugin.tsx @@ -61,7 +61,6 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { logsDataAccess, observabilityAIAssistant, share, - fieldFormats, } = plugins; const logViews = this.logViews.start({ @@ -72,14 +71,14 @@ export class LogsSharedPlugin implements LogsSharedClientPluginClass { }); const LogsOverview = createLogsOverview({ - core, charts, logsDataAccess, search: data.search.search, + searchSource: data.search.searchSource, uiSettings: settings, share, dataViews, - fieldFormats, + embeddable: plugins.embeddable, }); if (!observabilityAIAssistant) { diff --git a/x-pack/plugins/observability_solution/logs_shared/public/types.ts b/x-pack/plugins/observability_solution/logs_shared/public/types.ts index e2435fa1f491..90bbd89f2481 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/types.ts +++ b/x-pack/plugins/observability_solution/logs_shared/public/types.ts @@ -15,6 +15,8 @@ import type { ObservabilityAIAssistantPublicStart } from '@kbn/observability-ai- import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; +import { EmbeddableStart } from '@kbn/embeddable-plugin/public'; +import { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import type { LogsSharedLocators } from '../common/locators'; import type { LogAIAssistantProps } from './components/log_ai_assistant/log_ai_assistant'; import type { SelfContainedLogsOverview } from './components/logs_overview'; @@ -46,6 +48,8 @@ export interface LogsSharedClientStartDeps { share: SharePluginStart; uiActions: UiActionsStart; fieldFormats: FieldFormatsStart; + embeddable: EmbeddableStart; + savedSearch: SavedSearchPublicPluginStart; } export type LogsSharedClientCoreSetup = CoreSetup< diff --git a/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_data_search_request.test.tsx b/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_data_search_request.test.tsx index 33369c1125e1..08907b162708 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_data_search_request.test.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_data_search_request.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import React from 'react'; import { firstValueFrom, Observable, of, Subject } from 'rxjs'; import type { ISearchGeneric, IKibanaSearchResponse } from '@kbn/search-types'; diff --git a/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_latest_partial_data_search_response.test.tsx b/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_latest_partial_data_search_response.test.tsx index a4b01be03d80..24433f23bc67 100644 --- a/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_latest_partial_data_search_response.test.tsx +++ b/x-pack/plugins/observability_solution/logs_shared/public/utils/data_search/use_latest_partial_data_search_response.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { BehaviorSubject, Observable, of, Subject } from 'rxjs'; import { IKibanaSearchRequest } from '@kbn/search-types'; import { ParsedDataSearchRequestDescriptor, ParsedKibanaSearchResponse } from './types'; diff --git a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json index f171c79afccd..acaed5073a17 100644 --- a/x-pack/plugins/observability_solution/logs_shared/tsconfig.json +++ b/x-pack/plugins/observability_solution/logs_shared/tsconfig.json @@ -49,5 +49,7 @@ "@kbn/charts-plugin", "@kbn/core-ui-settings-common", "@kbn/field-formats-plugin", + "@kbn/embeddable-plugin", + "@kbn/saved-search-plugin", ] } diff --git a/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc b/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc index 17ad2991f315..3188d318b64c 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc +++ b/x-pack/plugins/observability_solution/metrics_data_access/kibana.jsonc @@ -1,10 +1,7 @@ { "type": "plugin", "id": "@kbn/metrics-data-access-plugin", - "owner": [ - "@elastic/obs-knowledge-team", - "@elastic/obs-ux-infra_services-team" - ], + "owner": ["@elastic/obs-ux-infra_services-team"], "group": "observability", "visibility": "private", "description": "Exposes utilities for accessing metrics data", diff --git a/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/container/use_container_metrics_table.test.ts b/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/container/use_container_metrics_table.test.ts index ec22fe1df6f9..d9da73336bf0 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/container/use_container_metrics_table.test.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/container/use_container_metrics_table.test.ts @@ -7,7 +7,7 @@ import { useContainerMetricsTable } from './use_container_metrics_table'; import { useInfrastructureNodeMetrics } from '../shared'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createMetricsClientMock } from '../test_helpers'; jest.mock('../shared', () => ({ @@ -33,6 +33,12 @@ describe('useContainerMetricsTable hook', () => { }, }; + // include this to prevent rendering error in test + useInfrastructureNodeMetricsMock.mockReturnValue({ + isLoading: true, + data: { state: 'empty-indices' }, + }); + renderHook(() => useContainerMetricsTable({ timerange: { from: 'now-30d', to: 'now' }, diff --git a/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/host/use_host_metrics_table.test.ts b/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/host/use_host_metrics_table.test.ts index f34fccc6e442..ab21b0c1ca76 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/host/use_host_metrics_table.test.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/host/use_host_metrics_table.test.ts @@ -7,7 +7,7 @@ import { useHostMetricsTable } from './use_host_metrics_table'; import { useInfrastructureNodeMetrics } from '../shared'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createMetricsClientMock } from '../test_helpers'; jest.mock('../shared', () => ({ @@ -40,6 +40,12 @@ describe('useHostMetricsTable hook', () => { }, }; + // include this to prevent rendering error in test + useInfrastructureNodeMetricsMock.mockReturnValue({ + isLoading: true, + data: { state: 'empty-indices' }, + }); + renderHook(() => useHostMetricsTable({ timerange: { from: 'now-30d', to: 'now' }, diff --git a/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/pod/use_pod_metrics_table.test.ts b/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/pod/use_pod_metrics_table.test.ts index fc6d14b03d08..14f3330e856a 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/pod/use_pod_metrics_table.test.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/public/components/infrastructure_node_metrics_tables/pod/use_pod_metrics_table.test.ts @@ -7,7 +7,7 @@ import { usePodMetricsTable } from './use_pod_metrics_table'; import { useInfrastructureNodeMetrics } from '../shared'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { createMetricsClientMock } from '../test_helpers'; jest.mock('../shared', () => ({ @@ -33,6 +33,12 @@ describe('usePodMetricsTable hook', () => { }, }; + // include this to prevent rendering error in test + useInfrastructureNodeMetricsMock.mockReturnValue({ + isLoading: true, + data: { state: 'empty-indices' }, + }); + renderHook(() => usePodMetricsTable({ timerange: { from: 'now-30d', to: 'now' }, diff --git a/x-pack/plugins/observability_solution/metrics_data_access/public/pages/link_to/use_asset_detail_redirect.test.tsx b/x-pack/plugins/observability_solution/metrics_data_access/public/pages/link_to/use_asset_detail_redirect.test.tsx index cf783e78bd67..1183979d6058 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/public/pages/link_to/use_asset_detail_redirect.test.tsx +++ b/x-pack/plugins/observability_solution/metrics_data_access/public/pages/link_to/use_asset_detail_redirect.test.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; import { sharePluginMock } from '@kbn/share-plugin/public/mocks'; diff --git a/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts index 246988ed9630..6449fcc30b2d 100644 --- a/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/observability_solution/metrics_data_access/server/lib/adapters/framework/adapter_types.ts @@ -19,7 +19,7 @@ import { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/serv import { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginSetup } from '@kbn/spaces-plugin/server'; -import { PluginSetupContract as AlertingPluginContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { MlPluginSetup } from '@kbn/ml-plugin/server'; import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; @@ -27,7 +27,7 @@ import { VersionedRouteConfig } from '@kbn/core-http-server'; import { MetricsDataPluginSetup } from '../../../types'; export interface InfraServerPluginSetupDeps { - alerting: AlertingPluginContract; + alerting: AlertingServerSetup; data: DataPluginSetup; home: HomeServerPluginSetup; features: FeaturesPluginSetup; diff --git a/x-pack/plugins/observability_solution/observability/common/constants.ts b/x-pack/plugins/observability_solution/observability/common/constants.ts index 0286e4bef082..785f1caf4cb6 100644 --- a/x-pack/plugins/observability_solution/observability/common/constants.ts +++ b/x-pack/plugins/observability_solution/observability/common/constants.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { + AlertConsumers, + STACK_RULE_TYPE_IDS_SUPPORTED_BY_OBSERVABILITY, + OBSERVABILITY_RULE_TYPE_IDS, +} from '@kbn/rule-data-utils'; import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { RuleCreationValidConsumer } from '@kbn/triggers-actions-ui-plugin/public'; @@ -20,6 +24,7 @@ export const observabilityAlertFeatureIds: ValidFeatureId[] = [ AlertConsumers.UPTIME, AlertConsumers.SLO, AlertConsumers.OBSERVABILITY, + AlertConsumers.ALERTS, ]; export const observabilityRuleCreationValidConsumers: RuleCreationValidConsumer[] = [ @@ -29,3 +34,8 @@ export const observabilityRuleCreationValidConsumers: RuleCreationValidConsumer[ ]; export const EventsAsUnit = 'events'; + +export const OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES = [ + ...OBSERVABILITY_RULE_TYPE_IDS, + ...STACK_RULE_TYPE_IDS_SUPPORTED_BY_OBSERVABILITY, +]; diff --git a/x-pack/plugins/observability_solution/observability/kibana.jsonc b/x-pack/plugins/observability_solution/observability/kibana.jsonc index 1c09efd7dd6e..3a888ce14e5e 100644 --- a/x-pack/plugins/observability_solution/observability/kibana.jsonc +++ b/x-pack/plugins/observability_solution/observability/kibana.jsonc @@ -56,7 +56,8 @@ "serverless", "guidedOnboarding", "observabilityAIAssistant", - "investigate" + "investigate", + "streams" ], "requiredBundles": [ "data", @@ -70,4 +71,4 @@ "common" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx index b7da84869679..d64d8dcbb1a4 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.test.tsx @@ -12,8 +12,8 @@ import { uiSettingsServiceMock } from '@kbn/core-ui-settings-browser-mocks'; import { ObservabilityAlertSearchBarProps, Services } from './types'; import { ObservabilityAlertSearchBar } from './alert_search_bar'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; import { render } from '../../utils/test_helper'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../../../common/constants'; const getAlertsSearchBarMock = jest.fn(); const ALERT_SEARCH_BAR_DATA_TEST_SUBJ = 'alerts-search-bar'; @@ -69,7 +69,7 @@ describe('ObservabilityAlertSearchBar', () => { expect(getAlertsSearchBarMock).toHaveBeenCalledWith( expect.objectContaining({ appName: 'testAppName', - featureIds: observabilityAlertFeatureIds, + ruleTypeIds: OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, rangeFrom: 'now-15m', rangeTo: 'now', query: '', diff --git a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx index 863855bbbb3b..dd855829edf6 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alert_search_bar/alert_search_bar.tsx @@ -11,8 +11,8 @@ import React, { useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { Filter, Query } from '@kbn/es-query'; import { getEsQueryConfig } from '@kbn/data-plugin/common'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../../../common/constants'; import { AlertsStatusFilter } from './components'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; import { ALERT_STATUS_QUERY, DEFAULT_QUERIES, DEFAULT_QUERY_STRING } from './constants'; import { ObservabilityAlertSearchBarProps } from './types'; import { buildEsQuery } from '../../utils/build_es_query'; @@ -161,7 +161,7 @@ export function ObservabilityAlertSearchBar({ <EuiFlexItem> <AlertsSearchBar appName={appName} - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} rangeFrom={rangeFrom} rangeTo={rangeTo} showFilterBar={showFilterBar} diff --git a/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_alerts_page_table_configuration.tsx b/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_alerts_page_table_configuration.tsx index 8282d90752d7..d64c8523ceb6 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_alerts_page_table_configuration.tsx +++ b/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_alerts_page_table_configuration.tsx @@ -15,11 +15,8 @@ import { import { DataViewsServicePublic } from '@kbn/data-views-plugin/public/types'; import { HttpSetup } from '@kbn/core-http-browser'; import { NotificationsStart } from '@kbn/core-notifications-browser'; -import { - casesFeatureId, - observabilityAlertFeatureIds, - observabilityFeatureId, -} from '../../../../common'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../../../../common/constants'; +import { casesFeatureId, observabilityFeatureId } from '../../../../common'; import { AlertActions } from '../../../pages/alerts/components/alert_actions'; import { useGetAlertFlyoutComponents } from '../../alerts_flyout/use_get_alert_flyout_components'; import type { ObservabilityRuleTypeRegistry } from '../../../rules/create_observability_rule_type_registry'; @@ -68,7 +65,7 @@ export const getAlertsPageTableConfiguration = ( ruleTypeIds: observabilityRuleTypeRegistry.list(), usePersistentControls: getPersistentControlsHook({ groupingId: id ?? ALERTS_PAGE_ALERTS_TABLE_CONFIG_ID, - featureIds: observabilityAlertFeatureIds, + ruleTypeIds: OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, services: { dataViews, http, diff --git a/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_persistent_controls.ts b/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_persistent_controls.ts index 2141e0fb68d6..6e0f697e831a 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_persistent_controls.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/alerts_table/alerts/get_persistent_controls.ts @@ -9,12 +9,11 @@ import { useMemo, useCallback } from 'react'; import { type AlertsGroupingProps, useAlertsGroupingState } from '@kbn/alerts-grouping'; import { useAlertsDataView } from '@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view'; import { useGetGroupSelectorStateless } from '@kbn/grouping/src/hooks/use_get_group_selector'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsByGroupingAgg } from '../types'; interface GetPersistentControlsParams { groupingId: string; - featureIds: AlertConsumers[]; + ruleTypeIds: string[]; maxGroupingLevels?: number; services: Pick< AlertsGroupingProps<AlertsByGroupingAgg>['services'], @@ -25,7 +24,7 @@ interface GetPersistentControlsParams { export const getPersistentControlsHook = ({ groupingId, - featureIds, + ruleTypeIds, maxGroupingLevels = 3, services: { dataViews, http, notifications }, }: GetPersistentControlsParams) => @@ -43,7 +42,7 @@ export const getPersistentControlsHook = ); const { dataView } = useAlertsDataView({ - featureIds, + ruleTypeIds, dataViewsService: dataViews, http, toasts: notifications.toasts, diff --git a/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts index a4825c11f85c..0aedbb572321 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.test.ts @@ -75,6 +75,32 @@ const useCases = [ sourceField: '', }, ], + [ + { + aggType: Aggregators.COUNT, + field: '', + filter: `container.name:container's name-1`, + name: '', + }, + { + operation: 'count', + operationWithField: `count(kql='container.name:container\\'s name-1')`, + sourceField: '', + }, + ], + [ + { + aggType: Aggregators.COUNT, + field: '', + filter: 'host.name: host-*', + name: '', + }, + { + operation: 'count', + operationWithField: `count(kql='host.name: host-*')`, + sourceField: '', + }, + ], [ { aggType: Aggregators.CARDINALITY, @@ -136,7 +162,7 @@ const useCases = [ }, { operation: 'counter_rate', - operationWithField: `counter_rate(max(system.network.in.bytes), kql='host.name : foo')`, + operationWithField: `counter_rate(max(system.network.in.bytes), kql='host.name : "foo"')`, sourceField: 'system.network.in.bytes', }, ], diff --git a/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts index 9eb52af738ea..30663d02cda7 100644 --- a/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts +++ b/x-pack/plugins/observability_solution/observability/public/components/rule_condition_chart/helpers.ts @@ -15,15 +15,15 @@ export interface LensOperation { } export const getLensOperationFromRuleMetric = (metric: GenericMetric): LensOperation => { - const { aggType, field, filter } = metric; + const { aggType, field, filter = '' } = metric; let operation: string = aggType; const operationArgs: string[] = []; - const aggFilter = JSON.stringify(filter || '').replace(/"|\\/g, ''); + const escapedFilter = filter.replace(/'/g, "\\'"); if (aggType === Aggregators.RATE) { return { operation: 'counter_rate', - operationWithField: `counter_rate(max(${field}), kql='${aggFilter}')`, + operationWithField: `counter_rate(max(${field}), kql='${escapedFilter}')`, sourceField: field || '', }; } @@ -45,8 +45,7 @@ export const getLensOperationFromRuleMetric = (metric: GenericMetric): LensOpera operationArgs.push('percentile=99'); } - if (aggFilter) operationArgs.push(`kql='${aggFilter}'`); - + if (escapedFilter) operationArgs.push(`kql='${escapedFilter}'`); return { operation, operationWithField: `${operation}(${operationArgs.join(', ')})`, diff --git a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts index 07bb33ebb5a9..16718648c972 100644 --- a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts +++ b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; import type { AddSolutionNavigationArg } from '@kbn/navigation-plugin/public'; -import { of } from 'rxjs'; +import { map, of } from 'rxjs'; import type { ObservabilityPublicPluginsStart } from './plugin'; const title = i18n.translate( @@ -18,7 +18,7 @@ const title = i18n.translate( ); const icon = 'logoObservability'; -export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { +function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) { const navTree: NavigationTreeDefinition = { body: [ { @@ -87,6 +87,13 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { link: 'inventory', spaceBefore: 'm', }, + ...(streamsAvailable + ? [ + { + link: 'streams' as const, + }, + ] + : []), { id: 'apm', title: i18n.translate('xpack.observability.obltNav.applications', { @@ -558,6 +565,8 @@ export const createDefinition = ( title, icon: 'logoObservability', homePage: 'observabilityOnboarding', - navigationTree$: of(createNavTree(pluginsStart)), + navigationTree$: (pluginsStart.streams?.status$ || of({ status: 'disabled' as const })).pipe( + map(({ status }) => createNavTree({ streamsAvailable: status === 'enabled' })) + ), dataTestSubj: 'observabilitySideNav', }); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx index dfcf01e4e4c1..614a84296386 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/alert_history.tsx @@ -6,7 +6,6 @@ */ import React from 'react'; -import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { EuiPanel, EuiFlexGroup, @@ -17,12 +16,10 @@ import { EuiLoadingSpinner, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ALERT_INSTANCE_ID, ALERT_RULE_UUID, type AlertConsumers } from '@kbn/rule-data-utils'; +import { ALERT_INSTANCE_ID, ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import { useAlertsHistory } from '@kbn/observability-alert-details'; import type { Rule } from '@kbn/triggers-actions-ui-plugin/public'; import { convertTo } from '../../../../common/utils/formatters'; -import { useFetchRuleTypes } from '../../../hooks/use_fetch_rule_types'; -import { useGetFilteredRuleTypes } from '../../../hooks/use_get_filtered_rule_types'; import { useKibana } from '../../../utils/kibana_react'; import { TopAlert } from '../../..'; import { getDefaultAlertSummaryTimeRange } from '../../../utils/alert_summary_widget'; @@ -43,19 +40,11 @@ export function AlertHistoryChart({ rule, alert }: Props) { notifications, triggersActionsUi: { getAlertSummaryWidget: AlertSummaryWidget }, } = useKibana().services; + const instanceId = alert.fields[ALERT_INSTANCE_ID]; - const filteredRuleTypes = useGetFilteredRuleTypes(); - const { ruleTypes } = useFetchRuleTypes({ - filterByRuleTypeIds: filteredRuleTypes, - }); - const ruleType = ruleTypes?.find((type) => type.id === rule?.ruleTypeId); - const featureIds = - rule?.consumer === ALERTING_FEATURE_ID && ruleType?.producer - ? [ruleType.producer as AlertConsumers] - : rule - ? [rule.consumer as AlertConsumers] - : []; const ruleId = alert.fields[ALERT_RULE_UUID]; + const ruleTypeIds = [rule.ruleTypeId]; + const consumers = [rule.consumer]; const { data: { avgTimeToRecoverUS, totalTriggeredAlerts }, @@ -63,7 +52,8 @@ export function AlertHistoryChart({ rule, alert }: Props) { isError, } = useAlertsHistory({ http, - featureIds, + ruleTypeIds, + consumers, ruleId: rule.id, dateRange, instanceId, @@ -162,7 +152,8 @@ export function AlertHistoryChart({ rule, alert }: Props) { </EuiFlexGroup> <EuiSpacer size="s" /> <AlertSummaryWidget - featureIds={featureIds} + ruleTypeIds={ruleTypeIds} + consumers={consumers} timeRange={getDefaultAlertSummaryTimeRange()} fullSize hideStats diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/related_alerts.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/related_alerts.tsx index 6ccebc34e472..5fba814fc334 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/related_alerts.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/related_alerts.tsx @@ -29,7 +29,10 @@ import { BoolQuery, Filter, type Query } from '@kbn/es-query'; import { AlertsGrouping } from '@kbn/alerts-grouping'; import { ObservabilityFields } from '../../../../common/utils/alerting/types'; -import { observabilityAlertFeatureIds } from '../../../../common/constants'; +import { + OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + observabilityAlertFeatureIds, +} from '../../../../common/constants'; import { getRelatedAlertKuery, getSharedFields, @@ -125,7 +128,8 @@ export function InternalRelatedAlerts({ alert }: Props) { <EuiFlexItem> {esQuery && ( <AlertsGrouping<AlertsByGroupingAgg> - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} defaultFilters={ALERT_STATUS_FILTER[alertSearchBarStateProps.status] ?? DEFAULT_FILTERS} from={alertSearchBarStateProps.rangeFrom} to={alertSearchBarStateProps.rangeTo} @@ -149,7 +153,8 @@ export function InternalRelatedAlerts({ alert }: Props) { return ( <AlertsStateTable id={ALERTS_TABLE_ID} - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} configurationId={RELATED_ALERTS_TABLE_CONFIG_ID} query={mergeBoolQueries(esQuery, groupQuery)} showAlertStatusWithFlapping diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx index 660705222555..64013c1762f1 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alerts/alerts.tsx @@ -37,8 +37,11 @@ import { } from '../../components/alert_search_bar/containers'; import { calculateTimeRangeBucketSize } from '../overview/helpers/calculate_bucket_size'; import { getAlertSummaryTimeRange } from '../../utils/alert_summary_widget'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; -import { ALERTS_URL_STORAGE_KEY } from '../../../common/constants'; +import { + ALERTS_URL_STORAGE_KEY, + OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + observabilityAlertFeatureIds, +} from '../../../common/constants'; import { ALERTS_PAGE_ALERTS_TABLE_CONFIG_ID } from '../../constants'; import { useGetAvailableRulesWithDescriptions } from '../../hooks/use_get_available_rules_with_descriptions'; import { HeaderMenu } from '../overview/components/header_menu/header_menu'; @@ -177,8 +180,8 @@ function InternalAlertsPage() { try { const response = await loadRuleAggregations({ http, - typesFilter: filteredRuleTypes, - filterConsumers: observabilityAlertFeatureIds, + ruleTypeIds: filteredRuleTypes, + consumers: observabilityAlertFeatureIds, }); const { ruleExecutionStatus, ruleMutedStatus, ruleEnabledStatus, ruleSnoozedStatus } = response; @@ -250,7 +253,8 @@ function InternalAlertsPage() { </EuiFlexItem> <EuiFlexItem> <AlertSummaryWidget - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} filter={esQuery} fullSize timeRange={alertSummaryTimeRange} @@ -260,7 +264,8 @@ function InternalAlertsPage() { <EuiFlexItem> {esQuery && ( <AlertsGrouping<AlertsByGroupingAgg> - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} defaultFilters={ ALERT_STATUS_FILTER[alertSearchBarStateProps.status] ?? DEFAULT_FILTERS } @@ -286,7 +291,8 @@ function InternalAlertsPage() { return ( <AlertsStateTable id={ALERTS_TABLE_ID} - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} configurationId={ALERTS_PAGE_ALERTS_TABLE_CONFIG_ID} query={mergeBoolQueries(esQuery, groupQuery)} showAlertStatusWithFlapping diff --git a/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx b/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx index c7b71431050c..ad6fccbb7df9 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/overview/overview.tsx @@ -11,7 +11,10 @@ import { i18n } from '@kbn/i18n'; import { useBreadcrumbs, useFetcher } from '@kbn/observability-shared-plugin/public'; import { AlertConsumers } from '@kbn/rule-data-utils'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; +import { + OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + observabilityAlertFeatureIds, +} from '../../../common/constants'; import { paths } from '../../../common/locators/paths'; import { LoadingObservability } from '../../components/loading_observability'; import { DEFAULT_DATE_FORMAT, DEFAULT_INTERVAL } from '../../constants'; @@ -235,7 +238,8 @@ export function OverviewPage() { hasError={false} > <AlertSummaryWidget - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} filter={esQuery} fullSize timeRange={alertSummaryTimeRange} @@ -243,7 +247,8 @@ export function OverviewPage() { <AlertsStateTable alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} configurationId={AlertConsumers.OBSERVABILITY} - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} hideLazyLoader id={ALERTS_TABLE_ID} initialPageSize={ALERTS_PER_PAGE} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/rule_details/components/rule_details_tabs.tsx b/x-pack/plugins/observability_solution/observability/public/pages/rule_details/components/rule_details_tabs.tsx index 095c5796946f..7a41d363c965 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/rule_details/components/rule_details_tabs.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/rule_details/components/rule_details_tabs.tsx @@ -15,9 +15,9 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import type { RuleTypeParams } from '@kbn/alerting-plugin/common'; -import type { AlertConsumers } from '@kbn/rule-data-utils'; import type { Rule } from '@kbn/triggers-actions-ui-plugin/public'; import type { Query, BoolQuery } from '@kbn/es-query'; +import { observabilityAlertFeatureIds } from '../../../../common'; import { useKibana } from '../../../utils/kibana_react'; import { usePluginContext } from '../../../hooks/use_plugin_context'; import { ObservabilityAlertSearchbarWithUrlSync } from '../../../components/alert_search_bar/alert_search_bar_with_url_sync'; @@ -38,7 +38,7 @@ interface Props { bool: BoolQuery; } | undefined; - featureIds: AlertConsumers[] | undefined; + ruleTypeIds?: string[]; rule: Rule<RuleTypeParams>; ruleId: string; ruleType: any; @@ -49,7 +49,7 @@ interface Props { export function RuleDetailsTabs({ activeTabId, esQuery, - featureIds, + ruleTypeIds, rule, ruleId, ruleType, @@ -90,12 +90,13 @@ export function RuleDetailsTabs({ <EuiFlexGroup style={{ minHeight: 450 }} direction={'column'}> <EuiFlexItem> - {esQuery && featureIds && ( + {esQuery && ruleTypeIds && ( <AlertsStateTable alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} configurationId={RULE_DETAILS_ALERTS_TABLE_CONFIG_ID} id={RULE_DETAILS_PAGE_ID} - featureIds={featureIds} + ruleTypeIds={ruleTypeIds} + consumers={observabilityAlertFeatureIds} query={esQuery} showAlertStatusWithFlapping cellContext={{ observabilityRuleTypeRegistry }} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx b/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx index 3b2e5d3118c4..11a3a736ecae 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/rule_details/rule_details.tsx @@ -9,9 +9,8 @@ import React, { useState, useEffect, useRef } from 'react'; import { useParams, useLocation } from 'react-router-dom'; import { EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ALERTING_FEATURE_ID, RuleExecutionStatusErrorReasons } from '@kbn/alerting-plugin/common'; +import { RuleExecutionStatusErrorReasons } from '@kbn/alerting-plugin/common'; import type { BoolQuery } from '@kbn/es-query'; -import type { AlertConsumers } from '@kbn/rule-data-utils'; import { useBreadcrumbs } from '@kbn/observability-shared-plugin/public'; import { useKibana } from '../../utils/kibana_react'; import { usePluginContext } from '../../hooks/use_plugin_context'; @@ -27,7 +26,11 @@ import { RuleDetailsTabs } from './components/rule_details_tabs'; import { getHealthColor } from './helpers/get_health_color'; import { isRuleEditable } from './helpers/is_rule_editable'; import { ruleDetailsLocatorID } from '../../../common'; -import { ALERT_STATUS_ALL } from '../../../common/constants'; +import { + ALERT_STATUS_ALL, + OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + observabilityAlertFeatureIds, +} from '../../../common/constants'; import { RULE_DETAILS_EXECUTION_TAB, RULE_DETAILS_ALERTS_TAB, @@ -180,16 +183,8 @@ export function RuleDetailsPage() { }; const ruleType = ruleTypes?.find((type) => type.id === rule?.ruleTypeId); - const isEditable = isRuleEditable({ capabilities, rule, ruleType, ruleTypeRegistry }); - const featureIds = - rule?.consumer === ALERTING_FEATURE_ID && ruleType?.producer - ? [ruleType.producer as AlertConsumers] - : rule - ? [rule.consumer as AlertConsumers] - : []; - const ruleStatusMessage = rule?.executionStatus.error?.reason === RuleExecutionStatusErrorReasons.License ? rulesStatusesTranslationsMapping.noLicense @@ -234,7 +229,8 @@ export function RuleDetailsPage() { <EuiFlexItem style={{ minWidth: 350 }}> <AlertSummaryWidget - featureIds={featureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} onClick={handleAlertSummaryWidgetClick} timeRange={alertSummaryWidgetTimeRange} filter={{ @@ -261,7 +257,7 @@ export function RuleDetailsPage() { <RuleDetailsTabs esQuery={esQuery} - featureIds={featureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} rule={rule} ruleId={ruleId} ruleType={ruleType} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/rules/rules_tab.tsx b/x-pack/plugins/observability_solution/observability/public/pages/rules/rules_tab.tsx index ae896b66d990..5fc4de8e0c45 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/rules/rules_tab.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/rules/rules_tab.tsx @@ -10,9 +10,10 @@ import { useHistory } from 'react-router-dom'; import { createKbnUrlStateStorage } from '@kbn/kibana-utils-plugin/public'; import { RuleStatus } from '@kbn/triggers-actions-ui-plugin/public'; import { AlertConsumers } from '@kbn/rule-data-utils'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../../../common/constants'; +import { observabilityAlertFeatureIds } from '../../../common'; import { useKibana } from '../../utils/kibana_react'; import { useGetFilteredRuleTypes } from '../../hooks/use_get_filtered_rule_types'; -import { observabilityAlertFeatureIds } from '../../../common/constants'; interface RulesTabProps { setRefresh: React.Dispatch<React.SetStateAction<Date>>; @@ -75,7 +76,8 @@ export function RulesTab({ setRefresh, stateRefresh }: RulesTabProps) { return ( <RuleList - filterConsumers={observabilityAlertFeatureIds} + ruleTypeIds={OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES} + consumers={observabilityAlertFeatureIds} filteredRuleTypes={filteredRuleTypes} lastRunOutcomeFilter={stateLastResponse} refresh={stateRefresh} diff --git a/x-pack/plugins/observability_solution/observability/public/plugin.ts b/x-pack/plugins/observability_solution/observability/public/plugin.ts index 5866a082556b..c37f3cc2f624 100644 --- a/x-pack/plugins/observability_solution/observability/public/plugin.ts +++ b/x-pack/plugins/observability_solution/observability/public/plugin.ts @@ -70,6 +70,7 @@ import type { import type { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; +import type { StreamsPluginStart, StreamsPluginSetup } from '@kbn/streams-plugin/public'; import { observabilityAppId, observabilityFeatureId } from '../common'; import { ALERTS_PATH, @@ -124,6 +125,7 @@ export interface ObservabilityPublicPluginsSetup { licensing: LicensingPluginSetup; serverless?: ServerlessPluginSetup; presentationUtil?: PresentationUtilPluginStart; + streams?: StreamsPluginSetup; } export interface ObservabilityPublicPluginsStart { actionTypeRegistry: ActionTypeRegistryContract; @@ -162,6 +164,7 @@ export interface ObservabilityPublicPluginsStart { dataViewFieldEditor: DataViewFieldEditorStart; toastNotifications: ToastsStart; investigate?: InvestigatePublicStart; + streams?: StreamsPluginStart; } export type ObservabilityPublicStart = ReturnType<Plugin['start']>; diff --git a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts index 984a614a367f..b8dff520ff11 100644 --- a/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts +++ b/x-pack/plugins/observability_solution/observability/server/lib/rules/custom_threshold/custom_threshold_executor.test.ts @@ -120,6 +120,7 @@ const mockOptions = { const date = STARTED_AT_MOCK_DATE.toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }; const setEvaluationResults = (response: Array<Record<string, Evaluation>>) => { diff --git a/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts b/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts index c214939bdec8..300dcda5e4f0 100644 --- a/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts +++ b/x-pack/plugins/observability_solution/observability/server/lib/rules/register_rule_types.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { IBasePath, Logger } from '@kbn/core/server'; import { CustomThresholdLocators } from './custom_threshold/custom_threshold_executor'; import { ObservabilityConfig } from '../..'; import { thresholdRuleType } from './custom_threshold/register_custom_threshold_rule_type'; export function registerRuleTypes( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, basePath: IBasePath, config: ObservabilityConfig, logger: Logger, diff --git a/x-pack/plugins/observability_solution/observability/server/plugin.ts b/x-pack/plugins/observability_solution/observability/server/plugin.ts index b98fe316c712..53c91feb3b84 100644 --- a/x-pack/plugins/observability_solution/observability/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability/server/plugin.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { PluginSetupContract, PluginStartContract } from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { createUICapabilities as createCasesUICapabilities, getApiTags as getCasesApiTags, @@ -23,21 +23,12 @@ import { LogsExplorerLocatorParams, LOGS_EXPLORER_LOCATOR_ID } from '@kbn/deepli import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server'; import { i18n } from '@kbn/i18n'; -import { - ApmRuleType, - ES_QUERY_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - SLO_BURN_RATE_RULE_TYPE_ID, - SYNTHETICS_STATUS_RULE, - SYNTHETICS_TLS_RULE, -} from '@kbn/rule-data-utils'; import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/server'; import { SharePluginSetup } from '@kbn/share-plugin/server'; import { SpacesPluginSetup, SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { ObservabilityConfig } from '.'; import { observabilityFeatureId } from '../common'; @@ -57,13 +48,14 @@ import { registerRoutes } from './routes/register_routes'; import { threshold } from './saved_objects/threshold'; import { AlertDetailsContextualInsightsService } from './services'; import { uiSettings } from './ui_settings'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '../common/constants'; import { getCasesFeature } from './features/cases_v1'; import { getCasesFeatureV2 } from './features/cases_v2'; export type ObservabilityPluginSetup = ReturnType<ObservabilityPlugin['setup']>; interface PluginSetup { - alerting: PluginSetupContract; + alerting: AlertingServerSetup; features: FeaturesPluginSetup; guidedOnboarding?: GuidedOnboardingPluginSetup; ruleRegistry: RuleRegistryPluginSetupContract; @@ -74,21 +66,17 @@ interface PluginSetup { } interface PluginStart { - alerting: PluginStartContract; + alerting: AlertingServerStart; spaces?: SpacesPluginStart; dataViews: DataViewsServerPluginStart; } -const o11yRuleTypes = [ - SLO_BURN_RATE_RULE_TYPE_ID, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ES_QUERY_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, - ...Object.values(ApmRuleType), - SYNTHETICS_STATUS_RULE, - SYNTHETICS_TLS_RULE, -]; +const alertingFeatures = OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES.map( + (ruleTypeId) => ({ + ruleTypeId, + consumers: [observabilityFeatureId, ALERTING_FEATURE_ID], + }) +); export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> { private logger: Logger; @@ -141,7 +129,7 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> { scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security], app: [observabilityFeatureId], catalogue: [observabilityFeatureId], - alerting: o11yRuleTypes, + alerting: alertingFeatures, privileges: { all: { app: [observabilityFeatureId], @@ -153,10 +141,10 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> { }, alerting: { rule: { - all: o11yRuleTypes, + all: alertingFeatures, }, alert: { - all: o11yRuleTypes, + all: alertingFeatures, }, }, ui: ['read', 'write'], @@ -171,10 +159,10 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> { }, alerting: { rule: { - read: o11yRuleTypes, + read: alertingFeatures, }, alert: { - read: o11yRuleTypes, + read: alertingFeatures, }, }, ui: ['read'], @@ -195,7 +183,6 @@ export class ObservabilityPlugin implements Plugin<ObservabilityPluginSetup> { void core.getStartServices().then(([coreStart, pluginStart]) => { registerRoutes({ core, - config, dependencies: { pluginsSetup: { ...plugins, diff --git a/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts b/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts index f5c6c393371c..7b224dc92ade 100644 --- a/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts +++ b/x-pack/plugins/observability_solution/observability/server/routes/assistant/route.ts @@ -12,9 +12,13 @@ import { createObservabilityServerRoute } from '../create_observability_server_r const getObservabilityAlertDetailsContextRoute = createObservabilityServerRoute({ endpoint: 'GET /internal/observability/assistant/alert_details_contextual_insights', options: { - tags: [], access: 'internal', }, + security: { + authz: { + requiredPrivileges: ['ai_assistant'], + }, + }, params: t.type({ query: alertDetailsContextRt, }), diff --git a/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts b/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts index 5599039a5ce6..e10ce506bc99 100644 --- a/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts +++ b/x-pack/plugins/observability_solution/observability/server/routes/register_routes.ts @@ -4,29 +4,16 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { errors } from '@elastic/elasticsearch'; -import Boom from '@hapi/boom'; import { RulesClientApi } from '@kbn/alerting-plugin/server/types'; -import { CoreSetup, KibanaRequest, Logger, RouteRegistrar } from '@kbn/core/server'; +import { CoreSetup, KibanaRequest, Logger } from '@kbn/core/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { RuleDataPluginService } from '@kbn/rule-registry-plugin/server'; -import { - IoTsParamsObject, - decodeRequestParams, - parseEndpoint, - passThroughValidationObject, - stripNullishRequestParameters, -} from '@kbn/server-route-repository'; +import { registerRoutes as registerServerRoutes } from '@kbn/server-route-repository'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; -import axios from 'axios'; -import * as t from 'io-ts'; -import { ObservabilityConfig } from '..'; import { AlertDetailsContextualInsightsService } from '../services'; -import { ObservabilityRequestHandlerContext } from '../types'; import { AbstractObservabilityServerRouteRepository } from './types'; interface RegisterRoutes { - config: ObservabilityConfig; core: CoreSetup; repository: AbstractObservabilityServerRouteRepository; logger: Logger; @@ -43,84 +30,14 @@ export interface RegisterRoutesDependencies { assistant: { alertDetailsContextualInsightsService: AlertDetailsContextualInsightsService; }; - getRulesClientWithRequest: (request: KibanaRequest) => RulesClientApi; + getRulesClientWithRequest: (request: KibanaRequest) => Promise<RulesClientApi>; } -export function registerRoutes({ config, repository, core, logger, dependencies }: RegisterRoutes) { - const routes = Object.values(repository); - - const router = core.http.createRouter(); - - routes.forEach((route) => { - const { endpoint, options, handler, params } = route; - const { pathname, method } = parseEndpoint(endpoint); - - (router[method] as RouteRegistrar<typeof method, ObservabilityRequestHandlerContext>)( - { - path: pathname, - validate: passThroughValidationObject, - options, - }, - async (context, request, response) => { - try { - const decodedParams = decodeRequestParams( - stripNullishRequestParameters({ - params: request.params, - body: request.body, - query: request.query, - }), - (params as IoTsParamsObject) ?? t.strict({}) - ); - - const data = await handler({ - config, - context, - request, - logger, - params: decodedParams, - dependencies, - }); - - if (data === undefined) { - return response.noContent(); - } - - return response.ok({ body: data }); - } catch (error) { - if (axios.isAxiosError(error)) { - logger.error(error); - return response.customError({ - statusCode: error.response?.status || 500, - body: { - message: error.message, - }, - }); - } - - if (Boom.isBoom(error)) { - logger.error(error.output.payload.message); - return response.customError({ - statusCode: error.output.statusCode, - body: { message: error.output.payload.message }, - }); - } - - logger.error(error); - const opts = { - statusCode: 500, - body: { - message: error.message, - }, - }; - - if (error instanceof errors.RequestAbortedError) { - opts.statusCode = 499; - opts.body.message = 'Client closed request'; - } - - return response.customError(opts); - } - } - ); +export function registerRoutes({ repository, core, logger, dependencies }: RegisterRoutes) { + registerServerRoutes({ + core, + dependencies: { dependencies }, + logger, + repository, }); } diff --git a/x-pack/plugins/observability_solution/observability/server/routes/types.ts b/x-pack/plugins/observability_solution/observability/server/routes/types.ts index 394025313764..1b189e1233b4 100644 --- a/x-pack/plugins/observability_solution/observability/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/observability/server/routes/types.ts @@ -13,7 +13,6 @@ import { } from './get_global_observability_server_route_repository'; import { ObservabilityRequestHandlerContext } from '../types'; import { RegisterRoutesDependencies } from './register_routes'; -import { ObservabilityConfig } from '..'; export type { ObservabilityServerRouteRepository, APIEndpoint }; @@ -22,14 +21,11 @@ export interface ObservabilityRouteHandlerResources { dependencies: RegisterRoutesDependencies; logger: Logger; request: KibanaRequest; - config: ObservabilityConfig; } export interface ObservabilityRouteCreateOptions { - options: { - tags: string[]; - access?: 'public' | 'internal'; - }; + tags?: string[]; + access?: 'public' | 'internal'; } export type AbstractObservabilityServerRouteRepository = ServerRouteRepository; diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index 84a691f1033a..b3c18dc24b8e 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -111,6 +111,7 @@ "@kbn/core-ui-settings-server-mocks", "@kbn/es-types", "@kbn/logging-mocks", + "@kbn/streams-plugin", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts index 049c5a1e65fb..422ef625cdc6 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/index.ts @@ -10,10 +10,16 @@ import { AssistantScope } from '@kbn/ai-assistant-common'; import type { Message } from '../../common'; import { chatFeedbackEventSchema, ChatFeedback } from './schemas/chat_feedback'; import { insightFeedbackEventSchema, InsightFeedback } from './schemas/insight_feedback'; +import { insightResponseEventSchema, InsightResponse } from './schemas/insight_response'; import { userSentPromptEventSchema } from './schemas/user_sent_prompt'; import { ObservabilityAIAssistantTelemetryEventType } from './telemetry_event_type'; -const schemas = [chatFeedbackEventSchema, insightFeedbackEventSchema, userSentPromptEventSchema]; +const schemas = [ + chatFeedbackEventSchema, + insightFeedbackEventSchema, + userSentPromptEventSchema, + insightResponseEventSchema, +]; export type TelemetryEventTypeWithPayload = | { type: ObservabilityAIAssistantTelemetryEventType.ChatFeedback; payload: ChatFeedback } @@ -21,6 +27,10 @@ export type TelemetryEventTypeWithPayload = | { type: ObservabilityAIAssistantTelemetryEventType.UserSentPromptInChat; payload: Message & { scopes: AssistantScope[] }; + } + | { + type: ObservabilityAIAssistantTelemetryEventType.InsightResponse; + payload: InsightResponse; }; export const registerTelemetryEventTypes = (analytics: AnalyticsServiceSetup) => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_response.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_response.ts new file mode 100644 index 000000000000..e46eabf7316c --- /dev/null +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/schemas/insight_response.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EventTypeOpts } from '@kbn/core/public'; +import { ObservabilityAIAssistantTelemetryEventType } from '../telemetry_event_type'; + +export interface InsightResponse { + '@timestamp': string; +} + +export const insightResponseEventSchema: EventTypeOpts<InsightResponse> = { + eventType: ObservabilityAIAssistantTelemetryEventType.InsightResponse, + schema: { + '@timestamp': { + type: 'text', + _meta: { + description: 'The timestamp of the last response from the LLM.', + }, + }, + }, +}; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts index e15ae317a773..17f9c1d53acd 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/analytics/telemetry_event_type.ts @@ -9,4 +9,5 @@ export enum ObservabilityAIAssistantTelemetryEventType { ChatFeedback = 'observability_ai_assistant_chat_feedback', InsightFeedback = 'observability_ai_assistant_insight_feedback', UserSentPromptInChat = 'observability_ai_assistant_user_sent_prompt_in_chat', + InsightResponse = 'observability_ai_assistant_insight_response', } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/assistant_avatar.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/assistant_avatar.tsx index c9b0b21e70bc..1ad8cd4d476c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/assistant_avatar.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/assistant_avatar.tsx @@ -4,6 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ +import { useEuiTheme } from '@elastic/eui'; import React, { ReactNode } from 'react'; export interface AssistantAvatarProps { @@ -22,7 +23,9 @@ export const sizeMap = { }; export function AssistantAvatar({ size = 's', css, className }: AssistantAvatarProps) { + const { euiTheme } = useEuiTheme(); const sizePx = sizeMap[size]; + return ( <svg xmlns="http://www.w3.org/2000/svg" @@ -36,7 +39,7 @@ export function AssistantAvatar({ size = 's', css, className }: AssistantAvatarP <path fill="#F04E98" d="M36 28h24v36H36V28Z" /> <path fill="#00BFB3" d="M4 46c0-9.941 8.059-18 18-18h6v36h-6c-9.941 0-18-8.059-18-18Z" /> <path - fill="#343741" + fill={euiTheme.colors.textParagraph} d="M60 12c0 6.627-5.373 12-12 12s-12-5.373-12-12S41.373 0 48 0s12 5.373 12 12Z" /> <path fill="#FA744E" d="M6 23C6 10.85 15.85 1 28 1v22H6Z" /> diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/chat/chat_item_controls.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/chat/chat_item_controls.tsx index 2b8487fa45c9..d2aa7a637944 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/chat/chat_item_controls.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/chat/chat_item_controls.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiPanel, useEuiTheme } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiPanel } from '@elastic/eui'; import { css } from '@emotion/css'; import { Feedback, FeedbackButtons } from '../buttons/feedback_buttons'; import { StopGeneratingButton } from '../buttons/stop_generating_button'; @@ -34,8 +34,6 @@ export function ChatItemControls({ onRegenerateClick: () => void; onStopGeneratingClick: () => void; }) { - const { euiTheme } = useEuiTheme(); - const displayFeedback = !error && canGiveFeedback; const displayRegenerate = !loading && canRegenerate; @@ -64,7 +62,7 @@ export function ChatItemControls({ return controls ? ( <> - <EuiHorizontalRule margin="none" color={euiTheme.colors.lightestShade} /> + <EuiHorizontalRule margin="none" /> <EuiPanel hasShadow={false} paddingSize="s" className={containerClassName}> {controls} </EuiPanel> diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx index e5168470be8f..680a92f559f0 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight.tsx @@ -81,6 +81,17 @@ function ChatContent({ next(initialMessagesRef.current); }, [next]); + useEffect(() => { + if (state !== ChatState.Loading && lastAssistantResponse) { + chatService.sendAnalyticsEvent({ + type: ObservabilityAIAssistantTelemetryEventType.InsightResponse, + payload: { + '@timestamp': lastAssistantResponse['@timestamp'], + }, + }); + } + }, [state, lastAssistantResponse, chatService]); + return ( <> <MessagePanel diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight_base.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight_base.tsx index 97f2e0a71a0c..ed7f13b93650 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight_base.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/components/insight/insight_base.tsx @@ -82,7 +82,7 @@ export function InsightBase({ position="right" /> </EuiFlexGroup> - <EuiText size="s" css={{ color: euiTheme.colors.subduedText }}> + <EuiText size="s" css={{ color: euiTheme.colors.textSubdued }}> <span>{description}</span> </EuiText> </EuiFlexItem> diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/public/hooks/use_chat.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/public/hooks/use_chat.test.ts index e21eda9e09c6..64fcdda7612a 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/public/hooks/use_chat.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/public/hooks/use_chat.test.ts @@ -5,7 +5,7 @@ * 2.0. */ import type { DeeplyMockedKeys } from '@kbn/utility-types-jest'; -import { act, renderHook, type RenderHookResult } from '@testing-library/react-hooks'; +import { renderHook, act, type RenderHookResult } from '@testing-library/react'; import { BehaviorSubject, Subject } from 'rxjs'; import { MessageRole, @@ -57,7 +57,7 @@ jest.spyOn(useKibanaModule, 'useKibana').mockReturnValue({ }, } as any); -let hookResult: RenderHookResult<UseChatProps, UseChatResult>; +let hookResult: RenderHookResult<UseChatResult, UseChatProps>; describe('useChat', () => { beforeEach(() => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts index 80ddf3cbc0a0..1bf892c0d40e 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/functions/context.ts @@ -34,7 +34,7 @@ export function registerContextFunction({ visibility: FunctionVisibility.Internal, }, async ({ messages, screenContexts, chat }, signal) => { - const { analytics } = (await resources.context.core).coreStart; + const { analytics } = await resources.plugins.core.start(); async function getContext() { const screenDescription = compact( diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts index f693fa53c06c..7949276ac6ab 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/plugin.ts @@ -111,7 +111,18 @@ export class ObservabilityAIAssistantPlugin ]; }), }; - }) as ObservabilityAIAssistantRouteHandlerResources['plugins']; + }) as Pick< + ObservabilityAIAssistantRouteHandlerResources['plugins'], + keyof ObservabilityAIAssistantPluginStartDependencies + >; + + const withCore = { + ...routeHandlerPlugins, + core: { + setup: core, + start: () => core.getStartServices().then(([coreStart]) => coreStart), + }, + }; const service = (this.service = new ObservabilityAIAssistantService({ logger: this.logger.get('service'), @@ -133,7 +144,7 @@ export class ObservabilityAIAssistantPlugin core, logger: this.logger, dependencies: { - plugins: routeHandlerPlugins, + plugins: withCore, service: this.service, }, }); diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/chat/route.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/chat/route.ts index a6fe57cb58ad..e80e6fa156b0 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/chat/route.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/chat/route.ts @@ -194,7 +194,7 @@ const chatRecallRoute = createObservabilityAIAssistantServerRoute({ const response$ = from( recallAndScore({ - analytics: (await resources.context.core).coreStart.analytics, + analytics: (await resources.plugins.core.start()).analytics, chat: (name, params) => client .chat(name, { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts index 50ce85e3578e..37e9248a0c62 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/knowledge_base/route.ts @@ -133,7 +133,7 @@ const saveKnowledgeBaseUserInstruction = createObservabilityAIAssistantServerRou params: t.type({ body: t.type({ id: t.string, - text: nonEmptyStringRt, + text: t.string, public: toBooleanRt, }), }), diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/register_routes.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/register_routes.ts index 1a6140968c92..27c7361e8a7f 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/register_routes.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/register_routes.ts @@ -6,7 +6,7 @@ */ import type { CoreSetup } from '@kbn/core/server'; import type { Logger } from '@kbn/logging'; -import { registerRoutes } from '@kbn/server-route-repository'; +import { DefaultRouteHandlerResources, registerRoutes } from '@kbn/server-route-repository'; import { getGlobalObservabilityAIAssistantServerRouteRepository } from './get_global_observability_ai_assistant_route_repository'; import type { ObservabilityAIAssistantRouteHandlerResources } from './types'; import { ObservabilityAIAssistantPluginStartDependencies } from '../types'; @@ -20,7 +20,7 @@ export function registerServerRoutes({ logger: Logger; dependencies: Omit< ObservabilityAIAssistantRouteHandlerResources, - 'request' | 'context' | 'logger' | 'params' + keyof DefaultRouteHandlerResources >; }) { registerRoutes({ diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts index b817328d22c6..645da146dfb8 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/routes/types.ts @@ -6,32 +6,36 @@ */ import type { + CoreSetup, CoreStart, CustomRequestHandlerContext, IScopedClusterClient, IUiSettingsClient, - KibanaRequest, SavedObjectsClientContract, } from '@kbn/core/server'; -import type { Logger } from '@kbn/logging'; import type { LicensingApiRequestHandlerContext } from '@kbn/licensing-plugin/server/types'; import type { RacApiRequestHandlerContext } from '@kbn/rule-registry-plugin/server'; import type { RulesClientApi } from '@kbn/alerting-plugin/server/types'; +import { DefaultRouteHandlerResources } from '@kbn/server-route-repository-utils'; import type { ObservabilityAIAssistantService } from '../service'; import type { ObservabilityAIAssistantPluginSetupDependencies, ObservabilityAIAssistantPluginStartDependencies, } from '../types'; +type ObservabilityAIAssistantRequestHandlerContextBase = CustomRequestHandlerContext<{ + licensing: Pick<LicensingApiRequestHandlerContext, 'license' | 'featureUsage'>; + // these two are here for compatibility with APM functions + rac: Pick<RacApiRequestHandlerContext, 'getAlertsClient'>; + alerting: { + getRulesClient: () => Promise<RulesClientApi>; + }; +}>; + +// this is the type used across methods, it's stripped down for compatibility +// with the context that's available when executing as an action export type ObservabilityAIAssistantRequestHandlerContext = Omit< - CustomRequestHandlerContext<{ - licensing: Pick<LicensingApiRequestHandlerContext, 'license' | 'featureUsage'>; - // these two are here for compatibility with APM functions - rac: Pick<RacApiRequestHandlerContext, 'getAlertsClient'>; - alerting: { - getRulesClient: () => RulesClientApi; - }; - }>, + ObservabilityAIAssistantRequestHandlerContextBase, 'core' | 'resolve' > & { core: Promise<{ @@ -45,32 +49,41 @@ export type ObservabilityAIAssistantRequestHandlerContext = Omit< savedObjects: { client: SavedObjectsClientContract; }; - coreStart: CoreStart; }>; }; -export interface ObservabilityAIAssistantRouteHandlerResources { - request: KibanaRequest; +interface PluginContractResolveCore { + core: { + setup: CoreSetup<ObservabilityAIAssistantPluginStartDependencies>; + start: () => Promise<CoreStart>; + }; +} + +type PluginContractResolveDependenciesStart = { + [key in keyof ObservabilityAIAssistantPluginStartDependencies]: { + start: () => Promise<Required<ObservabilityAIAssistantPluginStartDependencies>[key]>; + }; +}; + +type PluginContractResolveDependenciesSetup = { + [key in keyof ObservabilityAIAssistantPluginSetupDependencies]: { + setup: Required<ObservabilityAIAssistantPluginSetupDependencies>[key]; + }; +}; + +export interface ObservabilityAIAssistantRouteHandlerResources + extends Omit<DefaultRouteHandlerResources, 'context' | 'response'> { context: ObservabilityAIAssistantRequestHandlerContext; - logger: Logger; service: ObservabilityAIAssistantService; - plugins: { - [key in keyof ObservabilityAIAssistantPluginSetupDependencies]: { - setup: Required<ObservabilityAIAssistantPluginSetupDependencies>[key]; - }; - } & { - [key in keyof ObservabilityAIAssistantPluginStartDependencies]: { - start: () => Promise<Required<ObservabilityAIAssistantPluginStartDependencies>[key]>; - }; - }; + plugins: PluginContractResolveCore & + PluginContractResolveDependenciesSetup & + PluginContractResolveDependenciesStart; } export interface ObservabilityAIAssistantRouteCreateOptions { - options: { - timeout?: { - payload?: number; - idleSocket?: number; - }; - tags: Array<'access:ai_assistant'>; + timeout?: { + payload?: number; + idleSocket?: number; }; + tags: Array<'access:ai_assistant'>; } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts index a98cf6f810f2..fdde5ebb4997 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/service/knowledge_base_service/index.ts @@ -405,7 +405,7 @@ export class KnowledgeBaseService { document: { '@timestamp': new Date().toISOString(), ...doc, - semantic_text: doc.text, + ...(doc.text ? { semantic_text: doc.text } : {}), user, namespace, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts index a8ab57b8ee53..f44911c172ce 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/server/types.ts @@ -22,10 +22,7 @@ import type { LicensingPluginSetup, LicensingPluginStart } from '@kbn/licensing- import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/server'; import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/server'; import type { RuleRegistryPluginStartContract } from '@kbn/rule-registry-plugin/server'; -import type { - PluginSetupContract as AlertingPluginSetup, - PluginStartContract as AlertingPluginStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { ObservabilityAIAssistantService } from './service'; export interface ObservabilityAIAssistantServerSetup { @@ -51,7 +48,7 @@ export interface ObservabilityAIAssistantPluginSetupDependencies { licensing: LicensingPluginSetup; cloud?: CloudSetup; serverless?: ServerlessPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; } export interface ObservabilityAIAssistantPluginStartDependencies { @@ -64,5 +61,5 @@ export interface ObservabilityAIAssistantPluginStartDependencies { ruleRegistry: RuleRegistryPluginStartContract; cloud?: CloudStart; serverless?: ServerlessPluginStart; - alerting: AlertingPluginStart; + alerting: AlertingServerStart; } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json b/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json index d5acd7a365b5..709b3117d575 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability_ai_assistant/tsconfig.json @@ -47,6 +47,7 @@ "@kbn/ai-assistant-common", "@kbn/inference-common", "@kbn/core-lifecycle-server", + "@kbn/server-route-repository-utils", ], "exclude": ["target/**/*"] } diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx index a570d4ba0276..9a4cf790b85c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/functions/visualize_esql.tsx @@ -127,13 +127,13 @@ export function VisualizeESQL({ ( isLoading: boolean, adapters: InlineEditLensEmbeddableContext['lensEvent']['adapters'] | undefined, - lensEmbeddableOutput$?: InlineEditLensEmbeddableContext['lensEvent']['embeddableOutput$'] + dataLoading$?: InlineEditLensEmbeddableContext['lensEvent']['dataLoading$'] ) => { const adapterTables = adapters?.tables?.tables; if (adapterTables && !isLoading) { setLensLoadEvent({ adapters, - embeddableOutput$: lensEmbeddableOutput$, + dataLoading$, }); } }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts index ab1d00392fdb..ea4ed05e36b6 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/public/hooks/use_local_storage.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useLocalStorage } from './use_local_storage'; describe('useLocalStorage', () => { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts index 682f2e2a4b19..5408dbbf4ab4 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/functions/alerts.ts @@ -14,8 +14,10 @@ import { ParsedTechnicalFields } from '@kbn/rule-registry-plugin/common'; import { ALERT_STATUS, ALERT_STATUS_ACTIVE, + AlertConsumers, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { omit } from 'lodash'; +import { OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES } from '@kbn/observability-plugin/common/constants'; import { FunctionRegistrationParameters } from '.'; const defaultFields = [ @@ -61,15 +63,6 @@ const OMITTED_ALERT_FIELDS = [ 'kibana.version', ] as const; -const DEFAULT_FEATURE_IDS = [ - 'apm', - 'infrastructure', - 'logs', - 'uptime', - 'slo', - 'observability', -] as const; - export function registerAlertsFunction({ functions, resources, @@ -183,7 +176,16 @@ export function registerAlertsFunction({ const kqlQuery = !filter ? [] : [toElasticsearchQuery(fromKueryExpression(filter))]; const response = await alertsClient.find({ - featureIds: DEFAULT_FEATURE_IDS as unknown as string[], + ruleTypeIds: OBSERVABILITY_RULE_TYPE_IDS_WITH_SUPPORTED_STACK_RULE_TYPES, + consumers: [ + AlertConsumers.APM, + AlertConsumers.INFRASTRUCTURE, + AlertConsumers.LOGS, + AlertConsumers.UPTIME, + AlertConsumers.SLO, + AlertConsumers.OBSERVABILITY, + AlertConsumers.ALERTS, + ], query: { bool: { filter: [ @@ -194,17 +196,17 @@ export function registerAlertsFunction({ lte: end, }, }, - }, - ...kqlQuery, - ...(!includeRecovered - ? [ - { - term: { - [ALERT_STATUS]: ALERT_STATUS_ACTIVE, + ...kqlQuery, + ...(!includeRecovered + ? [ + { + term: { + [ALERT_STATUS]: ALERT_STATUS_ACTIVE, + }, }, - }, - ] - : []), + ] + : []), + }, ], }, }, diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/plugin.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/plugin.ts index 63e06818a2b7..97fdc01069b9 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/plugin.ts @@ -17,7 +17,6 @@ import { ObservabilityAIAssistantRequestHandlerContext, ObservabilityAIAssistantRouteHandlerResources, } from '@kbn/observability-ai-assistant-plugin/server/routes/types'; -import { ObservabilityAIAssistantPluginStartDependencies } from '@kbn/observability-ai-assistant-plugin/server/types'; import { mapValues } from 'lodash'; import { firstValueFrom } from 'rxjs'; import type { ObservabilityAIAssistantAppConfig } from './config'; @@ -59,13 +58,22 @@ export class ObservabilityAIAssistantAppPlugin setup: value, start: () => core.getStartServices().then((services) => { - const [, pluginsStartContracts] = services; + const [_, pluginsStartContracts] = services; + return pluginsStartContracts[ - key as keyof ObservabilityAIAssistantPluginStartDependencies + key as keyof ObservabilityAIAssistantAppPluginStartDependencies ]; }), }; - }) as ObservabilityAIAssistantRouteHandlerResources['plugins']; + }) as Omit<ObservabilityAIAssistantRouteHandlerResources['plugins'], 'core'>; + + const withCore = { + ...routeHandlerPlugins, + core: { + setup: core, + start: () => core.getStartServices().then(([coreStart]) => coreStart), + }, + }; const initResources = async ( request: KibanaRequest @@ -90,7 +98,6 @@ export class ObservabilityAIAssistantAppPlugin }; }), core: Promise.resolve({ - coreStart, elasticsearch: { client: coreStart.elasticsearch.client.asScoped(request), }, @@ -110,7 +117,7 @@ export class ObservabilityAIAssistantAppPlugin context, service: plugins.observabilityAIAssistant.service, logger: this.logger.get('connector'), - plugins: routeHandlerPlugins, + plugins: withCore, }; }; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts index de02e4cf841c..04fd10c3e506 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.test.ts @@ -94,12 +94,14 @@ describe('observabilityAIAssistant rule_connector', () => { getAdhocInstructions: () => [], }), }, - context: { - core: Promise.resolve({ - coreStart: { http: { basePath: { publicBaseUrl: 'http://kibana.com' } } }, - }), - }, + context: {}, plugins: { + core: { + start: () => + Promise.resolve({ + http: { basePath: { publicBaseUrl: 'http://kibana.com' } }, + }), + }, actions: { start: async () => { return { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts index 33f3bdd2c98f..1f5a097f8f7c 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/rule_connector/index.ts @@ -248,7 +248,7 @@ If available, include the link of the conversation at the end of your answer.` isPublic: true, connectorId: execOptions.params.connector, signal: new AbortController().signal, - kibanaPublicUrl: (await resources.context.core).coreStart.http.basePath.publicBaseUrl, + kibanaPublicUrl: (await resources.plugins.core.start()).http.basePath.publicBaseUrl, instructions: [backgroundInstruction], messages: [ { diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts index a1196be6a829..0a3fc6d9dc12 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_app/server/types.ts @@ -9,10 +9,7 @@ import type { PluginSetupContract as ActionsPluginSetup, PluginStartContract as ActionsPluginStart, } from '@kbn/actions-plugin/server'; -import type { - PluginSetupContract as AlertingPluginSetup, - PluginStartContract as AlertingPluginStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { DataViewsServerPluginSetup, DataViewsServerPluginStart, @@ -47,7 +44,7 @@ export interface ObservabilityAIAssistantAppServerSetup {} export interface ObservabilityAIAssistantAppPluginStartDependencies { observabilityAIAssistant: ObservabilityAIAssistantServerStart; ruleRegistry: RuleRegistryPluginStartContract; - alerting: AlertingPluginStart; + alerting: AlertingServerStart; licensing: LicensingPluginStart; actions: ActionsPluginStart; security: SecurityPluginStart; @@ -64,7 +61,7 @@ export interface ObservabilityAIAssistantAppPluginStartDependencies { export interface ObservabilityAIAssistantAppPluginSetupDependencies { observabilityAIAssistant: ObservabilityAIAssistantServerSetup; ruleRegistry: RuleRegistryPluginSetupContract; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; licensing: LicensingPluginSetup; actions: ActionsPluginSetup; security: SecurityPluginSetup; diff --git a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx index 1c05ca6d52b3..51801c44a683 100644 --- a/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx +++ b/x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/knowledge_base_edit_user_instruction_flyout.tsx @@ -31,7 +31,6 @@ export function KnowledgeBaseEditUserInstructionFlyout({ onClose }: { onClose: ( const { mutateAsync: createEntry, isLoading: isSaving } = useCreateKnowledgeBaseUserInstruction(); const [newEntryText, setNewEntryText] = useState(''); const [newEntryId, setNewEntryId] = useState<string>(); - const isSubmitDisabled = newEntryText.trim() === ''; useEffect(() => { const userInstruction = userInstructions?.find((entry) => !entry.public); @@ -118,7 +117,6 @@ export function KnowledgeBaseEditUserInstructionFlyout({ onClose }: { onClose: ( fill isLoading={isSaving} onClick={handleSubmit} - isDisabled={isSubmitDisabled} > {i18n.translate( 'xpack.observabilityAiAssistantManagement.knowledgeBaseNewManualEntryFlyout.saveButtonLabel', diff --git a/x-pack/plugins/observability_solution/observability_onboarding/public/application/footer/footer.tsx b/x-pack/plugins/observability_solution/observability_onboarding/public/application/footer/footer.tsx index dae5f70bf3db..8f8b0ec853dc 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/public/application/footer/footer.tsx +++ b/x-pack/plugins/observability_solution/observability_onboarding/public/application/footer/footer.tsx @@ -43,6 +43,7 @@ export const Footer: FunctionComponent = () => { { defaultMessage: 'Explore demo' } ), link: URL_DEMO_ENV, + testSubject: 'observabilityOnboardingFooterExploreDemoLink', }, { iconUrl: forumIconUrl, @@ -65,6 +66,7 @@ export const Footer: FunctionComponent = () => { { defaultMessage: 'Open Elastic Discuss forum' } ), link: URL_FORUM, + testSubject: 'observabilityOnboardingFooterDiscussForumLink', }, { iconUrl: docsIconUrl, @@ -87,6 +89,7 @@ export const Footer: FunctionComponent = () => { { defaultMessage: 'Learn more about all Elastic features' } ), link: docLinks.links.observability.guide, + testSubject: 'observabilityOnboardingFooterLearnMoreLink', }, { iconUrl: supportIconUrl, @@ -105,6 +108,7 @@ export const Footer: FunctionComponent = () => { { defaultMessage: 'Open Support Hub' } ), link: helpSupportUrl, + testSubject: 'observabilityOnboardingFooterOpenSupportHubLink', }, ]; @@ -127,7 +131,7 @@ export const Footer: FunctionComponent = () => { <EuiText size="xs"> <p> <EuiLink - data-test-subj="observabilityOnboardingFooterLearnMoreLink" + data-test-subj={section.testSubject} aria-label={section.linkARIALabel} href={section.link} target="_blank" diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/plugin.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/plugin.ts index ccb260a002cf..30aaaf258838 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/plugin.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/plugin.ts @@ -14,8 +14,8 @@ import type { } from '@kbn/core/server'; import { mapValues } from 'lodash'; import { i18n } from '@kbn/i18n'; +import { DefaultRouteHandlerResources, registerRoutes } from '@kbn/server-route-repository'; import { getObservabilityOnboardingServerRouteRepository } from './routes'; -import { registerRoutes } from './routes/register_routes'; import { ObservabilityOnboardingRouteHandlerResources } from './routes/types'; import { ObservabilityOnboardingPluginSetup, @@ -71,16 +71,28 @@ export class ObservabilityOnboardingPlugin }) as ObservabilityOnboardingRouteHandlerResources['plugins']; const config = this.initContext.config.get<ObservabilityOnboardingConfig>(); - registerRoutes({ - core, - logger: this.logger, - repository: getObservabilityOnboardingServerRouteRepository(), - plugins: resourcePlugins, + + const dependencies: Omit< + ObservabilityOnboardingRouteHandlerResources, + keyof DefaultRouteHandlerResources + > = { config, kibanaVersion: this.initContext.env.packageInfo.version, + plugins: resourcePlugins, services: { esLegacyConfigService: this.esLegacyConfigService, }, + core: { + setup: core, + start: () => core.getStartServices().then(([coreStart]) => coreStart), + }, + }; + + registerRoutes({ + core, + logger: this.logger, + repository: getObservabilityOnboardingServerRouteRepository(), + dependencies, }); plugins.customIntegrations.registerCustomIntegration({ diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts index 372eaf797237..738c9f1fefd5 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/flow/route.ts @@ -13,7 +13,8 @@ import { type PackageClient, } from '@kbn/fleet-plugin/server'; import { dump } from 'js-yaml'; -import { PackageDataStreamTypes } from '@kbn/fleet-plugin/common/types'; +import { PackageDataStreamTypes, Output } from '@kbn/fleet-plugin/common/types'; +import { transformOutputToFullPolicyOutput } from '@kbn/fleet-plugin/server/services/output_client'; import { getObservabilityOnboardingFlow, saveObservabilityOnboardingFlow } from '../../lib/state'; import type { SavedObservabilityOnboardingFlow } from '../../saved_objects/observability_onboarding_status'; import { ObservabilityOnboardingFlow } from '../../saved_objects/observability_onboarding_status'; @@ -21,7 +22,6 @@ import { createObservabilityOnboardingServerRoute } from '../create_observabilit import { getHasLogs } from './get_has_logs'; import { getKibanaUrl } from '../../lib/get_fallback_urls'; import { getAgentVersionInfo } from '../../lib/get_agent_version'; -import { getFallbackESUrl } from '../../lib/get_fallback_urls'; import { ElasticAgentStepPayload, InstalledIntegration, StepProgressPayloadRT } from '../types'; import { createShipperApiKey } from '../../lib/api_key/create_shipper_api_key'; import { createInstallApiKey } from '../../lib/api_key/create_install_api_key'; @@ -329,6 +329,13 @@ const integrationsInstallRoute = createObservabilityOnboardingServerRoute({ throw Boom.notFound(`Onboarding session '${params.path.onboardingId}' not found.`); } + const outputClient = await fleetStart.createOutputClient(request); + const defaultOutputId = await outputClient.getDefaultDataOutputId(); + if (!defaultOutputId) { + throw Boom.notFound('Default data output not found'); + } + const output = await outputClient.get(defaultOutputId); + const integrationsToInstall = parseIntegrationsTSV(params.body); if (!integrationsToInstall.length) { return response.badRequest({ @@ -381,15 +388,11 @@ const integrationsInstallRoute = createObservabilityOnboardingServerRoute({ }, }); - const elasticsearchUrl = plugins.cloud?.setup?.elasticsearchUrl - ? [plugins.cloud?.setup?.elasticsearchUrl] - : await getFallbackESUrl(services.esLegacyConfigService); - return response.ok({ headers: { 'content-type': 'application/x-tar', }, - body: generateAgentConfigTar({ elasticsearchUrl, installedIntegrations }), + body: generateAgentConfigTar(output, installedIntegrations), }); }, }); @@ -565,14 +568,9 @@ function parseRegistryIntegrationMetadata( } } -const generateAgentConfigTar = ({ - elasticsearchUrl, - installedIntegrations, -}: { - elasticsearchUrl: string[]; - installedIntegrations: InstalledIntegration[]; -}) => { +function generateAgentConfigTar(output: Output, installedIntegrations: InstalledIntegration[]) { const now = new Date(); + return makeTar([ { type: 'File', @@ -581,11 +579,7 @@ const generateAgentConfigTar = ({ mtime: now, data: dump({ outputs: { - default: { - type: 'elasticsearch', - hosts: elasticsearchUrl, - api_key: '${API_KEY}', // Placeholder to be replaced by bash script with the actual API key - }, + default: transformOutputToFullPolicyOutput(output, undefined, true), }, }), }, @@ -603,7 +597,7 @@ const generateAgentConfigTar = ({ data: integration.config, })), ]); -}; +} export const flowRouteRepository = { ...createFlowRoute, diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/register_routes.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/register_routes.ts deleted file mode 100644 index 8fe51623510e..000000000000 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/register_routes.ts +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { errors } from '@elastic/elasticsearch'; -import Boom from '@hapi/boom'; -import type { IKibanaResponse } from '@kbn/core/server'; -import { CoreSetup, Logger, RouteRegistrar } from '@kbn/core/server'; -import { - IoTsParamsObject, - ServerRouteRepository, - decodeRequestParams, - stripNullishRequestParameters, - parseEndpoint, - passThroughValidationObject, -} from '@kbn/server-route-repository'; -import * as t from 'io-ts'; -import { ObservabilityOnboardingConfig } from '..'; -import { EsLegacyConfigService } from '../services/es_legacy_config_service'; -import { ObservabilityOnboardingRequestHandlerContext } from '../types'; -import { ObservabilityOnboardingRouteHandlerResources } from './types'; - -interface RegisterRoutes { - core: CoreSetup; - repository: ServerRouteRepository; - logger: Logger; - plugins: ObservabilityOnboardingRouteHandlerResources['plugins']; - config: ObservabilityOnboardingConfig; - kibanaVersion: string; - services: { - esLegacyConfigService: EsLegacyConfigService; - }; -} - -export function registerRoutes({ - repository, - core, - logger, - plugins, - config, - kibanaVersion, - services, -}: RegisterRoutes) { - const routes = Object.values(repository); - - const router = core.http.createRouter(); - - routes.forEach((route) => { - const { endpoint, options, handler, params } = route; - const { pathname, method } = parseEndpoint(endpoint); - - (router[method] as RouteRegistrar<typeof method, ObservabilityOnboardingRequestHandlerContext>)( - { - path: pathname, - validate: passThroughValidationObject, - options, - }, - async (context, request, response) => { - try { - const decodedParams = decodeRequestParams( - stripNullishRequestParameters({ - params: request.params, - body: request.body, - query: request.query, - }), - (params as IoTsParamsObject) ?? t.strict({}) - ); - - const data = (await handler({ - context, - request, - response, - logger, - params: decodedParams, - plugins, - core: { - setup: core, - start: async () => { - const [coreStart] = await core.getStartServices(); - return coreStart; - }, - }, - config, - kibanaVersion, - services, - })) as any; - - if (data === undefined) { - return response.noContent(); - } - - if (data instanceof response.noContent().constructor) { - return data as IKibanaResponse; - } - - return response.ok({ body: data }); - } catch (error) { - if (Boom.isBoom(error)) { - logger.error(error.output.payload.message); - return response.customError({ - statusCode: error.output.statusCode, - body: { message: error.output.payload.message }, - }); - } - - logger.error(error); - const opts = { - statusCode: 500, - body: { - message: error.message, - }, - }; - - if (error instanceof errors.RequestAbortedError) { - opts.statusCode = 499; - opts.body.message = 'Client closed request'; - } - - return response.customError(opts); - } - } - ); - }); -} diff --git a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts index 4b35272eaa33..689ab1473981 100644 --- a/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/observability_onboarding/server/routes/types.ts @@ -46,10 +46,8 @@ export interface ObservabilityOnboardingRouteHandlerResources { } export interface ObservabilityOnboardingRouteCreateOptions { - options: { - tags: string[]; - xsrfRequired?: boolean; - }; + tags: string[]; + xsrfRequired?: boolean; } export const IntegrationRT = t.intersection([ diff --git a/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts b/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts index 4d8be9efc59c..db3e91fbf493 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/entity/entity_types.ts @@ -6,11 +6,11 @@ */ const createKubernetesEntity = <T extends string>(base: T) => ({ - ecs: `kubernetes_${base}_ecs` as const, - semconv: `kubernetes_${base}_semconv` as const, + ecs: `k8s.${base}.ecs` as const, + semconv: `k8s.${base}.semconv` as const, }); -export const ENTITY_TYPES = { +export const BUILT_IN_ENTITY_TYPES = { HOST: 'host', CONTAINER: 'container', SERVICE: 'service', @@ -18,12 +18,13 @@ export const ENTITY_TYPES = { CLUSTER: createKubernetesEntity('cluster'), CONTAINER: createKubernetesEntity('container'), CRONJOB: createKubernetesEntity('cron_job'), - DAEMONSET: createKubernetesEntity('daemon_set'), + DAEMONSET: createKubernetesEntity('daemonset'), DEPLOYMENT: createKubernetesEntity('deployment'), JOB: createKubernetesEntity('job'), NAMESPACE: createKubernetesEntity('namespace'), NODE: createKubernetesEntity('node'), POD: createKubernetesEntity('pod'), - STATEFULSET: createKubernetesEntity('stateful_set'), + SERVICE: createKubernetesEntity('service'), + STATEFULSET: createKubernetesEntity('statefulset'), }, } as const; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts b/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts index adc07a2931b6..92ae5701f800 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/entity/index.ts @@ -5,5 +5,5 @@ * 2.0. */ -export { ENTITY_TYPES } from './entity_types'; +export { BUILT_IN_ENTITY_TYPES } from './entity_types'; export { EntityDataStreamType } from './entity_data_stream_types'; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/index.ts b/x-pack/plugins/observability_solution/observability_shared/common/index.ts index f483bcc5dc26..a8e26366ab4b 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/index.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/index.ts @@ -219,4 +219,4 @@ export { export { COMMON_OBSERVABILITY_GROUPING } from './embeddable_grouping'; -export { ENTITY_TYPES, EntityDataStreamType } from './entity'; +export { BUILT_IN_ENTITY_TYPES, EntityDataStreamType } from './entity'; diff --git a/x-pack/plugins/observability_solution/observability_shared/common/locators/entity_inventory/entity_inventory_locator.ts b/x-pack/plugins/observability_solution/observability_shared/common/locators/entity_inventory/entity_inventory_locator.ts index deb820b0d5e0..29045de48e14 100644 --- a/x-pack/plugins/observability_solution/observability_shared/common/locators/entity_inventory/entity_inventory_locator.ts +++ b/x-pack/plugins/observability_solution/observability_shared/common/locators/entity_inventory/entity_inventory_locator.ts @@ -16,8 +16,8 @@ export class EntitiesInventoryLocatorDefinition implements LocatorDefinition<Ser public readonly getLocation = async () => { return { - app: 'observability', - path: `/inventory`, + app: 'inventory', + path: `/`, state: {}, }; }; diff --git a/x-pack/plugins/observability_solution/observability_shared/kibana.jsonc b/x-pack/plugins/observability_solution/observability_shared/kibana.jsonc index a5cde081c7c5..8e5a4c25af48 100644 --- a/x-pack/plugins/observability_solution/observability_shared/kibana.jsonc +++ b/x-pack/plugins/observability_solution/observability_shared/kibana.jsonc @@ -33,4 +33,4 @@ "common" ] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx b/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx index dcf15d83ef93..f0274ab739b9 100644 --- a/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx +++ b/x-pack/plugins/observability_solution/profiling/public/components/contexts/license/license_context.tsx @@ -14,8 +14,8 @@ import { useProfilingDependencies } from '../profiling_dependencies/use_profilin export const LicenseContext = React.createContext<ILicense | undefined>(undefined); -export function LicenseProvider({ children }: { children: React.ReactChild }) { - const { license$ } = useProfilingDependencies().setup.licensing; +export function LicenseProvider({ children }: { children: React.ReactNode }) { + const { license$ } = useProfilingDependencies().start.licensing; const license = useObservable(license$); // if license is not loaded yet, consider it valid const hasInvalidLicense = license?.isActive === false; diff --git a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts index 1c4017a468ea..4bb49fcf8ac5 100644 --- a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts +++ b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.test.ts @@ -40,9 +40,9 @@ describe('useCalculateImpactEstimate', () => { it('calculates impact when countExclusive is lower than countInclusive', () => { const calculateImpactEstimates = useCalculateImpactEstimate(); const { selfCPU, totalCPU, totalSamples } = calculateImpactEstimates({ - countExclusive: 500, - countInclusive: 1000, - totalSamples: 10000, + countExclusive: 475, + countInclusive: 950, + totalSamples: 9500, totalSeconds: 15 * 60, // 15m }); @@ -68,9 +68,9 @@ describe('useCalculateImpactEstimate', () => { it('calculates impact', () => { const calculateImpactEstimates = useCalculateImpactEstimate(); const { selfCPU, totalCPU, totalSamples } = calculateImpactEstimates({ - countExclusive: 1000, - countInclusive: 1000, - totalSamples: 10000, + countExclusive: 950, + countInclusive: 950, + totalSamples: 9500, totalSeconds: 15 * 60, // 15m }); diff --git a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts index d148e0cc262d..a56f8c96d95d 100644 --- a/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts +++ b/x-pack/plugins/observability_solution/profiling/public/hooks/use_calculate_impact_estimates.ts @@ -28,7 +28,7 @@ export function useCalculateImpactEstimate() { totalSeconds: number; }) { const annualizedScaleUp = ANNUAL_SECONDS / totalSeconds; - const totalCoreSeconds = totalSamples / 20; + const totalCoreSeconds = totalSamples / 19; const percentage = samples / totalSamples; const coreSeconds = totalCoreSeconds * percentage; const annualizedCoreSeconds = coreSeconds * annualizedScaleUp; diff --git a/x-pack/plugins/observability_solution/profiling/public/types.ts b/x-pack/plugins/observability_solution/profiling/public/types.ts index 89a8f999010c..31532150cc1f 100644 --- a/x-pack/plugins/observability_solution/profiling/public/types.ts +++ b/x-pack/plugins/observability_solution/profiling/public/types.ts @@ -18,7 +18,7 @@ import { ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public/plugin'; import { ChartsPluginSetup, ChartsPluginStart } from '@kbn/charts-plugin/public'; -import { LicensingPluginSetup } from '@kbn/licensing-plugin/public'; +import type { LicensingPluginStart } from '@kbn/licensing-plugin/public'; import type { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import { ObservabilityAIAssistantPublicSetup, @@ -36,7 +36,6 @@ export interface ProfilingPluginPublicSetupDeps { dataViews: DataViewsPublicPluginSetup; data: DataPublicPluginSetup; charts: ChartsPluginSetup; - licensing: LicensingPluginSetup; share: SharePluginSetup; unifiedSearch: UnifiedSearchPluginSetup; } @@ -50,4 +49,5 @@ export interface ProfilingPluginPublicStartDeps { charts: ChartsPluginStart; share: SharePluginStart; unifiedSearch: UnifiedSearchPublicPluginStart; + licensing: LicensingPluginStart; } diff --git a/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts b/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts index 83bd21b1740b..8696c97dabd3 100644 --- a/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts +++ b/x-pack/plugins/observability_solution/profiling/server/lib/setup/get_has_setup_privileges.ts @@ -7,6 +7,7 @@ import { KibanaRequest } from '@kbn/core/server'; import { INTEGRATIONS_PLUGIN_ID, PLUGIN_ID as FLEET_PLUGIN_ID } from '@kbn/fleet-plugin/common'; +import { ApiOperation } from '@kbn/security-plugin-types-server'; import { ProfilingPluginStartDeps } from '../../types'; export async function getHasSetupPrivileges({ @@ -31,8 +32,11 @@ export async function getHasSetupPrivileges({ }, }, kibana: [ - securityPluginStart.authz.actions.api.get(`${FLEET_PLUGIN_ID}-all`), - securityPluginStart.authz.actions.api.get(`${INTEGRATIONS_PLUGIN_ID}-all`), + securityPluginStart.authz.actions.api.get(ApiOperation.Manage, `${FLEET_PLUGIN_ID}-all`), + securityPluginStart.authz.actions.api.get( + ApiOperation.Manage, + `${INTEGRATIONS_PLUGIN_ID}-all` + ), ], }); return hasAllRequested; diff --git a/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts b/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts index 4d5a7cca0ff7..7ad001831c0e 100644 --- a/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts +++ b/x-pack/plugins/observability_solution/profiling/server/routes/apm.ts @@ -52,7 +52,9 @@ export function registerTopNFunctionsAPMTransactionsRoute({ }); } const core = await context.core; - const { transaction: transactionIndices } = await apmDataAccess.getApmIndices(); + const { transaction: transactionIndices } = await apmDataAccess.getApmIndices( + core.savedObjects.client + ); const esClient = await getClient(context); diff --git a/x-pack/plugins/observability_solution/profiling/tsconfig.json b/x-pack/plugins/observability_solution/profiling/tsconfig.json index 937eee96641c..b89d34bb8442 100644 --- a/x-pack/plugins/observability_solution/profiling/tsconfig.json +++ b/x-pack/plugins/observability_solution/profiling/tsconfig.json @@ -54,7 +54,8 @@ "@kbn/management-settings-components-field-row", "@kbn/deeplinks-observability", "@kbn/react-kibana-context-render", - "@kbn/apm-data-access-plugin" + "@kbn/apm-data-access-plugin", + "@kbn/security-plugin-types-server" // add references to other TypeScript projects the plugin depends on // requiredPlugins from ./kibana.json diff --git a/x-pack/plugins/observability_solution/slo/README.md b/x-pack/plugins/observability_solution/slo/README.md index f577b2da35ec..df6872a5e9ec 100755 --- a/x-pack/plugins/observability_solution/slo/README.md +++ b/x-pack/plugins/observability_solution/slo/README.md @@ -20,3 +20,27 @@ See the [kibana contributing guide](https://github.com/elastic/kibana/blob/main/ <dt><code>yarn plugin-helpers dev --watch</code></dt> <dd>Execute this to build your plugin ui browser side so Kibana could pick up when started in development</dd> </dl> + + +## API Integration Tests +The SLO tests are located under `x-pack/test/api_integration/deployment_agnostic/apis/observability/slo` folder. In order to run the SLO tests of your interest, you can grep accordingly. Use the commands below to run all SLO tests (`grep=SLO`) on stateful or serverless. + +### Stateful + +``` +# start server +node scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts + +# run tests +node scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/stateful/oblt.stateful.config.ts --grep=SLO +``` + +### Serverless + +``` +# start server +node scripts/functional_tests_server --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts + +# run tests +node scripts/functional_test_runner --config x-pack/test/api_integration/deployment_agnostic/configs/serverless/oblt.serverless.config.ts --grep=SLO +``` diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json index b4d66229dc49..915fa9e108d4 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.json @@ -14,8 +14,12 @@ }, "servers": [ { - "url": "http://localhost:5601", - "description": "local" + "url": "https://{kibana_url}", + "variables": { + "kibana_url": { + "default": "localhost:5601" + } + } } ], "tags": [ @@ -102,12 +106,7 @@ } } } - }, - "servers": [ - { - "url": "https://localhost:5601" - } - ] + } }, "get": { "summary": "Get a paginated list of SLOs", @@ -738,12 +737,7 @@ } } } - }, - "servers": [ - { - "url": "https://localhost:5601" - } - ] + } } } }, @@ -1653,20 +1647,25 @@ "description": "Defines properties for SLO settings.", "type": "object", "properties": { + "syncField": { + "description": "The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field.", + "type": "string", + "example": "event.ingested" + }, "syncDelay": { - "description": "The synch delay to apply to the transform. Default 1m", + "description": "The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval.", "type": "string", "default": "1m", "example": "5m" }, "frequency": { - "description": "Configure how often the transform runs, default 1m", + "description": "The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute.", "type": "string", "default": "1m", "example": "5m" }, "preventInitialBackfill": { - "description": "Prevents the transform from backfilling data when it starts.", + "description": "Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window.", "type": "boolean", "default": false, "example": true diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml index fde29b3602be..96d63163b1d5 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/bundled.yaml @@ -9,8 +9,10 @@ info: name: Elastic License 2.0 url: https://www.elastic.co/licensing/elastic-license servers: - - url: http://localhost:5601 - description: local + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 tags: - name: slo description: SLO APIs enable you to define, manage and track service-level objectives @@ -63,8 +65,6 @@ paths: application/json: schema: $ref: '#/components/schemas/409_response' - servers: - - url: https://localhost:5601 get: summary: Get a paginated list of SLOs operationId: findSlosOp @@ -448,8 +448,6 @@ paths: application/json: schema: $ref: '#/components/schemas/403_response' - servers: - - url: https://localhost:5601 components: parameters: kbn_xsrf: @@ -1139,18 +1137,22 @@ components: description: Defines properties for SLO settings. type: object properties: + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + type: string + example: event.ingested syncDelay: - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. type: string default: 1m example: 5m frequency: - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. type: string default: 1m example: 5m preventInitialBackfill: - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. type: boolean default: false example: true diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml index a50ce0c28c13..e811e18734d5 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/components/schemas/settings.yaml @@ -2,18 +2,22 @@ title: Settings description: Defines properties for SLO settings. type: object properties: + syncField: + description: The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field. + type: string + example: 'event.ingested' syncDelay: - description: The synch delay to apply to the transform. Default 1m + description: The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval. type: string default: 1m example: 5m frequency: - description: Configure how often the transform runs, default 1m + description: The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute. type: string default: 1m example: 5m preventInitialBackfill: - description: Prevents the transform from backfilling data when it starts. + description: Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window. type: boolean default: false example: true diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml index a1f7a8739c07..413540ecb96c 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/entrypoint.yaml @@ -12,8 +12,10 @@ tags: - name: slo description: SLO APIs enable you to define, manage and track service-level objectives servers: - - url: "http://localhost:5601" - description: local + - url: https://{kibana_url} + variables: + kibana_url: + default: localhost:5601 paths: "/s/{spaceId}/api/observability/slos": $ref: "paths/s@{spaceid}@api@slos.yaml" @@ -31,17 +33,3 @@ paths: # $ref: "paths/s@{spaceid}@api@slos@_definitions.yaml" "/s/{spaceId}/api/observability/slos/_delete_instances": $ref: "paths/s@{spaceid}@api@slos@_delete_instances.yaml" -# Security is defined when files are joined in oas_docs -# components: -# securitySchemes: -# basicAuth: -# type: http -# scheme: basic -# apiKeyAuth: -# type: apiKey -# in: header -# name: Authorization -# description: 'e.g. Authorization: ApiKey base64AccessApiKey' -# security: -# - basicAuth: [] -# - apiKeyAuth: [] diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml index ed489df00d80..68de4d633a82 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos.yaml @@ -46,9 +46,6 @@ post: application/json: schema: $ref: '../components/schemas/409_response.yaml' - servers: - - url: https://localhost:5601 - get: summary: Get a paginated list of SLOs operationId: findSlosOp diff --git a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml index 3ae6388f09d5..f7d0e3a3c884 100644 --- a/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml +++ b/x-pack/plugins/observability_solution/slo/docs/openapi/slo/paths/s@{spaceid}@api@slos@_delete_instances.yaml @@ -37,5 +37,3 @@ post: application/json: schema: $ref: '../components/schemas/403_response.yaml' - servers: - - url: https://localhost:5601 diff --git a/x-pack/plugins/observability_solution/slo/kibana.jsonc b/x-pack/plugins/observability_solution/slo/kibana.jsonc index 79302b58f826..11eca10c6c8d 100644 --- a/x-pack/plugins/observability_solution/slo/kibana.jsonc +++ b/x-pack/plugins/observability_solution/slo/kibana.jsonc @@ -21,40 +21,41 @@ "charts", "dashboard", "data", - "dataViews", - "discoverShared", - "lens", "dataViewEditor", "dataViewFieldEditor", + "dataViews", + "discoverShared", + "embeddable", + "features", "fieldFormats", + "lens", + "licensing", "observability", "observabilityShared", + "presentationUtil", "ruleRegistry", + "share", "taskManager", "triggersActionsUi", - "share", - "unifiedSearch", "uiActions", - "embeddable", - "presentationUtil", - "features", - "licensing", - "usageCollection", + "unifiedSearch", + "usageCollection" ], "optionalPlugins": [ "cloud", - "serverless", "discover", "observabilityAIAssistant", + "serverless", "spaces", + "security" ], "requiredBundles": [ "controls", + "embeddable", + "ingestPipelines", "kibanaReact", "kibanaUtils", - "unifiedSearch", - "embeddable", - "ingestPipelines" + "unifiedSearch" ] } } \ No newline at end of file diff --git a/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts b/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts index ce50190eb7ad..0fccc4deb0f8 100644 --- a/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts +++ b/x-pack/plugins/observability_solution/slo/public/data/slo/slo.ts @@ -39,6 +39,7 @@ const baseSlo: Omit<SLOWithSummaryResponse, 'id'> = { good: 'http_status: 2xx', total: 'a query', timestampField: 'custom_timestamp', + dataViewId: 'some-data-view-id', }, }, timeWindow: { diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx index 968d1f80a082..9aea7b17f43f 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_summary.tsx @@ -9,7 +9,7 @@ import type { TimeRange } from '@kbn/es-query'; import { useTimeBuckets } from '@kbn/observability-plugin/public'; import { getAlertSummaryTimeRange } from '@kbn/observability-plugin/public'; import { calculateTimeRangeBucketSize } from '@kbn/observability-plugin/public'; -import { observabilityAlertFeatureIds } from '@kbn/observability-plugin/common'; +import { AlertConsumers, SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { useSloAlertsQuery } from './slo_alerts_table'; import { SloEmbeddableDeps } from '../types'; @@ -61,7 +61,8 @@ export function SloAlertsSummary({ return ( <AlertSummaryWidget - featureIds={observabilityAlertFeatureIds} + ruleTypeIds={SLO_RULE_TYPE_IDS} + consumers={[AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY]} filter={esQuery} timeRange={alertSummaryTimeRange} fullSize diff --git a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_table.tsx b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_table.tsx index 02e94973e4ff..8da688e38a75 100644 --- a/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_table.tsx +++ b/x-pack/plugins/observability_solution/slo/public/embeddable/slo/alerts/components/slo_alerts_table.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React, { useMemo } from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers, SLO_BURN_RATE_RULE_TYPE_ID } from '@kbn/rule-data-utils'; import type { TimeRange } from '@kbn/es-query'; import { ALL_VALUE } from '@kbn/slo-schema'; import { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; @@ -105,7 +105,8 @@ export function SloAlertsTable({ query={useSloAlertsQuery(slos, timeRange, showAllGroupByInstances)} alertsTableConfigurationRegistry={alertsTableConfigurationRegistry} configurationId={SLO_ALERTS_TABLE_CONFIG_ID} - featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} + ruleTypeIds={[SLO_BURN_RATE_RULE_TYPE_ID]} + consumers={[AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY]} hideLazyLoader id={ALERTS_TABLE_ID} initialPageSize={ALERTS_PER_PAGE} diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts index 8fa7d3ec88e9..8ca275ae78a1 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_active_alerts.ts @@ -8,7 +8,10 @@ import { useQuery } from '@tanstack/react-query'; import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import { + AlertConsumers, + SLO_RULE_TYPE_IDS, +} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { useKibana } from './use_kibana'; import { sloKeys } from './query_key_factory'; import { ActiveAlerts } from './active_alerts'; @@ -57,7 +60,8 @@ export function useFetchActiveAlerts({ try { const response = await http.post<FindApiResponse>(`${BASE_RAC_ALERTS_API_PATH}/find`, { body: JSON.stringify({ - feature_ids: [AlertConsumers.SLO, AlertConsumers.OBSERVABILITY], + rule_type_ids: SLO_RULE_TYPE_IDS, + consumers: [AlertConsumers.SLO, AlertConsumers.OBSERVABILITY, AlertConsumers.ALERTS], size: 0, query: { bool: { @@ -69,11 +73,6 @@ export function useFetchActiveAlerts({ }, }, }, - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, { term: { 'kibana.alert.status': 'active', diff --git a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts index ce1efab91072..65546a3f6c96 100644 --- a/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts +++ b/x-pack/plugins/observability_solution/slo/public/hooks/use_fetch_slos_with_burn_rate_rules.ts @@ -12,8 +12,9 @@ import { useQuery, } from '@tanstack/react-query'; import type { Rule } from '@kbn/triggers-actions-ui-plugin/public'; -import { BASE_ALERTING_API_PATH } from '@kbn/alerting-plugin/common'; +import { INTERNAL_ALERTING_API_FIND_RULES_PATH } from '@kbn/alerting-plugin/common'; import { HttpSetup } from '@kbn/core/public'; +import { SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { useKibana } from './use_kibana'; import { sloKeys } from './query_key_factory'; import { WindowSchema } from '../typings'; @@ -54,17 +55,15 @@ async function fetchRules({ http: HttpSetup; signal?: AbortSignal; }) { - const filter = 'alert.attributes.alertTypeId:slo.rules.burnRate'; - - const query = { + const body = { search, - filter, fields: ['id', 'params.windows', 'name'], per_page: 1000, + rule_type_ids: SLO_RULE_TYPE_IDS, }; - const response = await http.get<RuleApiResponse>(`${BASE_ALERTING_API_PATH}/rules/_find`, { - query, + const response = await http.post<RuleApiResponse>(INTERNAL_ALERTING_API_FIND_RULES_PATH, { + body: JSON.stringify({ ...body }), signal, }); diff --git a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts index 40fcae8c840e..55305a4a3719 100644 --- a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.test.ts @@ -11,16 +11,21 @@ import { SloEditLocatorDefinition } from './slo_edit'; describe('SloEditLocator', () => { const locator = new SloEditLocatorDefinition(); - it('should return correct url when empty params are provided', async () => { + it('returns the correct url when empty params are provided', async () => { const location = await locator.getLocation({}); expect(location.app).toEqual('slo'); expect(location.path).toEqual('/create?_a=()'); }); - it('should return correct url when slo is provided', async () => { - const location = await locator.getLocation(buildSlo({ id: 'foo' })); + it('returns the correct url when slo id is provided', async () => { + const location = await locator.getLocation({ id: 'existing-slo-id' }); + expect(location.path).toEqual('/edit/existing-slo-id'); + }); + + it('returns the correct url when partial slo input is provided', async () => { + const location = await locator.getLocation(buildSlo({ id: undefined })); expect(location.path).toEqual( - "/edit/foo?_a=(budgetingMethod:occurrences,createdAt:'2022-12-29T10:11:12.000Z',description:'some%20description%20useful',enabled:!t,groupBy:'*',groupings:(),id:foo,indicator:(params:(filter:'baz:%20foo%20and%20bar%20%3E%202',good:'http_status:%202xx',index:some-index,timestampField:custom_timestamp,total:'a%20query'),type:sli.kql.custom),instanceId:'*',meta:(),name:'super%20important%20level%20service',objective:(target:0.98),revision:1,settings:(frequency:'1m',preventInitialBackfill:!f,syncDelay:'1m'),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:'30d',type:rolling),updatedAt:'2022-12-29T10:11:12.000Z',version:2)" + "/create?_a=(budgetingMethod:occurrences,createdAt:'2022-12-29T10:11:12.000Z',description:'some%20description%20useful',enabled:!t,groupBy:'*',groupings:(),indicator:(params:(dataViewId:some-data-view-id,filter:'baz:%20foo%20and%20bar%20%3E%202',good:'http_status:%202xx',index:some-index,timestampField:custom_timestamp,total:'a%20query'),type:sli.kql.custom),instanceId:'*',meta:(),name:'super%20important%20level%20service',objective:(target:0.98),revision:1,settings:(frequency:'1m',preventInitialBackfill:!f,syncDelay:'1m'),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:'30d',type:rolling),updatedAt:'2022-12-29T10:11:12.000Z',version:2)" ); }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts index 120bc533e9ee..2233ea9c5718 100644 --- a/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts +++ b/x-pack/plugins/observability_solution/slo/public/locators/slo_edit.ts @@ -5,31 +5,34 @@ * 2.0. */ -import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import type { RecursivePartial } from '@elastic/charts'; -import type { SerializableRecord } from '@kbn/utility-types'; -import type { LocatorDefinition } from '@kbn/share-plugin/public'; +import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import { sloEditLocatorID } from '@kbn/observability-plugin/common'; -import type { CreateSLOForm } from '../pages/slo_edit/types'; +import type { LocatorDefinition } from '@kbn/share-plugin/public'; +import { CreateSLOInput } from '@kbn/slo-schema'; import { SLO_CREATE_PATH } from '../../common/locators/paths'; -export type SloEditParams = RecursivePartial<CreateSLOForm>; - -export interface SloEditLocatorParams extends SloEditParams, SerializableRecord {} +export type SloEditLocatorParams = RecursivePartial<CreateSLOInput>; export class SloEditLocatorDefinition implements LocatorDefinition<SloEditLocatorParams> { public readonly id = sloEditLocatorID; public readonly getLocation = async (slo: SloEditLocatorParams) => { + if (!!slo.id) { + return { + app: 'slo', + path: `/edit/${encodeURIComponent(slo.id)}`, + state: {}, + }; + } + return { app: 'slo', - path: setStateToKbnUrl<SloEditParams>( + path: setStateToKbnUrl<RecursivePartial<CreateSLOInput>>( '_a', - { - ...slo, - }, + slo, { useHash: false, storeInHashQuery: false }, - slo.id ? `/edit/${encodeURIComponent(String(slo.id))}` : `${SLO_CREATE_PATH}` + SLO_CREATE_PATH ), state: {}, }; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx index 34f3b0132dc8..9a2f798ab628 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/overview/overview.tsx @@ -8,15 +8,14 @@ import { EuiFlexGrid, EuiPanel, EuiText, useIsWithinBreakpoints } from '@elastic/eui'; import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; +import { TagsList } from '@kbn/observability-shared-plugin/public'; import { + SLOWithSummaryResponse, occurrencesBudgetingMethodSchema, querySchema, rollingTimeWindowTypeSchema, - SLOWithSummaryResponse, } from '@kbn/slo-schema'; import React from 'react'; -import { TagsList } from '@kbn/observability-shared-plugin/public'; -import { DisplayQuery } from './display_query'; import { useKibana } from '../../../../hooks/use_kibana'; import { BUDGETING_METHOD_OCCURRENCES, @@ -26,9 +25,9 @@ import { toIndicatorTypeLabel, } from '../../../../utils/slo/labels'; import { ApmIndicatorOverview } from './apm_indicator_overview'; -import { SyntheticsIndicatorOverview } from './synthetics_indicator_overview'; - +import { DisplayQuery } from './display_query'; import { OverviewItem } from './overview_item'; +import { SyntheticsIndicatorOverview } from './synthetics_indicator_overview'; export interface Props { slo: SLOWithSummaryResponse; @@ -170,6 +169,19 @@ export function Overview({ slo }: Props) { } /> )} + + <OverviewItem + title={i18n.translate('xpack.slo.sloDetails.overview.settings.syncDelay', { + defaultMessage: 'Sync delay', + })} + subtitle={slo.settings.syncDelay} + /> + <OverviewItem + title={i18n.translate('xpack.slo.sloDetails.overview.settings.frequency', { + defaultMessage: 'Frequency', + })} + subtitle={slo.settings.frequency} + /> </EuiFlexGrid> </EuiPanel> ); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx index 3aa94c00b644..7b31baf0d62b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_details/components/slo_detail_alerts.tsx @@ -6,7 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { Fragment } from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers, SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { ALL_VALUE, SLOWithSummaryResponse } from '@kbn/slo-schema'; import { SLO_ALERTS_TABLE_ID } from '@kbn/observability-shared-plugin/common'; @@ -32,7 +32,8 @@ export function SloDetailsAlerts({ slo }: Props) { configurationId={AlertConsumers.OBSERVABILITY} id={SLO_ALERTS_TABLE_ID} data-test-subj="alertTable" - featureIds={[AlertConsumers.SLO, AlertConsumers.OBSERVABILITY]} + ruleTypeIds={SLO_RULE_TYPE_IDS} + consumers={[AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY]} query={{ bool: { filter: [ diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/advanced_settings.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/advanced_settings.tsx new file mode 100644 index 000000000000..81a630990a25 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/advanced_settings.tsx @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiAccordion, + EuiCheckbox, + EuiFieldNumber, + EuiFlexGrid, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiIcon, + EuiIconTip, + EuiTitle, + useGeneratedHtmlId, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import { CreateSLOForm } from '../../../types'; +import { SyncFieldSelector } from './sync_field_selector'; + +export function AdvancedSettings() { + const { control, getFieldState } = useFormContext<CreateSLOForm>(); + const preventBackfillCheckbox = useGeneratedHtmlId({ prefix: 'preventBackfill' }); + const advancedSettingsAccordion = useGeneratedHtmlId({ prefix: 'advancedSettingsAccordion' }); + + return ( + <EuiAccordion + paddingSize="s" + id={advancedSettingsAccordion} + buttonContent={ + <EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}> + <EuiFlexItem grow={false}> + <EuiIcon type="controlsVertical" size="m" /> + </EuiFlexItem> + + <EuiFlexItem> + <EuiTitle size="xxs"> + <h3> + {i18n.translate('xpack.slo.sloEdit.settings.advancedSettingsLabel', { + defaultMessage: 'Advanced settings', + })} + </h3> + </EuiTitle> + </EuiFlexItem> + </EuiFlexGroup> + } + > + <EuiFlexGroup direction="column" gutterSize="m"> + <EuiFlexGrid columns={3} gutterSize="m"> + <EuiFlexItem> + <SyncFieldSelector /> + </EuiFlexItem> + + <EuiFlexItem> + <EuiFormRow + isInvalid={getFieldState('settings.syncDelay').invalid} + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.settings.syncDelay.label', { + defaultMessage: 'Sync delay (in minutes)', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.settings.syncDelay.tooltip', { + defaultMessage: + 'The time delay in minutes between the current time and the latest source data time. Increasing the value will delay any alerting. The default value is 1 minute. The minimum value is 1m and the maximum is 359m. It should always be greater then source index refresh interval.', + })} + position="top" + /> + </span> + } + > + <Controller + name="settings.syncDelay" + defaultValue={1} + control={control} + rules={{ required: true, min: 1, max: 359 }} + render={({ field: { ref, onChange, ...field }, fieldState }) => ( + <EuiFieldNumber + {...field} + data-test-subj="sloAdvancedSettingsSyncDelay" + isInvalid={fieldState.invalid} + required + value={field.value} + min={1} + max={359} + step={1} + onChange={(event) => onChange(event.target.value)} + /> + )} + /> + </EuiFormRow> + </EuiFlexItem> + + <EuiFlexItem> + <EuiFormRow + isInvalid={getFieldState('settings.frequency').invalid} + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.settings.frequency.label', { + defaultMessage: 'Frequency (in minutes)', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.settings.frequency.tooltip', { + defaultMessage: + 'The interval between checks for changes in the source data. The minimum value is 1m and the maximum is 59m. The default value is 1 minute.', + })} + position="top" + /> + </span> + } + > + <Controller + name="settings.frequency" + defaultValue={1} + control={control} + rules={{ required: true, min: 1, max: 59 }} + render={({ field: { ref, onChange, ...field }, fieldState }) => ( + <EuiFieldNumber + {...field} + data-test-subj="sloAdvancedSettingsFrequency" + isInvalid={fieldState.invalid} + required + value={field.value} + min={1} + max={59} + step={1} + onChange={(event) => onChange(event.target.value)} + /> + )} + /> + </EuiFormRow> + </EuiFlexItem> + </EuiFlexGrid> + + <EuiFormRow isInvalid={getFieldState('settings.preventInitialBackfill').invalid}> + <Controller + name="settings.preventInitialBackfill" + control={control} + render={({ field: { ref, onChange, ...field } }) => ( + <EuiCheckbox + id={preventBackfillCheckbox} + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.settings.preventInitialBackfill.label', { + defaultMessage: 'Prevent initial backfill of data', + })}{' '} + <EuiIconTip + content={i18n.translate( + 'xpack.slo.sloEdit.settings.preventInitialBackfill.tooltip', + { + defaultMessage: + 'Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window.', + } + )} + position="top" + /> + </span> + } + checked={Boolean(field.value)} + onChange={(event: any) => onChange(event.target.checked)} + /> + )} + /> + </EuiFormRow> + </EuiFlexGroup> + </EuiAccordion> + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/sync_field_selector.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/sync_field_selector.tsx new file mode 100644 index 000000000000..ddfb51bb2897 --- /dev/null +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/advanced_settings/sync_field_selector.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiComboBox, EuiComboBoxOptionOption, EuiFormRow, EuiIconTip } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { Controller, useFormContext } from 'react-hook-form'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { createOptionsFromFields } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; +import { OptionalText } from '../../common/optional_text'; + +const placeholder = i18n.translate('xpack.slo.sloEdit.settings.syncField.placeholder', { + defaultMessage: 'Select a timestamp field', +}); + +export function SyncFieldSelector() { + const { control, watch, getFieldState } = useFormContext<CreateSLOForm>(); + const [index, dataViewId] = watch(['indicator.params.index', 'indicator.params.dataViewId']); + const { dataView, loading: isIndexFieldsLoading } = useCreateDataView({ + indexPatternString: index, + dataViewId, + }); + const timestampFields = dataView?.fields?.filter((field) => field.type === 'date') ?? []; + + return ( + <EuiFormRow + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.settings.syncField.label', { + defaultMessage: 'Sync field', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.settings.syncField.tooltip', { + defaultMessage: + 'The date field that is used to identify new documents in the source. It is strongly recommended to use a field that contains the ingest timestamp. If you use a different field, you might need to set the delay such that it accounts for data transmission delays. When unspecified, we use the indicator timestamp field.', + })} + position="top" + /> + </span> + } + isInvalid={getFieldState('settings.syncField').invalid} + labelAppend={<OptionalText />} + > + <Controller + name={'settings.syncField'} + defaultValue={null} + control={control} + rules={{ required: false }} + render={({ field, fieldState }) => { + return ( + <EuiComboBox<string> + {...field} + placeholder={placeholder} + aria-label={placeholder} + isClearable + isDisabled={isIndexFieldsLoading} + isInvalid={fieldState.invalid} + isLoading={isIndexFieldsLoading} + onChange={(selected: EuiComboBoxOptionOption[]) => { + if (selected.length) { + return field.onChange(selected[0].value); + } + + field.onChange(null); + }} + singleSelection={{ asPlainText: true }} + options={createOptionsFromFields(timestampFields)} + selectedOptions={ + !!timestampFields && !!field.value + ? [{ value: field.value, label: field.value }] + : [] + } + /> + ); + }} + /> + </EuiFormRow> + ); +} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.stories.tsx index c3c506eb484e..d40d56941ccf 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { ApmAvailabilityIndicatorTypeForm as Component } from './apm_availability_indicator_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.tsx similarity index 88% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.tsx index 0dcddcdb232b..fd00e3d35953 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_availability/apm_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_availability/apm_availability_indicator_type_form.tsx @@ -12,14 +12,14 @@ import React from 'react'; import { useFormContext } from 'react-hook-form'; import { useApmDefaultValues } from '../apm_common/use_apm_default_values'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { GroupByField } from '../common/group_by_field'; -import { useFetchApmIndex } from '../../../../hooks/use_fetch_apm_indices'; -import { CreateSLOForm } from '../../types'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { GroupByField } from '../../common/group_by_field'; +import { useFetchApmIndex } from '../../../../../hooks/use_fetch_apm_indices'; +import { CreateSLOForm } from '../../../types'; import { FieldSelector } from '../apm_common/field_selector'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; -import { formatAllFilters } from '../../helpers/format_filters'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; +import { formatAllFilters } from '../../../helpers/format_filters'; import { getGroupByCardinalityFilters } from '../apm_common/get_group_by_cardinality_filters'; export function ApmAvailabilityIndicatorTypeForm() { @@ -56,8 +56,8 @@ export function ApmAvailabilityIndicatorTypeForm() { }); return ( - <EuiFlexGroup direction="column" gutterSize="l"> - <EuiFlexGroup direction="row" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> + <EuiFlexGroup direction="row" gutterSize="m"> <FieldSelector allowAllOption={false} label={i18n.translate('xpack.slo.sloEdit.apmAvailability.serviceName', { @@ -94,7 +94,7 @@ export function ApmAvailabilityIndicatorTypeForm() { /> </EuiFlexGroup> - <EuiFlexGroup direction="row" gutterSize="l"> + <EuiFlexGroup direction="row" gutterSize="m"> <FieldSelector label={i18n.translate('xpack.slo.sloEdit.apmAvailability.transactionType', { defaultMessage: 'Transaction type', @@ -125,7 +125,7 @@ export function ApmAvailabilityIndicatorTypeForm() { /> </EuiFlexGroup> - <EuiFlexGroup direction="row" gutterSize="l"> + <EuiFlexGroup direction="row" gutterSize="m"> <EuiFlexItem> <QueryBuilder dataTestSubj="apmLatencyFilterInput" diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/field_selector.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/field_selector.stories.tsx similarity index 87% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/field_selector.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/field_selector.stories.tsx index 47111ee1c565..f9756501bab9 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/field_selector.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/field_selector.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { FieldSelector as Component, Props } from './field_selector'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/field_selector.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/field_selector.tsx similarity index 97% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/field_selector.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/field_selector.tsx index 850bb1ea423c..0b1855185b53 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/field_selector.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/field_selector.tsx @@ -11,8 +11,8 @@ import { ALL_VALUE } from '@kbn/slo-schema'; import { debounce } from 'lodash'; import React, { ReactNode, useState } from 'react'; import { Controller, FieldPath, useFormContext } from 'react-hook-form'; -import { Suggestion, useFetchApmSuggestions } from '../../../../hooks/use_fetch_apm_suggestions'; -import { CreateSLOForm } from '../../types'; +import { Suggestion, useFetchApmSuggestions } from '../../../../../hooks/use_fetch_apm_suggestions'; +import { CreateSLOForm } from '../../../types'; interface Option { label: string; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/get_group_by_cardinality_filters.test.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/get_group_by_cardinality_filters.test.ts similarity index 100% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/get_group_by_cardinality_filters.test.ts rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/get_group_by_cardinality_filters.test.ts diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/get_group_by_cardinality_filters.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/get_group_by_cardinality_filters.ts similarity index 100% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/get_group_by_cardinality_filters.ts rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/get_group_by_cardinality_filters.ts diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/use_apm_default_values.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/use_apm_default_values.ts similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/use_apm_default_values.ts rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/use_apm_default_values.ts index d61578bed859..7a155c504b15 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_common/use_apm_default_values.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_common/use_apm_default_values.ts @@ -8,8 +8,8 @@ import { useFormContext } from 'react-hook-form'; import { ALL_VALUE, APMTransactionErrorRateIndicator } from '@kbn/slo-schema'; import { useEffect } from 'react'; -import { useFetchApmIndex } from '../../../../hooks/use_fetch_apm_indices'; -import { CreateSLOForm } from '../../types'; +import { useFetchApmIndex } from '../../../../../hooks/use_fetch_apm_indices'; +import { CreateSLOForm } from '../../../types'; export const useApmDefaultValues = () => { const { watch, setValue } = useFormContext<CreateSLOForm<APMTransactionErrorRateIndicator>>(); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.stories.tsx index 3ca02641f9bf..9b346c94dea9 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { ApmLatencyIndicatorTypeForm as Component } from './apm_latency_indicator_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.tsx index 03b47aafe415..0d7b86d0b88d 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/apm_latency/apm_latency_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/apm_latency/apm_latency_indicator_type_form.tsx @@ -12,14 +12,14 @@ import React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { useApmDefaultValues } from '../apm_common/use_apm_default_values'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; -import { GroupByField } from '../common/group_by_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { useFetchApmIndex } from '../../../../hooks/use_fetch_apm_indices'; -import { CreateSLOForm } from '../../types'; +import { GroupByField } from '../../common/group_by_field'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { useFetchApmIndex } from '../../../../../hooks/use_fetch_apm_indices'; +import { CreateSLOForm } from '../../../types'; import { FieldSelector } from '../apm_common/field_selector'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; -import { formatAllFilters } from '../../helpers/format_filters'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; +import { formatAllFilters } from '../../../helpers/format_filters'; import { getGroupByCardinalityFilters } from '../apm_common/get_group_by_cardinality_filters'; export function ApmLatencyIndicatorTypeForm() { @@ -58,8 +58,8 @@ export function ApmLatencyIndicatorTypeForm() { }); return ( - <EuiFlexGroup direction="column" gutterSize="l"> - <EuiFlexGroup direction="row" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> + <EuiFlexGroup direction="row" gutterSize="m"> <FieldSelector allowAllOption={false} label={i18n.translate('xpack.slo.sloEdit.apmLatency.serviceName', { @@ -96,7 +96,7 @@ export function ApmLatencyIndicatorTypeForm() { /> </EuiFlexGroup> - <EuiFlexGroup direction="row" gutterSize="l"> + <EuiFlexGroup direction="row" gutterSize="m"> <FieldSelector label={i18n.translate('xpack.slo.sloEdit.apmLatency.transactionType', { defaultMessage: 'Transaction type', diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_and_timestamp_field.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_and_timestamp_field.tsx similarity index 83% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_and_timestamp_field.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_and_timestamp_field.tsx index 7059810a5aae..c5503943925c 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_and_timestamp_field.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_and_timestamp_field.tsx @@ -9,17 +9,16 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { DataView } from '@kbn/data-views-plugin/public'; import React from 'react'; import { useFormContext } from 'react-hook-form'; -import { CreateSLOForm } from '../../types'; -import { TimestampFieldSelector } from '../common/timestamp_field_selector'; +import { CreateSLOForm } from '../../../types'; +import { TimestampFieldSelector } from '../../common/timestamp_field_selector'; import { IndexSelection } from './index_selection'; -export function IndexAndTimestampField({ - dataView, - isLoading, -}: { +interface Props { dataView?: DataView; isLoading: boolean; -}) { +} + +export function IndexAndTimestampField({ dataView, isLoading }: Props) { const { watch } = useFormContext<CreateSLOForm>(); const index = watch('indicator.params.index'); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.stories.tsx index 4b8dce62f43b..b1739a63881f 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { IndexSelection as Component } from './index_selection'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.tsx similarity index 63% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.tsx index 146d11be84ac..9d5489ddd283 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/index_selection.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/index_selection.tsx @@ -8,37 +8,47 @@ import { EuiFormRow } from '@elastic/eui'; import { DataView } from '@kbn/data-views-plugin/public'; import { i18n } from '@kbn/i18n'; +import { ALL_VALUE } from '@kbn/slo-schema'; +import { DataViewPicker } from '@kbn/unified-search-plugin/public'; import React, { useEffect } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { DataViewPicker } from '@kbn/unified-search-plugin/public'; -import { getDataViewPattern, useAdhocDataViews } from './use_adhoc_data_views'; -import { SLOPublicPluginsStart } from '../../../..'; -import { useKibana } from '../../../../hooks/use_kibana'; -import { CreateSLOForm } from '../../types'; +import { SLOPublicPluginsStart } from '../../../../..'; +import { useKibana } from '../../../../../hooks/use_kibana'; +import { CreateSLOForm } from '../../../types'; +import { getDataViewPatternOrId, useAdhocDataViews } from './use_adhoc_data_views'; const BTN_MAX_WIDTH = 515; export const DATA_VIEW_FIELD = 'indicator.params.dataViewId'; const INDEX_FIELD = 'indicator.params.index'; -const TIMESTAMP_FIELD = 'indicator.params.timestampField'; +const INDICATOR_TIMESTAMP_FIELD = 'indicator.params.timestampField'; +const GROUP_BY_FIELD = 'groupBy'; +const SETTINGS_SYNC_FIELD = 'settings.syncField'; export function IndexSelection({ selectedDataView }: { selectedDataView?: DataView }) { const { control, getFieldState, setValue, watch } = useFormContext<CreateSLOForm>(); - const { dataViews: dataViewsService, dataViewFieldEditor } = useKibana().services; - - const { dataViewEditor } = useKibana<SLOPublicPluginsStart>().services; + const { + dataViews: dataViewsService, + dataViewFieldEditor, + dataViewEditor, + } = useKibana<SLOPublicPluginsStart>().services; const currentIndexPattern = watch(INDEX_FIELD); const currentDataViewId = watch(DATA_VIEW_FIELD); - const { dataViewsList, isDataViewsLoading, adHocDataViews, setAdHocDataViews, refetch } = - useAdhocDataViews({ - currentIndexPattern, - }); + const { + dataViewsList, + isDataViewsLoading, + adHocDataViews, + setAdHocDataViews, + refetchDataViewsList, + } = useAdhocDataViews({ + currentIndexPattern, + }); useEffect(() => { - const indPatternId = getDataViewPattern({ - byPatten: currentIndexPattern, + const indPatternId = getDataViewPatternOrId({ + byPattern: currentIndexPattern, dataViewsList, adHocDataViews, }); @@ -54,13 +64,24 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi setValue, ]); + const updateDataViewDependantFields = (indexPattern?: string, timestampField?: string) => { + setValue(INDEX_FIELD, indexPattern ?? ''); + setValue(INDICATOR_TIMESTAMP_FIELD, timestampField ?? ''); + setValue(GROUP_BY_FIELD, ALL_VALUE); + setValue(SETTINGS_SYNC_FIELD, null); + }; + return ( - <EuiFormRow label={INDEX_LABEL} isInvalid={getFieldState(INDEX_FIELD).invalid} fullWidth> + <EuiFormRow + label={INDEX_LABEL} + isInvalid={getFieldState(INDEX_FIELD).invalid || getFieldState(DATA_VIEW_FIELD).invalid} + fullWidth + > <Controller defaultValue="" name={DATA_VIEW_FIELD} control={control} - rules={{ required: !Boolean(currentIndexPattern) }} + rules={{ required: true }} render={({ field, fieldState }) => ( <DataViewPicker adHocDataViews={adHocDataViews} @@ -72,15 +93,13 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi style: { width: '100%', maxWidth: BTN_MAX_WIDTH }, }} onChangeDataView={(newId: string) => { - setValue( - INDEX_FIELD, - getDataViewPattern({ byId: newId, adHocDataViews, dataViewsList })! - ); field.onChange(newId); + dataViewsService.get(newId).then((dataView) => { - if (dataView.timeFieldName) { - setValue(TIMESTAMP_FIELD, dataView.timeFieldName); - } + updateDataViewDependantFields( + getDataViewPatternOrId({ byId: newId, adHocDataViews, dataViewsList })!, + dataView.timeFieldName + ); }); }} onAddField={ @@ -97,8 +116,8 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi } currentDataViewId={ field.value ?? - getDataViewPattern({ - byPatten: currentIndexPattern, + getDataViewPatternOrId({ + byPattern: currentIndexPattern, dataViewsList, adHocDataViews, }) @@ -108,17 +127,13 @@ export function IndexSelection({ selectedDataView }: { selectedDataView?: DataVi allowAdHocDataView: true, onSave: (dataView: DataView) => { if (!dataView.isPersisted()) { - setAdHocDataViews([...adHocDataViews, dataView]); - field.onChange(dataView.id); - setValue(INDEX_FIELD, dataView.getIndexPattern()); + setAdHocDataViews((prev) => [...prev, dataView]); } else { - refetch(); - field.onChange(dataView.id); - setValue(INDEX_FIELD, dataView.getIndexPattern()); - } - if (dataView.timeFieldName) { - setValue(TIMESTAMP_FIELD, dataView.timeFieldName); + refetchDataViewsList(); } + + field.onChange(dataView.id); + updateDataViewDependantFields(dataView.getIndexPattern(), dataView.timeFieldName); }, }); }} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/use_adhoc_data_views.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/use_adhoc_data_views.ts similarity index 79% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/use_adhoc_data_views.ts rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/use_adhoc_data_views.ts index 67792b056408..986b681c9bca 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_common/use_adhoc_data_views.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_common/use_adhoc_data_views.ts @@ -8,16 +8,16 @@ import { useEffect, useState } from 'react'; import { DataView, DataViewListItem } from '@kbn/data-views-plugin/common'; import { useFetchDataViews } from '@kbn/observability-plugin/public'; -import { useKibana } from '../../../../hooks/use_kibana'; +import { useKibana } from '../../../../../hooks/use_kibana'; -export const getDataViewPattern = ({ +export const getDataViewPatternOrId = ({ byId, - byPatten, + byPattern, dataViewsList, adHocDataViews, }: { byId?: string; - byPatten?: string; + byPattern?: string; dataViewsList: DataViewListItem[]; adHocDataViews: DataView[]; }) => { @@ -28,20 +28,24 @@ export const getDataViewPattern = ({ if (byId) { return allDataViews.find((dv) => dv.id === byId)?.title; } - if (byPatten) { - return allDataViews.find((dv) => dv.title === byPatten)?.id; + if (byPattern) { + return allDataViews.find((dv) => dv.title === byPattern)?.id; } }; export const useAdhocDataViews = ({ currentIndexPattern }: { currentIndexPattern: string }) => { - const { isLoading: isDataViewsLoading, data: dataViewsList = [], refetch } = useFetchDataViews(); + const { + isLoading: isDataViewsLoading, + data: dataViewsList = [], + refetch: refetchDataViewsList, + } = useFetchDataViews(); const { dataViews: dataViewsService } = useKibana().services; const [adHocDataViews, setAdHocDataViews] = useState<DataView[]>([]); useEffect(() => { if (!isDataViewsLoading) { - const missingDataView = getDataViewPattern({ - byPatten: currentIndexPattern, + const missingDataView = getDataViewPatternOrId({ + byPattern: currentIndexPattern, dataViewsList, adHocDataViews, }); @@ -70,6 +74,6 @@ export const useAdhocDataViews = ({ currentIndexPattern }: { currentIndexPattern setAdHocDataViews, dataViewsList, isDataViewsLoading, - refetch, + refetchDataViewsList, }; }; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.stories.tsx similarity index 84% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.stories.tsx index 5eb0b6807078..1ecf3f57c149 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { CustomKqlIndicatorTypeForm as Component } from './custom_kql_indicator_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.tsx index 92ba2cac50e7..ccebca1fbb36 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_kql/custom_kql_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_kql/custom_kql_indicator_type_form.tsx @@ -9,12 +9,12 @@ import { EuiFlexGroup, EuiFlexItem, EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { useFormContext } from 'react-hook-form'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { GroupByField } from '../../common/group_by_field'; +import { QueryBuilder } from '../../common/query_builder'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { GroupByField } from '../common/group_by_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; export function CustomKqlIndicatorTypeForm() { @@ -28,7 +28,7 @@ export function CustomKqlIndicatorTypeForm() { }); return ( - <EuiFlexGroup direction="column" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> <IndexAndTimestampField dataView={dataView} isLoading={isIndexFieldsLoading} /> <EuiFlexItem> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.stories.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.stories.tsx similarity index 89% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.stories.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.stories.tsx index 1abbff61a0dc..771405a539f1 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.stories.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.stories.tsx @@ -9,9 +9,9 @@ import React from 'react'; import { ComponentStory } from '@storybook/react'; import { FormProvider, useForm } from 'react-hook-form'; -import { KibanaReactStorybookDecorator } from '../../../../utils/kibana_react.storybook_decorator'; +import { KibanaReactStorybookDecorator } from '../../../../../utils/kibana_react.storybook_decorator'; import { CustomMetricIndicatorTypeForm as Component } from './custom_metric_type_form'; -import { SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC } from '../../constants'; +import { SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC } from '../../../constants'; export default { component: Component, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.tsx index ee9bcf8d9964..365205ed6b4b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/custom_metric_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/custom_metric_type_form.tsx @@ -18,11 +18,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { GroupByField } from '../common/group_by_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; +import { GroupByField } from '../../common/group_by_field'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; import { MetricIndicator } from './metric_indicator'; @@ -55,7 +55,7 @@ export function CustomMetricIndicatorTypeForm() { </h3> </EuiTitle> <EuiSpacer size="s" /> - <EuiFlexGroup direction="column" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> <IndexAndTimestampField dataView={dataView} isLoading={isIndexFieldsLoading} /> <EuiFlexItem> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/metric_indicator.tsx similarity index 60% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/metric_indicator.tsx index 03939dce314b..519167be5db2 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/custom_metric/metric_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/custom_metric/metric_indicator.tsx @@ -26,10 +26,10 @@ import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; import { aggValueToLabel, CUSTOM_METRIC_AGGREGATION_OPTIONS, -} from '../../helpers/aggregation_options'; -import { createOptionsFromFields, Option } from '../../helpers/create_options'; -import { CreateSLOForm } from '../../types'; -import { QueryBuilder } from '../common/query_builder'; +} from '../../../helpers/aggregation_options'; +import { createOptionsFromFields, Option } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; +import { QueryBuilder } from '../../common/query_builder'; interface MetricIndicatorProps { type: 'good' | 'total'; @@ -134,95 +134,28 @@ export function MetricIndicator({ <EuiFlexItem> {fields?.map((metric, index, arr) => ( <div key={metric.id}> - <EuiFlexGroup alignItems="center" gutterSize="xs" key={metric.id}> - <input hidden {...register(`indicator.params.${type}.metrics.${index}.name`)} /> - <EuiFlexItem> - <EuiFormRow - fullWidth - isInvalid={ - getFieldState(`indicator.params.${type}.metrics.${index}.aggregation`).invalid - } - label={ - <span> - {i18n.translate('xpack.slo.sloEdit.customMetric.aggregationLabel', { - defaultMessage: 'Aggregation', - })}{' '} - {metric.name} - </span> - } - > - <Controller - name={`indicator.params.${type}.metrics.${index}.aggregation`} - defaultValue="sum" - rules={{ required: true }} - control={control} - render={({ field: { ref, ...field }, fieldState }) => ( - <EuiComboBox - {...field} - async - fullWidth - singleSelection={{ asPlainText: true }} - placeholder={i18n.translate( - 'xpack.slo.sloEdit.sliType.customMetric.aggregation.placeholder', - { defaultMessage: 'Select an aggregation' } - )} - aria-label={i18n.translate( - 'xpack.slo.sloEdit.sliType.customMetric.aggregation.placeholder', - { defaultMessage: 'Select an aggregation' } - )} - isClearable - isInvalid={fieldState.invalid} - isDisabled={isLoadingIndex || !indexPattern} - isLoading={!!indexPattern && isLoadingIndex} - onChange={(selected: EuiComboBoxOptionOption[]) => { - if (selected.length) { - return field.onChange(selected[0].value); - } - field.onChange(''); - }} - selectedOptions={ - !!indexPattern && - !!field.value && - CUSTOM_METRIC_AGGREGATION_OPTIONS.some((agg) => agg.value === field.value) - ? [ - { - value: field.value, - label: aggValueToLabel(field.value), - }, - ] - : [] - } - onSearchChange={(searchValue: string) => { - setAggregationOptions( - CUSTOM_METRIC_AGGREGATION_OPTIONS.filter(({ value }) => - value.includes(searchValue) - ) - ); - }} - options={aggregationOptions} - /> - )} - /> - </EuiFormRow> - </EuiFlexItem> - {watch(`indicator.params.${type}.metrics.${index}.aggregation`) !== 'doc_count' && ( + <EuiFlexGroup direction="column" gutterSize="xs"> + <EuiFlexGroup alignItems="center" gutterSize="xs" key={metric.id}> + <input hidden {...register(`indicator.params.${type}.metrics.${index}.name`)} /> <EuiFlexItem> <EuiFormRow fullWidth isInvalid={ - getFieldState(`indicator.params.${type}.metrics.${index}.field`).invalid + getFieldState(`indicator.params.${type}.metrics.${index}.aggregation`).invalid } label={ <span> - {metricLabel} {metric.name} {metricTooltip} + {i18n.translate('xpack.slo.sloEdit.customMetric.aggregationLabel', { + defaultMessage: 'Aggregation', + })}{' '} + {metric.name} </span> } > <Controller - name={`indicator.params.${type}.metrics.${index}.field`} - defaultValue="" + name={`indicator.params.${type}.metrics.${index}.aggregation`} + defaultValue="sum" rules={{ required: true }} - shouldUnregister control={control} render={({ field: { ref, ...field }, fieldState }) => ( <EuiComboBox @@ -231,12 +164,12 @@ export function MetricIndicator({ fullWidth singleSelection={{ asPlainText: true }} placeholder={i18n.translate( - 'xpack.slo.sloEdit.sliType.customMetric.metricField.placeholder', - { defaultMessage: 'Select a metric field' } + 'xpack.slo.sloEdit.sliType.customMetric.aggregation.placeholder', + { defaultMessage: 'Select an aggregation' } )} aria-label={i18n.translate( - 'xpack.slo.sloEdit.sliType.customMetric.metricField.placeholder', - { defaultMessage: 'Select a metric field' } + 'xpack.slo.sloEdit.sliType.customMetric.aggregation.placeholder', + { defaultMessage: 'Select an aggregation' } )} isClearable isInvalid={fieldState.invalid} @@ -251,64 +184,138 @@ export function MetricIndicator({ selectedOptions={ !!indexPattern && !!field.value && - metricFields.some((metricField) => metricField.name === field.value) + CUSTOM_METRIC_AGGREGATION_OPTIONS.some( + (agg) => agg.value === field.value + ) ? [ { value: field.value, - label: field.value, + label: aggValueToLabel(field.value), }, ] : [] } onSearchChange={(searchValue: string) => { - setOptions( - createOptionsFromFields(metricFields, ({ value }) => + setAggregationOptions( + CUSTOM_METRIC_AGGREGATION_OPTIONS.filter(({ value }) => value.includes(searchValue) ) ); }} - options={options} + options={aggregationOptions} /> )} /> </EuiFormRow> </EuiFlexItem> - )} - <EuiFlexItem grow={0}> - <EuiButtonIcon - data-test-subj="o11yMetricIndicatorButton" - iconType="trash" - color="danger" - style={{ marginTop: '1.5em' }} - onClick={handleDeleteMetric(index)} - disabled={disableDelete} - title={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.deleteLabel', { - defaultMessage: 'Delete metric', - })} - aria-label={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.deleteLabel', { - defaultMessage: 'Delete metric', - })} - /> - </EuiFlexItem> + {watch(`indicator.params.${type}.metrics.${index}.aggregation`) !== 'doc_count' && ( + <EuiFlexItem> + <EuiFormRow + fullWidth + isInvalid={ + getFieldState(`indicator.params.${type}.metrics.${index}.field`).invalid + } + label={ + <span> + {metricLabel} {metric.name} {metricTooltip} + </span> + } + > + <Controller + name={`indicator.params.${type}.metrics.${index}.field`} + defaultValue="" + rules={{ required: true }} + shouldUnregister + control={control} + render={({ field: { ref, ...field }, fieldState }) => ( + <EuiComboBox + {...field} + async + fullWidth + singleSelection={{ asPlainText: true }} + placeholder={i18n.translate( + 'xpack.slo.sloEdit.sliType.customMetric.metricField.placeholder', + { defaultMessage: 'Select a metric field' } + )} + aria-label={i18n.translate( + 'xpack.slo.sloEdit.sliType.customMetric.metricField.placeholder', + { defaultMessage: 'Select a metric field' } + )} + isClearable + isInvalid={fieldState.invalid} + isDisabled={isLoadingIndex || !indexPattern} + isLoading={!!indexPattern && isLoadingIndex} + onChange={(selected: EuiComboBoxOptionOption[]) => { + if (selected.length) { + return field.onChange(selected[0].value); + } + field.onChange(''); + }} + selectedOptions={ + !!indexPattern && + !!field.value && + metricFields.some((metricField) => metricField.name === field.value) + ? [ + { + value: field.value, + label: field.value, + }, + ] + : [] + } + onSearchChange={(searchValue: string) => { + setOptions( + createOptionsFromFields(metricFields, ({ value }) => + value.includes(searchValue) + ) + ); + }} + options={options} + /> + )} + /> + </EuiFormRow> + </EuiFlexItem> + )} + <EuiFlexItem grow={0}> + <EuiButtonIcon + data-test-subj="o11yMetricIndicatorButton" + iconType="trash" + color="danger" + style={{ marginTop: '1.5em' }} + onClick={handleDeleteMetric(index)} + disabled={disableDelete} + title={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.deleteLabel', { + defaultMessage: 'Delete metric', + })} + aria-label={i18n.translate( + 'xpack.slo.sloEdit.sliType.customMetric.deleteLabel', + { + defaultMessage: 'Delete metric', + } + )} + /> + </EuiFlexItem> + </EuiFlexGroup> + <QueryBuilder + dataTestSubj="customKqlIndicatorFormGoodQueryInput" + dataView={dataView} + label={`${filterLabel} ${metric.name}`} + name={`indicator.params.${type}.metrics.${index}.filter`} + placeholder={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.placeholder', { + defaultMessage: 'KQL filter', + })} + required={false} + tooltip={ + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.tooltip', { + defaultMessage: 'This KQL query should return a subset of events.', + })} + position="top" + /> + } + /> </EuiFlexGroup> - <QueryBuilder - dataTestSubj="customKqlIndicatorFormGoodQueryInput" - dataView={dataView} - label={`${filterLabel} ${metric.name}`} - name={`indicator.params.${type}.metrics.${index}.filter`} - placeholder={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.placeholder', { - defaultMessage: 'KQL filter', - })} - required={false} - tooltip={ - <EuiIconTip - content={i18n.translate('xpack.slo.sloEdit.sliType.customMetric.tooltip', { - defaultMessage: 'This KQL query should return a subset of events.', - })} - position="top" - /> - } - /> {index !== arr.length - 1 && <EuiHorizontalRule size="quarter" />} </div> ))} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator.tsx similarity index 98% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator.tsx index 009504e5e697..3b435fa52494 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator.tsx @@ -19,9 +19,9 @@ import { DataView, FieldSpec } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; import React, { Fragment, useEffect, useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { createOptionsFromFields, Option } from '../../helpers/create_options'; -import { CreateSLOForm } from '../../types'; -import { QueryBuilder } from '../common/query_builder'; +import { createOptionsFromFields, Option } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; +import { QueryBuilder } from '../../common/query_builder'; interface HistogramIndicatorProps { type: 'good' | 'total'; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator_type_form.tsx similarity index 91% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator_type_form.tsx index 6bb1918dba3c..2e934c74d9d0 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/histogram/histogram_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/histogram/histogram_indicator_type_form.tsx @@ -18,11 +18,11 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { GroupByField } from '../common/group_by_field'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { GroupByField } from '../../common/group_by_field'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; import { HistogramIndicator } from './histogram_indicator'; @@ -49,7 +49,7 @@ export function HistogramIndicatorTypeForm() { </h3> </EuiTitle> <EuiSpacer size="s" /> - <EuiFlexGroup direction="column" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> <IndexAndTimestampField dataView={dataView} isLoading={isIndexFieldsLoading} /> <EuiFlexItem> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx similarity index 100% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.test.tsx diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.tsx similarity index 93% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.tsx index 07f2f8666329..88dbb16d667b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_availability/synthetics_availability_indicator_type_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form.tsx @@ -17,12 +17,12 @@ import moment from 'moment'; import React, { useEffect, useState } from 'react'; import { useFormContext } from 'react-hook-form'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; -import { formatAllFilters } from '../../helpers/format_filters'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { GroupByCardinality } from '../common/group_by_cardinality'; -import { QueryBuilder } from '../common/query_builder'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; +import { formatAllFilters } from '../../../helpers/format_filters'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { GroupByCardinality } from '../../common/group_by_cardinality'; +import { QueryBuilder } from '../../common/query_builder'; import { FieldSelector } from '../synthetics_common/field_selector'; export function SyntheticsAvailabilityIndicatorTypeForm() { @@ -74,8 +74,8 @@ export function SyntheticsAvailabilityIndicatorTypeForm() { }, [currentMonitors, setValue]); return ( - <EuiFlexGroup direction="column" gutterSize="l"> - <EuiFlexGroup direction="column" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> + <EuiFlexGroup direction="column" gutterSize="m"> <FieldSelector required allowAllOption @@ -130,7 +130,7 @@ export function SyntheticsAvailabilityIndicatorTypeForm() { /> </EuiFlexGroup> - <EuiFlexGroup direction="row" gutterSize="l"> + <EuiFlexGroup direction="row" gutterSize="m"> <EuiFlexItem> <QueryBuilder dataTestSubj="syntheticsAvailabilityFilterInput" diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_common/field_selector.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_common/field_selector.tsx similarity index 96% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_common/field_selector.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_common/field_selector.tsx index 1fea21a322c7..2dffc3abd4ea 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/synthetics_common/field_selector.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/synthetics_common/field_selector.tsx @@ -11,12 +11,12 @@ import { i18n } from '@kbn/i18n'; import { ALL_VALUE, SyntheticsAvailabilityIndicator } from '@kbn/slo-schema'; import { debounce } from 'lodash'; import { Controller, FieldPath, useFormContext } from 'react-hook-form'; -import { OptionalText } from '../common/optional_text'; +import { OptionalText } from '../../common/optional_text'; import { useFetchSyntheticsSuggestions, Suggestion, -} from '../../../../hooks/use_fetch_synthetics_suggestions'; -import { CreateSLOForm } from '../../types'; +} from '../../../../../hooks/use_fetch_synthetics_suggestions'; +import { CreateSLOForm } from '../../../types'; interface Option { label: string; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_indicator.tsx similarity index 80% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_indicator.tsx index e035680e5902..39fc95c04c12 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_indicator.tsx @@ -24,9 +24,9 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { first, range, xor } from 'lodash'; import React from 'react'; import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; -import { QueryBuilder } from '../common/query_builder'; -import { COMPARATOR_OPTIONS } from '../../constants'; -import { CreateSLOForm } from '../../types'; +import { QueryBuilder } from '../../common/query_builder'; +import { COMPARATOR_OPTIONS } from '../../../constants'; +import { CreateSLOForm } from '../../../types'; import { MetricInput } from './metric_input'; interface MetricIndicatorProps { @@ -117,54 +117,56 @@ export function MetricIndicator({ indexFields, isLoadingIndex, dataView }: Metri <EuiFlexItem> {fields?.map((metric, index, arr) => ( <React.Fragment key={metric.id}> - <EuiFlexGroup alignItems="center" gutterSize="xs"> - <input hidden {...register(`indicator.params.metric.metrics.${index}.name`)} /> - <MetricInput - isLoadingIndex={isLoadingIndex} - metricIndex={index} - indexPattern={indexPattern} - indexFields={indexFields} - /> - <EuiFlexItem grow={0}> - <EuiButtonIcon - data-test-subj="o11yMetricIndicatorButton" - iconType="trash" - color="danger" - style={{ marginTop: '1.5em' }} - onClick={handleDeleteMetric(index)} - disabled={disableDelete} - title={i18n.translate('xpack.slo.sloEdit.sliType.timesliceMetric.deleteLabel', { - defaultMessage: 'Delete metric', - })} - aria-label={i18n.translate( - 'xpack.slo.sloEdit.sliType.timesliceMetric.deleteLabel', - { defaultMessage: 'Delete metric' } - )} + <EuiFlexGroup direction="column" gutterSize="xs"> + <EuiFlexGroup alignItems="center" gutterSize="xs"> + <input hidden {...register(`indicator.params.metric.metrics.${index}.name`)} /> + <MetricInput + isLoadingIndex={isLoadingIndex} + metricIndex={index} + indexPattern={indexPattern} + indexFields={indexFields} /> - </EuiFlexItem> + <EuiFlexItem grow={0}> + <EuiButtonIcon + data-test-subj="o11yMetricIndicatorButton" + iconType="trash" + color="danger" + style={{ marginTop: '1.5em' }} + onClick={handleDeleteMetric(index)} + disabled={disableDelete} + title={i18n.translate('xpack.slo.sloEdit.sliType.timesliceMetric.deleteLabel', { + defaultMessage: 'Delete metric', + })} + aria-label={i18n.translate( + 'xpack.slo.sloEdit.sliType.timesliceMetric.deleteLabel', + { defaultMessage: 'Delete metric' } + )} + /> + </EuiFlexItem> + </EuiFlexGroup> + <QueryBuilder + dataTestSubj="timesliceMetricIndicatorFormMetricQueryInput" + dataView={dataView} + label={`${filterLabel} ${metric.name}`} + name={`indicator.params.metric.metrics.${index}.filter`} + placeholder={i18n.translate( + 'xpack.slo.sloEdit.sliType.timesliceMetric.goodQuery.placeholder', + { defaultMessage: 'KQL filter' } + )} + required={false} + tooltip={ + <EuiIconTip + content={i18n.translate( + 'xpack.slo.sloEdit.sliType.timesliceMetric.goodQuery.tooltip', + { + defaultMessage: 'This KQL query should return a subset of events.', + } + )} + position="top" + /> + } + /> </EuiFlexGroup> - <QueryBuilder - dataTestSubj="timesliceMetricIndicatorFormMetricQueryInput" - dataView={dataView} - label={`${filterLabel} ${metric.name}`} - name={`indicator.params.metric.metrics.${index}.filter`} - placeholder={i18n.translate( - 'xpack.slo.sloEdit.sliType.timesliceMetric.goodQuery.placeholder', - { defaultMessage: 'KQL filter' } - )} - required={false} - tooltip={ - <EuiIconTip - content={i18n.translate( - 'xpack.slo.sloEdit.sliType.timesliceMetric.goodQuery.tooltip', - { - defaultMessage: 'This KQL query should return a subset of events.', - } - )} - position="top" - /> - } - /> {index !== arr.length - 1 && <EuiHorizontalRule size="quarter" />} </React.Fragment> ))} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_input.tsx similarity index 97% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_input.tsx index ebb539b97dab..ef798305b20d 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/metric_input.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/metric_input.tsx @@ -16,9 +16,9 @@ import { FieldSpec } from '@kbn/data-views-plugin/common'; import { i18n } from '@kbn/i18n'; import React, { useEffect, useState } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; -import { AGGREGATION_OPTIONS, aggValueToLabel } from '../../helpers/aggregation_options'; -import { createOptionsFromFields, Option } from '../../helpers/create_options'; -import { CreateSLOForm } from '../../types'; +import { AGGREGATION_OPTIONS, aggValueToLabel } from '../../../helpers/aggregation_options'; +import { createOptionsFromFields, Option } from '../../../helpers/create_options'; +import { CreateSLOForm } from '../../../types'; const fieldLabel = i18n.translate('xpack.slo.sloEdit.sliType.timesliceMetric.fieldLabel', { defaultMessage: 'Field', diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/timeslice_metric_indicator.tsx similarity index 88% rename from x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx rename to x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/timeslice_metric_indicator.tsx index 86eede0ba65e..73bc3135d91a 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/timeslice_metric/timeslice_metric_indicator.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/indicator_section/timeslice_metric/timeslice_metric_indicator.tsx @@ -19,15 +19,15 @@ import { FormattedMessage } from '@kbn/i18n-react'; import React from 'react'; import { useFormContext } from 'react-hook-form'; import { IndexAndTimestampField } from '../custom_common/index_and_timestamp_field'; -import { useKibana } from '../../../../hooks/use_kibana'; -import { GroupByField } from '../common/group_by_field'; -import { CreateSLOForm } from '../../types'; -import { DataPreviewChart } from '../common/data_preview_chart'; -import { QueryBuilder } from '../common/query_builder'; +import { useKibana } from '../../../../../hooks/use_kibana'; +import { GroupByField } from '../../common/group_by_field'; +import { CreateSLOForm } from '../../../types'; +import { DataPreviewChart } from '../../common/data_preview_chart'; +import { QueryBuilder } from '../../common/query_builder'; import { DATA_VIEW_FIELD } from '../custom_common/index_selection'; import { MetricIndicator } from './metric_indicator'; -import { COMPARATOR_MAPPING } from '../../constants'; -import { useCreateDataView } from '../../../../hooks/use_create_data_view'; +import { COMPARATOR_MAPPING } from '../../../constants'; +import { useCreateDataView } from '../../../../../hooks/use_create_data_view'; export { NEW_TIMESLICE_METRIC } from './metric_indicator'; @@ -54,7 +54,7 @@ export function TimesliceMetricIndicatorTypeForm() { </h3> </EuiTitle> <EuiSpacer size="s" /> - <EuiFlexGroup direction="column" gutterSize="l"> + <EuiFlexGroup direction="column" gutterSize="m"> <IndexAndTimestampField dataView={dataView} isLoading={isIndexFieldsLoading} /> <EuiFlexItem> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx index 7ffc274ffce1..9082d5367670 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form.tsx @@ -5,43 +5,56 @@ * 2.0. */ -import { EuiFlexGroup, EuiSpacer, EuiSteps } from '@elastic/eui'; +import { EuiFlexGroup, EuiSteps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { GetSLOResponse } from '@kbn/slo-schema'; +import type { CreateSLOInput, GetSLOResponse } from '@kbn/slo-schema'; +import { RecursivePartial } from '@kbn/utility-types'; import React from 'react'; import { FormProvider, useForm } from 'react-hook-form'; -import { RecursivePartial } from '@kbn/utility-types'; -import { SloEditFormFooter } from './slo_edit_form_footer'; import { SLO_EDIT_FORM_DEFAULT_VALUES } from '../constants'; -import { transformSloResponseToCreateSloForm } from '../helpers/process_slo_form_values'; +import { + transformPartialSLOStateToFormState, + transformSloResponseToCreateSloForm, +} from '../helpers/process_slo_form_values'; import { useParseUrlState } from '../hooks/use_parse_url_state'; import { useSectionFormValidation } from '../hooks/use_section_form_validation'; import { useShowSections } from '../hooks/use_show_sections'; import { CreateSLOForm } from '../types'; import { SloEditFormDescriptionSection } from './slo_edit_form_description_section'; +import { SloEditFormFooter } from './slo_edit_form_footer'; import { SloEditFormIndicatorSection } from './slo_edit_form_indicator_section'; import { SloEditFormObjectiveSection } from './slo_edit_form_objective_section'; export interface Props { slo?: GetSLOResponse; - initialValues?: RecursivePartial<CreateSLOForm>; + initialValues?: RecursivePartial<CreateSLOInput>; onSave?: () => void; } -export const maxWidth = 900; - export function SloEditForm({ slo, initialValues, onSave }: Props) { const isEditMode = slo !== undefined; + const isFlyoutMode = initialValues !== undefined && onSave !== undefined; - const sloFormValuesFromUrlState = useParseUrlState() ?? (initialValues as CreateSLOForm); + const sloFormValuesFromFlyoutState = isFlyoutMode + ? transformPartialSLOStateToFormState(initialValues) + : undefined; + const sloFormValuesFromUrlState = useParseUrlState(); const sloFormValuesFromSloResponse = transformSloResponseToCreateSloForm(slo); - const methods = useForm<CreateSLOForm>({ - defaultValues: sloFormValuesFromUrlState ?? SLO_EDIT_FORM_DEFAULT_VALUES, - values: sloFormValuesFromUrlState ? sloFormValuesFromUrlState : sloFormValuesFromSloResponse, + const form = useForm<CreateSLOForm>({ + defaultValues: isFlyoutMode + ? sloFormValuesFromFlyoutState + : sloFormValuesFromUrlState + ? sloFormValuesFromUrlState + : sloFormValuesFromSloResponse ?? SLO_EDIT_FORM_DEFAULT_VALUES, + values: isFlyoutMode + ? sloFormValuesFromFlyoutState + : sloFormValuesFromUrlState + ? sloFormValuesFromUrlState + : sloFormValuesFromSloResponse, mode: 'all', }); - const { watch, getFieldState, getValues, formState } = methods; + const { watch, getFieldState, getValues, formState } = form; const { isIndicatorSectionValid, isObjectiveSectionValid, isDescriptionSectionValid } = useSectionFormValidation({ @@ -59,41 +72,37 @@ export function SloEditForm({ slo, initialValues, onSave }: Props) { ); return ( - <> - <FormProvider {...methods}> - <EuiFlexGroup direction="column" gutterSize="s" data-test-subj="sloForm"> - <EuiSteps - steps={[ - { - title: i18n.translate('xpack.slo.sloEdit.definition.title', { - defaultMessage: 'Define SLI', - }), - children: <SloEditFormIndicatorSection isEditMode={isEditMode} />, - status: isIndicatorSectionValid ? 'complete' : 'incomplete', - }, - { - title: i18n.translate('xpack.slo.sloEdit.objectives.title', { - defaultMessage: 'Set objectives', - }), - children: showObjectiveSection ? <SloEditFormObjectiveSection /> : null, - status: showObjectiveSection && isObjectiveSectionValid ? 'complete' : 'incomplete', - }, - { - title: i18n.translate('xpack.slo.sloEdit.description.title', { - defaultMessage: 'Describe SLO', - }), - children: showDescriptionSection ? <SloEditFormDescriptionSection /> : null, - status: - showDescriptionSection && isDescriptionSectionValid ? 'complete' : 'incomplete', - }, - ]} - /> - - <EuiSpacer size="m" /> + <FormProvider {...form}> + <EuiFlexGroup direction="column" gutterSize="m" data-test-subj="sloForm"> + <EuiSteps + steps={[ + { + title: i18n.translate('xpack.slo.sloEdit.definition.title', { + defaultMessage: 'Define SLI', + }), + children: <SloEditFormIndicatorSection isEditMode={isEditMode} />, + status: isIndicatorSectionValid ? 'complete' : 'incomplete', + }, + { + title: i18n.translate('xpack.slo.sloEdit.objectives.title', { + defaultMessage: 'Set objectives', + }), + children: showObjectiveSection ? <SloEditFormObjectiveSection /> : null, + status: showObjectiveSection && isObjectiveSectionValid ? 'complete' : 'incomplete', + }, + { + title: i18n.translate('xpack.slo.sloEdit.description.title', { + defaultMessage: 'Describe SLO', + }), + children: showDescriptionSection ? <SloEditFormDescriptionSection /> : null, + status: + showDescriptionSection && isDescriptionSectionValid ? 'complete' : 'incomplete', + }, + ]} + /> - <SloEditFormFooter slo={slo} onSave={onSave} /> - </EuiFlexGroup> - </FormProvider> - </> + <SloEditFormFooter slo={slo} onSave={onSave} /> + </EuiFlexGroup> + </FormProvider> ); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx index a210021674f6..f242669e566d 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_description_section.tsx @@ -9,8 +9,6 @@ import { EuiComboBox, EuiComboBoxOptionOption, EuiFieldText, - EuiFlexGroup, - EuiFlexItem, EuiFormRow, EuiPanel, EuiTextArea, @@ -20,9 +18,9 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { useFetchSLOSuggestions } from '../hooks/use_fetch_suggestions'; -import { OptionalText } from './common/optional_text'; import { CreateSLOForm } from '../types'; -import { maxWidth } from './slo_edit_form'; +import { OptionalText } from './common/optional_text'; +import { MAX_WIDTH } from '../constants'; export function SloEditFormDescriptionSection() { const { control, getFieldState } = useFormContext<CreateSLOForm>(); @@ -37,129 +35,117 @@ export function SloEditFormDescriptionSection() { hasBorder={false} hasShadow={false} paddingSize="none" - style={{ maxWidth }} + style={{ maxWidth: MAX_WIDTH }} data-test-subj="sloEditFormDescriptionSection" > - <EuiFlexGroup direction="column" gutterSize="l"> - <EuiFlexItem> - <EuiFormRow - fullWidth - isInvalid={getFieldState('name').invalid} - label={i18n.translate('xpack.slo.sloEdit.description.sloName', { - defaultMessage: 'SLO Name', - })} - > - <Controller - name="name" - control={control} - rules={{ required: true }} - render={({ field: { ref, ...field }, fieldState }) => ( - <EuiFieldText - {...field} - fullWidth - isInvalid={fieldState.invalid} - id={sloNameId} - data-test-subj="sloFormNameInput" - placeholder={i18n.translate('xpack.slo.sloEdit.description.sloNamePlaceholder', { - defaultMessage: 'Name for the SLO', - })} - /> - )} + <EuiFormRow + fullWidth + isInvalid={getFieldState('name').invalid} + label={i18n.translate('xpack.slo.sloEdit.description.sloName', { + defaultMessage: 'SLO Name', + })} + > + <Controller + name="name" + control={control} + rules={{ required: true }} + render={({ field: { ref, ...field }, fieldState }) => ( + <EuiFieldText + {...field} + fullWidth + isInvalid={fieldState.invalid} + id={sloNameId} + data-test-subj="sloFormNameInput" + placeholder={i18n.translate('xpack.slo.sloEdit.description.sloNamePlaceholder', { + defaultMessage: 'Name for the SLO', + })} /> - </EuiFormRow> - </EuiFlexItem> + )} + /> + </EuiFormRow> - <EuiFlexItem grow> - <EuiFormRow - fullWidth - label={i18n.translate('xpack.slo.sloEdit.description.sloDescription', { - defaultMessage: 'Description', - })} - labelAppend={<OptionalText />} - > - <Controller - name="description" - defaultValue="" - control={control} - rules={{ required: false }} - render={({ field: { ref, ...field } }) => ( - <EuiTextArea - {...field} - fullWidth - id={descriptionId} - data-test-subj="sloFormDescriptionTextArea" - placeholder={i18n.translate( - 'xpack.slo.sloEdit.description.sloDescriptionPlaceholder', - { - defaultMessage: 'A short description of the SLO', - } - )} - /> + <EuiFormRow + fullWidth + label={i18n.translate('xpack.slo.sloEdit.description.sloDescription', { + defaultMessage: 'Description', + })} + labelAppend={<OptionalText />} + > + <Controller + name="description" + defaultValue="" + control={control} + rules={{ required: false }} + render={({ field: { ref, ...field } }) => ( + <EuiTextArea + {...field} + fullWidth + id={descriptionId} + data-test-subj="sloFormDescriptionTextArea" + placeholder={i18n.translate( + 'xpack.slo.sloEdit.description.sloDescriptionPlaceholder', + { + defaultMessage: 'A short description of the SLO', + } )} /> - </EuiFormRow> - </EuiFlexItem> + )} + /> + </EuiFormRow> - <EuiFlexItem grow> - <EuiFormRow - fullWidth - label={i18n.translate('xpack.slo.sloEdit.tags.label', { - defaultMessage: 'Tags', - })} - > - <Controller - name="tags" - control={control} - defaultValue={[]} - rules={{ required: false }} - render={({ field: { ref, ...field }, fieldState }) => ( - <EuiComboBox - {...field} - id={tagsId} - fullWidth - aria-label={i18n.translate('xpack.slo.sloEdit.tags.placeholder', { - defaultMessage: 'Add tags', - })} - placeholder={i18n.translate('xpack.slo.sloEdit.tags.placeholder', { - defaultMessage: 'Add tags', - })} - isInvalid={fieldState.invalid} - options={suggestions?.tags ?? []} - selectedOptions={generateTagOptions(field.value)} - onChange={(selected: EuiComboBoxOptionOption[]) => { - if (selected.length) { - return field.onChange(selected.map((opts) => opts.value)); - } + <EuiFormRow + fullWidth + label={i18n.translate('xpack.slo.sloEdit.tags.label', { + defaultMessage: 'Tags', + })} + > + <Controller + name="tags" + control={control} + defaultValue={[]} + rules={{ required: false }} + render={({ field: { ref, ...field }, fieldState }) => ( + <EuiComboBox + {...field} + id={tagsId} + fullWidth + aria-label={i18n.translate('xpack.slo.sloEdit.tags.placeholder', { + defaultMessage: 'Add tags', + })} + placeholder={i18n.translate('xpack.slo.sloEdit.tags.placeholder', { + defaultMessage: 'Add tags', + })} + isInvalid={fieldState.invalid} + options={suggestions?.tags ?? []} + selectedOptions={generateTagOptions(field.value)} + onChange={(selected: EuiComboBoxOptionOption[]) => { + if (selected.length) { + return field.onChange(selected.map((opts) => opts.value)); + } - field.onChange([]); - }} - onCreateOption={( - searchValue: string, - options: EuiComboBoxOptionOption[] = [] - ) => { - const normalizedSearchValue = searchValue.trim().toLowerCase(); + field.onChange([]); + }} + onCreateOption={(searchValue: string, options: EuiComboBoxOptionOption[] = []) => { + const normalizedSearchValue = searchValue.trim().toLowerCase(); - if (!normalizedSearchValue) { - return; - } - const values = field.value ?? []; + if (!normalizedSearchValue) { + return; + } + const values = field.value ?? []; - if ( - values.findIndex( - (tag) => tag.trim().toLowerCase() === normalizedSearchValue - ) === -1 - ) { - field.onChange([...values, searchValue]); - } - }} - isClearable - data-test-subj="sloEditTagsSelector" - /> - )} + if ( + values.findIndex((tag) => tag.trim().toLowerCase() === normalizedSearchValue) === + -1 + ) { + field.onChange([...values, searchValue]); + } + }} + isClearable + data-test-subj="sloEditTagsSelector" /> - </EuiFormRow> - </EuiFlexItem> - </EuiFlexGroup> + )} + /> + </EuiFormRow> </EuiPanel> ); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx index 156f45c2c982..4d30bef7ac69 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_indicator_section.tsx @@ -7,19 +7,20 @@ import { EuiFormRow, EuiPanel, EuiSelect, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { assertNever } from '@kbn/std'; import React, { useMemo } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { SLI_OPTIONS } from '../constants'; import { useUnregisterFields } from '../hooks/use_unregister_fields'; import { CreateSLOForm } from '../types'; -import { ApmAvailabilityIndicatorTypeForm } from './apm_availability/apm_availability_indicator_type_form'; -import { ApmLatencyIndicatorTypeForm } from './apm_latency/apm_latency_indicator_type_form'; -import { SyntheticsAvailabilityIndicatorTypeForm } from './synthetics_availability/synthetics_availability_indicator_type_form'; -import { CustomKqlIndicatorTypeForm } from './custom_kql/custom_kql_indicator_type_form'; -import { CustomMetricIndicatorTypeForm } from './custom_metric/custom_metric_type_form'; -import { HistogramIndicatorTypeForm } from './histogram/histogram_indicator_type_form'; -import { maxWidth } from './slo_edit_form'; -import { TimesliceMetricIndicatorTypeForm } from './timeslice_metric/timeslice_metric_indicator'; +import { MAX_WIDTH } from '../constants'; +import { ApmAvailabilityIndicatorTypeForm } from './indicator_section/apm_availability/apm_availability_indicator_type_form'; +import { ApmLatencyIndicatorTypeForm } from './indicator_section/apm_latency/apm_latency_indicator_type_form'; +import { CustomKqlIndicatorTypeForm } from './indicator_section/custom_kql/custom_kql_indicator_type_form'; +import { CustomMetricIndicatorTypeForm } from './indicator_section/custom_metric/custom_metric_type_form'; +import { HistogramIndicatorTypeForm } from './indicator_section/histogram/histogram_indicator_type_form'; +import { SyntheticsAvailabilityIndicatorTypeForm } from './indicator_section/synthetics_availability/synthetics_availability_indicator_type_form'; +import { TimesliceMetricIndicatorTypeForm } from './indicator_section/timeslice_metric/timeslice_metric_indicator'; interface SloEditFormIndicatorSectionProps { isEditMode: boolean; @@ -48,7 +49,7 @@ export function SloEditFormIndicatorSection({ isEditMode }: SloEditFormIndicator case 'sli.metric.timeslice': return <TimesliceMetricIndicatorTypeForm />; default: - return null; + assertNever(indicatorType); } }, [indicatorType]); @@ -57,7 +58,7 @@ export function SloEditFormIndicatorSection({ isEditMode }: SloEditFormIndicator hasBorder={false} hasShadow={false} paddingSize="none" - style={{ maxWidth }} + style={{ maxWidth: MAX_WIDTH }} data-test-subj="sloEditFormIndicatorSection" > {!isEditMode && ( @@ -78,7 +79,7 @@ export function SloEditFormIndicatorSection({ isEditMode }: SloEditFormIndicator )} /> </EuiFormRow> - <EuiSpacer size="xxl" /> + <EuiSpacer size="xl" /> </> )} {indicatorTypeForm} diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx index 15c51b1b86ce..65e4a25a86c3 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/components/slo_edit_form_objective_section.tsx @@ -7,15 +7,14 @@ import { EuiCallOut, - EuiCheckbox, EuiFieldNumber, EuiFlexGrid, + EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiIconTip, EuiPanel, EuiSelect, - EuiSpacer, useGeneratedHtmlId, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -30,7 +29,8 @@ import { TIMEWINDOW_TYPE_OPTIONS, } from '../constants'; import { CreateSLOForm } from '../types'; -import { maxWidth } from './slo_edit_form'; +import { MAX_WIDTH } from '../constants'; +import { AdvancedSettings } from './indicator_section/advanced_settings/advanced_settings'; import { SloEditFormObjectiveSectionTimeslices } from './slo_edit_form_objective_section_timeslices'; export function SloEditFormObjectiveSection() { @@ -44,7 +44,6 @@ export function SloEditFormObjectiveSection() { const budgetingSelect = useGeneratedHtmlId({ prefix: 'budgetingSelect' }); const timeWindowTypeSelect = useGeneratedHtmlId({ prefix: 'timeWindowTypeSelect' }); const timeWindowSelect = useGeneratedHtmlId({ prefix: 'timeWindowSelect' }); - const preventBackfillCheckbox = useGeneratedHtmlId({ prefix: 'preventBackfill' }); const timeWindowType = watch('timeWindow.type'); const indicator = watch('indicator.type'); @@ -91,237 +90,199 @@ export function SloEditFormObjectiveSection() { hasBorder={false} hasShadow={false} paddingSize="none" - style={{ maxWidth }} + style={{ maxWidth: MAX_WIDTH }} data-test-subj="sloEditFormObjectiveSection" > - <EuiFlexGrid columns={3}> - <EuiFlexItem> - <EuiFormRow - label={ - <span> - {i18n.translate('xpack.slo.sloEdit.timeWindowType.label', { - defaultMessage: 'Time window', - })}{' '} - <EuiIconTip - content={i18n.translate('xpack.slo.sloEdit.timeWindowType.tooltip', { - defaultMessage: 'Choose between a rolling or a calendar aligned window.', - })} - position="top" - /> - </span> - } - > - <Controller - name="timeWindow.type" - control={control} - rules={{ required: true }} - render={({ field: { ref, ...field } }) => ( - <EuiSelect - {...field} - required - id={timeWindowTypeSelect} - data-test-subj="sloFormTimeWindowTypeSelect" - options={TIMEWINDOW_TYPE_OPTIONS} - value={field.value} - /> - )} - /> - </EuiFormRow> - </EuiFlexItem> - <EuiFlexItem> - <EuiFormRow - label={ - <span> - {i18n.translate('xpack.slo.sloEdit.timeWindowDuration.label', { - defaultMessage: 'Duration', - })}{' '} - <EuiIconTip - content={i18n.translate('xpack.slo.sloEdit.timeWindowDuration.tooltip', { - defaultMessage: 'The time window duration used to compute the SLO over.', - })} - position="top" - /> - </span> - } - > - <Controller - name="timeWindow.duration" - control={control} - rules={{ required: true }} - render={({ field: { ref, ...field } }) => ( - <EuiSelect - {...field} - required - id={timeWindowSelect} - data-test-subj="sloFormTimeWindowDurationSelect" - options={ - timeWindowType === 'calendarAligned' - ? CALENDARALIGNED_TIMEWINDOW_OPTIONS - : ROLLING_TIMEWINDOW_OPTIONS - } - value={field.value} - /> - )} - /> - </EuiFormRow> - </EuiFlexItem> - </EuiFlexGrid> - - <EuiSpacer size="l" /> - {indicator === 'sli.metric.timeslice' && ( - <EuiFlexItem> - <EuiCallOut color="warning"> - <p> - <FormattedMessage - id="xpack.slo.sloEdit.sliType.timesliceMetric.objectiveMessage" - defaultMessage="The timeslice metric requires the budgeting method to be set to 'Timeslices' due to the nature of the statistical aggregations. The 'timeslice target' is also ignored in favor of the 'threshold' set in the metric definition above. The 'timeslice window' will set the size of the window the aggregation is performed on." + <EuiFlexGroup direction="column" gutterSize="m"> + <EuiFlexGrid columns={3} gutterSize="m"> + <EuiFlexItem> + <EuiFormRow + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.timeWindowType.label', { + defaultMessage: 'Time window', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.timeWindowType.tooltip', { + defaultMessage: 'Choose between a rolling or a calendar aligned window.', + })} + position="top" + /> + </span> + } + > + <Controller + name="timeWindow.type" + control={control} + rules={{ required: true }} + render={({ field: { ref, ...field } }) => ( + <EuiSelect + {...field} + required + id={timeWindowTypeSelect} + data-test-subj="sloFormTimeWindowTypeSelect" + options={TIMEWINDOW_TYPE_OPTIONS} + value={field.value} + /> + )} /> - </p> - </EuiCallOut> - <EuiSpacer size="l" /> - </EuiFlexItem> - )} - - {indicator === 'sli.synthetics.availability' && ( - <EuiFlexItem> - <EuiCallOut color="warning"> - <p> - <FormattedMessage - id="xpack.slo.sloEdit.sliType.syntheticAvailability.objectiveMessage" - defaultMessage="The Synthetics availability indicator requires the budgeting method to be set to 'Occurrences'." + </EuiFormRow> + </EuiFlexItem> + <EuiFlexItem> + <EuiFormRow + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.timeWindowDuration.label', { + defaultMessage: 'Duration', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.timeWindowDuration.tooltip', { + defaultMessage: 'The time window duration used to compute the SLO over.', + })} + position="top" + /> + </span> + } + > + <Controller + name="timeWindow.duration" + control={control} + rules={{ required: true }} + render={({ field: { ref, ...field } }) => ( + <EuiSelect + {...field} + required + id={timeWindowSelect} + data-test-subj="sloFormTimeWindowDurationSelect" + options={ + timeWindowType === 'calendarAligned' + ? CALENDARALIGNED_TIMEWINDOW_OPTIONS + : ROLLING_TIMEWINDOW_OPTIONS + } + value={field.value} + /> + )} /> - </p> - </EuiCallOut> - <EuiSpacer size="l" /> - </EuiFlexItem> - )} + </EuiFormRow> + </EuiFlexItem> + </EuiFlexGrid> - <EuiFlexGrid columns={3}> - <EuiFlexItem> - <EuiFormRow - label={ - <span> - {i18n.translate('xpack.slo.sloEdit.budgetingMethod.label', { - defaultMessage: 'Budgeting method', - })}{' '} - <EuiIconTip - content={i18n.translate('xpack.slo.sloEdit.budgetingMethod.tooltip', { - defaultMessage: - 'Occurrences-based SLO uses the ratio of good events over the total events during the time window. Timeslices-based SLO uses the ratio of good time slices over the total time slices during the time window.', - })} - position="top" - /> - </span> - } - > - <Controller - name="budgetingMethod" - control={control} - rules={{ required: true }} - render={({ field: { ref, ...field } }) => ( - <EuiSelect - {...field} - disabled={ - indicator === 'sli.metric.timeslice' || - indicator === 'sli.synthetics.availability' - } - required - id={budgetingSelect} - data-test-subj="sloFormBudgetingMethodSelect" - options={BUDGETING_METHOD_OPTIONS} + {indicator === 'sli.metric.timeslice' && ( + <EuiFlexItem> + <EuiCallOut color="warning"> + <p> + <FormattedMessage + id="xpack.slo.sloEdit.sliType.timesliceMetric.objectiveMessage" + defaultMessage="The timeslice metric requires the budgeting method to be set to 'Timeslices' due to the nature of the statistical aggregations. The 'timeslice target' is also ignored in favor of the 'threshold' set in the metric definition above. The 'timeslice window' will set the size of the window the aggregation is performed on." /> - )} - /> - </EuiFormRow> - </EuiFlexItem> + </p> + </EuiCallOut> + </EuiFlexItem> + )} - {watch('budgetingMethod') === 'timeslices' ? ( - <SloEditFormObjectiveSectionTimeslices /> - ) : null} - </EuiFlexGrid> + {indicator === 'sli.synthetics.availability' && ( + <EuiFlexItem> + <EuiCallOut color="warning"> + <p> + <FormattedMessage + id="xpack.slo.sloEdit.sliType.syntheticAvailability.objectiveMessage" + defaultMessage="The Synthetics availability indicator requires the budgeting method to be set to 'Occurrences'." + /> + </p> + </EuiCallOut> + </EuiFlexItem> + )} - <EuiSpacer size="l" /> + <EuiFlexGrid columns={3} gutterSize="m"> + <EuiFlexItem> + <EuiFormRow + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.budgetingMethod.label', { + defaultMessage: 'Budgeting method', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.budgetingMethod.tooltip', { + defaultMessage: + 'Occurrences-based SLO uses the ratio of good events over the total events during the time window. Timeslices-based SLO uses the ratio of good time slices over the total time slices during the time window.', + })} + position="top" + /> + </span> + } + > + <Controller + name="budgetingMethod" + control={control} + rules={{ required: true }} + render={({ field: { ref, ...field } }) => ( + <EuiSelect + {...field} + disabled={ + indicator === 'sli.metric.timeslice' || + indicator === 'sli.synthetics.availability' + } + required + id={budgetingSelect} + data-test-subj="sloFormBudgetingMethodSelect" + options={BUDGETING_METHOD_OPTIONS} + /> + )} + /> + </EuiFormRow> + </EuiFlexItem> - <EuiFlexGrid columns={3}> - <EuiFlexItem> - <EuiFormRow - isInvalid={getFieldState('objective.target').invalid} - label={ - <span> - {i18n.translate('xpack.slo.sloEdit.targetSlo.label', { - defaultMessage: 'Target / SLO (%)', - })}{' '} - <EuiIconTip - content={i18n.translate('xpack.slo.sloEdit.targetSlo.tooltip', { - defaultMessage: 'The target objective in percentage for the SLO.', - })} - position="top" - /> - </span> - } - > - <Controller - name="objective.target" - control={control} - rules={{ - required: true, - min: 0.001, - max: 99.999, - }} - render={({ field: { ref, onChange, ...field }, fieldState }) => ( - <EuiFieldNumber - {...field} - required - isInvalid={fieldState.invalid} - data-test-subj="sloFormObjectiveTargetInput" - value={field.value} - min={0.001} - max={99.999} - step={0.001} - onChange={(event) => onChange(event.target.value)} - /> - )} - /> - </EuiFormRow> - </EuiFlexItem> - </EuiFlexGrid> + {watch('budgetingMethod') === 'timeslices' ? ( + <SloEditFormObjectiveSectionTimeslices /> + ) : null} + </EuiFlexGrid> - <EuiSpacer size="l" /> + <EuiFlexGrid columns={3} gutterSize="m"> + <EuiFlexItem> + <EuiFormRow + isInvalid={getFieldState('objective.target').invalid} + label={ + <span> + {i18n.translate('xpack.slo.sloEdit.targetSlo.label', { + defaultMessage: 'Target / SLO (%)', + })}{' '} + <EuiIconTip + content={i18n.translate('xpack.slo.sloEdit.targetSlo.tooltip', { + defaultMessage: 'The target objective in percentage for the SLO.', + })} + position="top" + /> + </span> + } + > + <Controller + name="objective.target" + control={control} + rules={{ + required: true, + min: 0.001, + max: 99.999, + }} + render={({ field: { ref, onChange, ...field }, fieldState }) => ( + <EuiFieldNumber + {...field} + required + isInvalid={fieldState.invalid} + data-test-subj="sloFormObjectiveTargetInput" + value={field.value} + min={0.001} + max={99.999} + step={0.001} + onChange={(event) => onChange(event.target.value)} + /> + )} + /> + </EuiFormRow> + </EuiFlexItem> + </EuiFlexGrid> - <EuiFlexGrid columns={3}> - <EuiFlexItem> - <EuiFormRow isInvalid={getFieldState('settings.preventInitialBackfill').invalid}> - <Controller - name="settings.preventInitialBackfill" - control={control} - render={({ field: { ref, onChange, ...field } }) => ( - <EuiCheckbox - id={preventBackfillCheckbox} - label={ - <span> - {i18n.translate('xpack.slo.sloEdit.settings.preventInitialBackfill.label', { - defaultMessage: 'Prevent initial backfill of data', - })} - <EuiIconTip - content={i18n.translate( - 'xpack.slo.sloEdit.settings.preventInitialBackfill.tooltip', - { - defaultMessage: - 'Start aggregating data from the time the SLO is created, instead of backfilling data from the beginning of the time window.', - } - )} - position="top" - /> - </span> - } - checked={Boolean(field.value)} - onChange={(event: any) => onChange(event.target.checked)} - /> - )} - /> - </EuiFormRow> - </EuiFlexItem> - </EuiFlexGrid> + <AdvancedSettings /> + </EuiFlexGroup> </EuiPanel> ); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts index 123ebdc66094..55dfec93f8a3 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/constants.ts @@ -33,6 +33,8 @@ import { import { SYNTHETICS_DEFAULT_GROUPINGS, SYNTHETICS_INDEX_PATTERN } from '../../../common/constants'; import { CreateSLOForm } from './types'; +export const MAX_WIDTH = 900; + export const SLI_OPTIONS: Array<{ value: IndicatorType; text: string; @@ -205,6 +207,13 @@ export const SYNTHETICS_AVAILABILITY_DEFAULT_VALUES: SyntheticsAvailabilityIndic }, }; +export const SETTINGS_DEFAULT_VALUES = { + frequency: 1, + preventInitialBackfill: false, + syncDelay: 1, + syncField: null, +}; + export const SLO_EDIT_FORM_DEFAULT_VALUES: CreateSLOForm = { name: '', description: '', @@ -219,9 +228,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES: CreateSLOForm = { target: 99, }, groupBy: ALL_VALUE, - settings: { - preventInitialBackfill: false, - }, + settings: SETTINGS_DEFAULT_VALUES, }; export const SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC: CreateSLOForm = { @@ -238,9 +245,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES_CUSTOM_METRIC: CreateSLOForm = { target: 99, }, groupBy: ALL_VALUE, - settings: { - preventInitialBackfill: false, - }, + settings: SETTINGS_DEFAULT_VALUES, }; export const SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY: CreateSLOForm = { @@ -257,9 +262,7 @@ export const SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY: CreateSLOForm target: 99, }, groupBy: SYNTHETICS_DEFAULT_GROUPINGS, - settings: { - preventInitialBackfill: false, - }, + settings: SETTINGS_DEFAULT_VALUES, }; export const COMPARATOR_GT = i18n.translate('xpack.slo.sloEdit.sliType.timesliceMetric.gtLabel', { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap index 3f7ac0ce83be..78f63a4b8f7b 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/__snapshots__/process_slo_form_values.test.ts.snap @@ -26,7 +26,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -74,7 +77,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -104,7 +110,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -146,7 +155,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -178,7 +190,10 @@ Object { "timesliceWindow": "2", }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -208,7 +223,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -218,6 +236,105 @@ Object { } `; +exports[`Transform partial URL state into form state settings handles optional 'syncField' URL state 1`] = ` +Object { + "budgetingMethod": "occurrences", + "description": "", + "groupBy": "*", + "indicator": Object { + "params": Object { + "filter": "", + "good": "", + "index": "", + "timestampField": "", + "total": "", + }, + "type": "sli.kql.custom", + }, + "name": "", + "objective": Object { + "target": 99, + }, + "settings": Object { + "frequency": 1, + "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": "override-field", + }, + "tags": Array [], + "timeWindow": Object { + "duration": "30d", + "type": "rolling", + }, +} +`; + +exports[`Transform partial URL state into form state settings handles partial 'settings' URL state 1`] = ` +Object { + "budgetingMethod": "occurrences", + "description": "", + "groupBy": "*", + "indicator": Object { + "params": Object { + "filter": "", + "good": "", + "index": "", + "timestampField": "", + "total": "", + }, + "type": "sli.kql.custom", + }, + "name": "", + "objective": Object { + "target": 99, + }, + "settings": Object { + "frequency": 1, + "preventInitialBackfill": false, + "syncDelay": 12, + "syncField": null, + }, + "tags": Array [], + "timeWindow": Object { + "duration": "30d", + "type": "rolling", + }, +} +`; + +exports[`Transform partial URL state into form state settings handles the 'settings' URL state 1`] = ` +Object { + "budgetingMethod": "occurrences", + "description": "", + "groupBy": "*", + "indicator": Object { + "params": Object { + "filter": "", + "good": "", + "index": "", + "timestampField": "", + "total": "", + }, + "type": "sli.kql.custom", + }, + "name": "", + "objective": Object { + "target": 99, + }, + "settings": Object { + "frequency": 1, + "preventInitialBackfill": true, + "syncDelay": 180, + "syncField": null, + }, + "tags": Array [], + "timeWindow": Object { + "duration": "30d", + "type": "rolling", + }, +} +`; + exports[`Transform partial URL state into form state with 'indicator' in URL state handles partial APM Availability state 1`] = ` Object { "budgetingMethod": "occurrences", @@ -239,7 +356,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -271,7 +391,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -301,7 +424,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { @@ -331,7 +457,10 @@ Object { "target": 99, }, "settings": Object { + "frequency": 1, "preventInitialBackfill": false, + "syncDelay": 1, + "syncField": null, }, "tags": Array [], "timeWindow": Object { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts index 16ad733619e6..c79571d4ab77 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/format_filters.test.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { getGroupByCardinalityFilters } from '../components/synthetics_availability/synthetics_availability_indicator_type_form'; +import { getGroupByCardinalityFilters } from '../components/indicator_section/synthetics_availability/synthetics_availability_indicator_type_form'; import { formatAllFilters } from './format_filters'; describe('formatAllFilters', () => { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts index a69cd1152985..7518e1c679c8 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { transformPartialUrlStateToFormState as transform } from './process_slo_form_values'; +import { transformPartialSLOStateToFormState as transform } from './process_slo_form_values'; describe('Transform partial URL state into form state', () => { describe("with 'indicator' in URL state", () => { @@ -121,4 +121,20 @@ describe('Transform partial URL state into form state', () => { }) ).toMatchSnapshot(); }); + + describe('settings', () => { + it("handles the 'settings' URL state", () => { + expect( + transform({ settings: { preventInitialBackfill: true, syncDelay: '3h' } }) + ).toMatchSnapshot(); + }); + + it("handles partial 'settings' URL state", () => { + expect(transform({ settings: { syncDelay: '12m' } })).toMatchSnapshot(); + }); + + it("handles optional 'syncField' URL state", () => { + expect(transform({ settings: { syncField: 'override-field' } })).toMatchSnapshot(); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts index 8bbbcf9d2fee..81d6714dac2e 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/helpers/process_slo_form_values.ts @@ -9,13 +9,14 @@ import { CreateSLOInput, GetSLOResponse, Indicator, UpdateSLOInput } from '@kbn/ import { assertNever } from '@kbn/std'; import { RecursivePartial } from '@kbn/utility-types'; import { cloneDeep } from 'lodash'; -import { toDuration } from '../../../utils/slo/duration'; +import { toDuration, toMinutes } from '../../../utils/slo/duration'; import { APM_AVAILABILITY_DEFAULT_VALUES, APM_LATENCY_DEFAULT_VALUES, CUSTOM_KQL_DEFAULT_VALUES, CUSTOM_METRIC_DEFAULT_VALUES, HISTOGRAM_DEFAULT_VALUES, + SETTINGS_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY, SYNTHETICS_AVAILABILITY_DEFAULT_VALUES, @@ -52,6 +53,13 @@ export function transformSloResponseToCreateSloForm( tags: values.tags, settings: { preventInitialBackfill: values.settings?.preventInitialBackfill ?? false, + syncDelay: values.settings?.syncDelay + ? toMinutes(toDuration(values.settings.syncDelay)) + : SETTINGS_DEFAULT_VALUES.syncDelay, + frequency: values.settings?.frequency + ? toMinutes(toDuration(values.settings.frequency)) + : SETTINGS_DEFAULT_VALUES.frequency, + syncField: values.settings?.syncField ?? null, }, }; } @@ -80,7 +88,10 @@ export function transformCreateSLOFormToCreateSLOInput(values: CreateSLOForm): C tags: values.tags, groupBy: [values.groupBy].flat(), settings: { - preventInitialBackfill: values.settings?.preventInitialBackfill ?? false, + preventInitialBackfill: values.settings.preventInitialBackfill, + syncDelay: `${values.settings.syncDelay ?? SETTINGS_DEFAULT_VALUES.syncDelay}m`, + frequency: `${values.settings.frequency ?? SETTINGS_DEFAULT_VALUES.frequency}m`, + syncField: values.settings.syncField, }, }; } @@ -109,7 +120,10 @@ export function transformValuesToUpdateSLOInput(values: CreateSLOForm): UpdateSL tags: values.tags, groupBy: [values.groupBy].flat(), settings: { - preventInitialBackfill: values.settings?.preventInitialBackfill ?? false, + preventInitialBackfill: values.settings.preventInitialBackfill, + syncDelay: `${values.settings.syncDelay ?? SETTINGS_DEFAULT_VALUES.syncDelay}m`, + frequency: `${values.settings.frequency ?? SETTINGS_DEFAULT_VALUES.frequency}m`, + syncField: values.settings.syncField, }, }; } @@ -165,7 +179,7 @@ function transformPartialIndicatorState( } } -export function transformPartialUrlStateToFormState( +export function transformPartialSLOStateToFormState( values: RecursivePartial<CreateSLOInput> ): CreateSLOForm { let state: CreateSLOForm; @@ -189,8 +203,8 @@ export function transformPartialUrlStateToFormState( if (values.description) { state.description = values.description; } - if (!!values.tags) { - state.tags = values.tags as string[]; + if (values.tags) { + state.tags = [values.tags].flat().filter((tag) => !!tag) as string[]; } if (values.objective) { @@ -220,8 +234,19 @@ export function transformPartialUrlStateToFormState( state.timeWindow = { duration: values.timeWindow.duration, type: values.timeWindow.type }; } - if (!!values.settings?.preventInitialBackfill) { - state.settings = { preventInitialBackfill: values.settings.preventInitialBackfill }; + if (!!values.settings) { + if (values.settings.preventInitialBackfill) { + state.settings.preventInitialBackfill = values.settings.preventInitialBackfill; + } + if (values.settings.syncDelay) { + state.settings.syncDelay = toMinutes(toDuration(values.settings.syncDelay)); + } + if (values.settings.frequency) { + state.settings.frequency = toMinutes(toDuration(values.settings.frequency)); + } + if (values.settings.syncField) { + state.settings.syncField = values.settings.syncField; + } } return state; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts index 2c305feda3c0..9ada81ea8438 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_parse_url_state.ts @@ -10,7 +10,7 @@ import { CreateSLOInput } from '@kbn/slo-schema'; import { RecursivePartial } from '@kbn/utility-types'; import { useHistory } from 'react-router-dom'; import { useMemo } from 'react'; -import { transformPartialUrlStateToFormState } from '../helpers/process_slo_form_values'; +import { transformPartialSLOStateToFormState } from '../helpers/process_slo_form_values'; import { CreateSLOForm } from '../types'; export function useParseUrlState(): CreateSLOForm | undefined { @@ -25,6 +25,6 @@ export function useParseUrlState(): CreateSLOForm | undefined { const urlState = urlStateStorage.get<RecursivePartial<CreateSLOInput>>('_a'); - return !!urlState ? transformPartialUrlStateToFormState(urlState) : undefined; + return !!urlState ? transformPartialSLOStateToFormState(urlState) : undefined; }, [history]); } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts index 7d75359f4cd4..94ffc92adedb 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_section_form_validation.ts @@ -220,8 +220,10 @@ export function useSectionFormValidation({ getFieldState, getValues, formState, 'objective.target', 'objective.timesliceTarget', 'objective.timesliceWindow', + 'settings.syncDelay', + 'settings.frequency', ] as const - ).every((field) => getFieldState(field).error === undefined); + ).every((field) => !getFieldState(field).invalid); const isDescriptionSectionValid = !getFieldState('name').invalid && diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts index 9d7752f19034..eb7a77f82266 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/hooks/use_unregister_fields.ts @@ -19,8 +19,8 @@ import { CUSTOM_METRIC_DEFAULT_VALUES, HISTOGRAM_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES, - TIMESLICE_METRIC_DEFAULT_VALUES, SLO_EDIT_FORM_DEFAULT_VALUES_SYNTHETICS_AVAILABILITY, + TIMESLICE_METRIC_DEFAULT_VALUES, } from '../constants'; import { CreateSLOForm } from '../types'; diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx index 98c76b190aa1..f71d7caa80d1 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/shared_flyout/slo_add_form_flyout.tsx @@ -7,12 +7,11 @@ import { EuiFlyout, EuiFlyoutBody, EuiFlyoutFooter, EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { CreateSLOInput } from '@kbn/slo-schema'; import { RecursivePartial } from '@kbn/utility-types'; -import { merge } from 'lodash'; import React from 'react'; import { OutPortal, createHtmlPortalNode } from 'react-reverse-portal'; import { SloEditForm } from '../components/slo_edit_form'; -import { CreateSLOForm } from '../types'; export const sloEditFormFooterPortal = createHtmlPortalNode(); @@ -22,7 +21,7 @@ export default function SloAddFormFlyout({ initialValues, }: { onClose: () => void; - initialValues?: RecursivePartial<CreateSLOForm>; + initialValues?: RecursivePartial<CreateSLOInput>; }) { return ( <EuiFlyout @@ -40,29 +39,7 @@ export default function SloAddFormFlyout({ </EuiTitle> </EuiFlyoutHeader> <EuiFlyoutBody> - <SloEditForm - onSave={onClose} - initialValues={ - initialValues - ? merge( - { - indicator: { - type: 'sli.kql.custom', - }, - objective: { - target: 99, - }, - timeWindow: { - duration: '30d', - type: 'rolling', - }, - budgetingMethod: 'occurrences', - }, - { ...initialValues } - ) - : undefined - } - /> + <SloEditForm onSave={onClose} initialValues={initialValues} /> </EuiFlyoutBody> <EuiFlyoutFooter> <OutPortal node={sloEditFormFooterPortal} /> diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx index abc60d6a0035..8d52ed914302 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.test.tsx @@ -423,11 +423,11 @@ describe('SLO Edit Page', () => { jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '123' }); history.push( - '/slos/123/edit?_a=(name:%27updated-name%27,indicator:(params:(environment:prod,service:cartService),type:sli.apm.transactionDuration),objective:(target:0.92))' + '/slos/edit/123?_a=(name:%27updated-name%27,indicator:(params:(environment:prod,service:cartService),type:sli.apm.transactionDuration),objective:(target:0.92))' ); jest .spyOn(Router, 'useLocation') - .mockReturnValue({ pathname: '/slos/123/edit', search: '', state: '', hash: '' }); + .mockReturnValue({ pathname: '/slos/edit/123', search: '', state: '', hash: '' }); useFetchSloMock.mockReturnValue({ isLoading: false, data: slo }); @@ -463,8 +463,7 @@ describe('SLO Edit Page', () => { jest.spyOn(Router, 'useParams').mockReturnValue({ sloId: '123' }); jest .spyOn(Router, 'useLocation') - .mockReturnValue({ pathname: '/slos/123/edit', search: '', state: '', hash: '' }); - + .mockReturnValue({ pathname: '/slos/edit/123', search: '', state: '', hash: '' }); useFetchSloMock.mockReturnValue({ isLoading: false, data: slo }); const { getByTestId } = render(<SloEditPage />); diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx index b014bdb1d6de..0a563bbe75b4 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/slo_edit.tsx @@ -12,10 +12,10 @@ import { useParams } from 'react-router-dom'; import { paths } from '../../../common/locators/paths'; import { HeaderMenu } from '../../components/header_menu/header_menu'; import { useFetchSloDetails } from '../../hooks/use_fetch_slo_details'; +import { useKibana } from '../../hooks/use_kibana'; import { useLicense } from '../../hooks/use_license'; import { usePermissions } from '../../hooks/use_permissions'; import { usePluginContext } from '../../hooks/use_plugin_context'; -import { useKibana } from '../../hooks/use_kibana'; import { SloEditForm } from './components/slo_edit_form'; export function SloEditPage() { diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts index 5eef9a2d0e5b..6584e52404bc 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts +++ b/x-pack/plugins/observability_solution/slo/public/pages/slo_edit/types.ts @@ -25,5 +25,8 @@ export interface CreateSLOForm<IndicatorType = Indicator> { groupBy: string[] | string; settings: { preventInitialBackfill: boolean; + syncDelay: number; // in minutes + frequency: number; // in minutes + syncField: string | null; }; } diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/overview_item.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/overview_item.tsx index d26eea29f996..f7953854b217 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/overview_item.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/overview_item.tsx @@ -9,7 +9,7 @@ import { EuiFlexItem, EuiStat, EuiToolTip } from '@elastic/eui'; import React from 'react'; import { useUrlSearchState } from '../../hooks/use_url_search_state'; -export function OverViewItem({ +export function OverviewItem({ title, description, titleColor, diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slo_overview_alerts.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slo_overview_alerts.tsx index 9fba8b59bef4..1edfba0fffb4 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slo_overview_alerts.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slo_overview_alerts.tsx @@ -12,7 +12,7 @@ import { GetOverviewResponse } from '@kbn/slo-schema/src/rest_specs/routes/get_o import { rulesLocatorID, RulesParams } from '@kbn/observability-plugin/public'; import { useAlertsUrl } from '../../../../hooks/use_alerts_url'; import { useKibana } from '../../../../hooks/use_kibana'; -import { OverViewItem } from './overview_item'; +import { OverviewItem } from './overview_item'; export function SLOOverviewAlerts({ data, @@ -55,7 +55,7 @@ export function SLOOverviewAlerts({ <EuiSpacer size="xs" /> <EuiFlexGroup justifyContent="spaceBetween"> - <OverViewItem + <OverviewItem title={data?.burnRateActiveAlerts} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.burnRateActiveAlerts', { defaultMessage: 'Active alerts', @@ -66,7 +66,7 @@ export function SLOOverviewAlerts({ application.navigateToUrl(getAlertsUrl('active')); }} /> - <OverViewItem + <OverviewItem title={data?.burnRateRecoveredAlerts} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.burnRateRecoveredAlerts', { defaultMessage: 'Recovered alerts', @@ -77,7 +77,7 @@ export function SLOOverviewAlerts({ application.navigateToUrl(getAlertsUrl('recovered')); }} /> - <OverViewItem + <OverviewItem title={data?.burnRateRules} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.burnRateRules', { defaultMessage: 'Rules', diff --git a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx index 42c0d199db78..49e9e6e34e0d 100644 --- a/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx +++ b/x-pack/plugins/observability_solution/slo/public/pages/slos/components/slos_overview/slos_overview.tsx @@ -20,7 +20,7 @@ import { SLOOverviewAlerts } from './slo_overview_alerts'; import { useGetSettings } from '../../../slo_settings/hooks/use_get_settings'; import { useFetchSLOsOverview } from '../../hooks/use_fetch_slos_overview'; import { useUrlSearchState } from '../../hooks/use_url_search_state'; -import { OverViewItem } from './overview_item'; +import { OverviewItem } from './overview_item'; export function SLOsOverview() { const { state } = useUrlSearchState(); @@ -50,7 +50,7 @@ export function SLOsOverview() { </EuiTitle> <EuiSpacer size="xs" /> <EuiFlexGroup gutterSize="xl" justifyContent="spaceBetween"> - <OverViewItem + <OverviewItem title={data?.healthy} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.healthyLabel', { defaultMessage: 'Healthy', @@ -62,7 +62,7 @@ export function SLOsOverview() { defaultMessage: 'Click to filter SLOs by Healthy status.', })} /> - <OverViewItem + <OverviewItem title={data?.violated} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.violatedLabel', { defaultMessage: 'Violated', @@ -74,7 +74,7 @@ export function SLOsOverview() { defaultMessage: 'Click to filter SLOs by Violated status.', })} /> - <OverViewItem + <OverviewItem title={data?.noData} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.noDataLabel', { defaultMessage: 'No data', @@ -86,7 +86,7 @@ export function SLOsOverview() { defaultMessage: 'Click to filter SLOs by no data status.', })} /> - <OverViewItem + <OverviewItem title={data?.degrading} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.degradingLabel', { defaultMessage: 'Degrading', @@ -98,7 +98,7 @@ export function SLOsOverview() { })} titleColor={theme.colors.warningText} /> - <OverViewItem + <OverviewItem title={data?.stale} description={i18n.translate('xpack.slo.sLOsOverview.euiStat.staleLabel', { defaultMessage: 'Stale', diff --git a/x-pack/plugins/observability_solution/slo/public/types.ts b/x-pack/plugins/observability_solution/slo/public/types.ts index 1397b08a2952..964fb9b289ea 100644 --- a/x-pack/plugins/observability_solution/slo/public/types.ts +++ b/x-pack/plugins/observability_solution/slo/public/types.ts @@ -47,6 +47,7 @@ import type { UsageCollectionSetup, UsageCollectionStart, } from '@kbn/usage-collection-plugin/public'; +import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin-types-public'; import type { SLORouteRepository } from '../server/routes/get_slo_server_route_repository'; import { SLOPlugin } from './plugin'; @@ -65,6 +66,7 @@ export interface SLOPublicPluginsSetup { triggersActionsUi: TriggersAndActionsUIPublicPluginSetup; uiActions: UiActionsSetup; usageCollection: UsageCollectionSetup; + security?: SecurityPluginSetup; } export interface SLOPublicPluginsStart { @@ -94,6 +96,7 @@ export interface SLOPublicPluginsStart { uiActions: UiActionsStart; unifiedSearch: UnifiedSearchPublicPluginStart; usageCollection: UsageCollectionStart; + security?: SecurityPluginStart; } export type SLOPublicSetup = ReturnType<SLOPlugin['setup']>; diff --git a/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts b/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts index 3c0495fd1bc9..6f44d1315081 100644 --- a/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts +++ b/x-pack/plugins/observability_solution/slo/public/utils/slo/remote_slo_urls.test.ts @@ -51,7 +51,7 @@ describe('remote SLO URLs Utils', () => { `"https://cloud.elast.co/app/slos/edit/fixed-id"` ); expect(createRemoteSloCloneUrl(remoteSlo)).toMatchInlineSnapshot( - `"https://cloud.elast.co/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` + `"https://cloud.elast.co/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(dataViewId:some-data-view-id,filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` ); }); @@ -71,7 +71,7 @@ describe('remote SLO URLs Utils', () => { `"https://cloud.elast.co/s/my-custom-space/app/slos/edit/fixed-id"` ); expect(createRemoteSloCloneUrl(remoteSlo, 'my-custom-space')).toMatchInlineSnapshot( - `"https://cloud.elast.co/s/my-custom-space/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` + `"https://cloud.elast.co/s/my-custom-space/app/slos/create?_a=(budgetingMethod:occurrences,createdAt:%272022-12-29T10:11:12.000Z%27,description:%27some%20description%20useful%27,enabled:!t,groupBy:%27*%27,groupings:(),indicator:(params:(dataViewId:some-data-view-id,filter:%27baz:%20foo%20and%20bar%20%3E%202%27,good:%27http_status:%202xx%27,index:some-index,timestampField:custom_timestamp,total:%27a%20query%27),type:sli.kql.custom),instanceId:%27*%27,meta:(),name:%27[Copy]%20super%20important%20level%20service%27,objective:(target:0.98),remote:(kibanaUrl:%27https:/cloud.elast.co/kibana%27,remoteName:remote_cluster),revision:1,settings:(frequency:%271m%27,preventInitialBackfill:!f,syncDelay:%271m%27),summary:(errorBudget:(consumed:0.064,initial:0.02,isEstimated:!f,remaining:0.936),fiveMinuteBurnRate:0,oneDayBurnRate:0,oneHourBurnRate:0,sliValue:0.99872,status:HEALTHY),tags:!(k8s,production,critical),timeWindow:(duration:%2730d%27,type:rolling),updatedAt:%272022-12-29T10:11:12.000Z%27,version:2)"` ); }); }); diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts index d432dc5c52d3..ace1a1318ce2 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/register_burn_rate_rule.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import { IBasePath, Logger } from '@kbn/core/server'; import { IRuleDataService } from '@kbn/rule-registry-plugin/server'; import { CustomThresholdLocators } from '@kbn/observability-plugin/server'; import { sloBurnRateRuleType } from './slo_burn_rate'; export function registerBurnRateRule( - alertingPlugin: PluginSetupContract, + alertingPlugin: AlertingServerSetup, basePath: IBasePath, logger: Logger, ruleDataService: IRuleDataService, diff --git a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts index 6b6c85f9120f..e5c07b797677 100644 --- a/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/lib/rules/slo_burn_rate/executor.test.ts @@ -204,6 +204,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }) ).rejects.toThrowError(); }); @@ -226,6 +227,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(esClientMock.search).not.toHaveBeenCalled(); @@ -276,6 +278,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).not.toBeCalled(); @@ -323,6 +326,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).not.toBeCalled(); @@ -382,6 +386,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).toBeCalledWith({ @@ -531,6 +536,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient?.report).toBeCalledWith({ @@ -651,6 +657,7 @@ describe('BurnRateRuleExecutor', () => { state: {}, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(servicesMock.alertsClient!.report).toBeCalledWith({ diff --git a/x-pack/plugins/observability_solution/slo/server/plugin.ts b/x-pack/plugins/observability_solution/slo/server/plugin.ts index 7699cbe5f140..99cd4a2230a9 100644 --- a/x-pack/plugins/observability_solution/slo/server/plugin.ts +++ b/x-pack/plugins/observability_solution/slo/server/plugin.ts @@ -14,10 +14,11 @@ import { PluginInitializerContext, SavedObjectsClient, } from '@kbn/core/server'; -import { KibanaFeatureScope } from '@kbn/features-plugin/common'; -import { i18n } from '@kbn/i18n'; import { AlertsLocatorDefinition, sloFeatureId } from '@kbn/observability-plugin/common'; import { SLO_BURN_RATE_RULE_TYPE_ID } from '@kbn/rule-data-utils'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; +import { KibanaFeatureScope } from '@kbn/features-plugin/common'; +import { i18n } from '@kbn/i18n'; import { mapValues } from 'lodash'; import { registerSloUsageCollector } from './lib/collectors/register'; import { registerBurnRateRule } from './lib/rules/register_burn_rate_rule'; @@ -61,6 +62,11 @@ export class SLOPlugin const savedObjectTypes = [SO_SLO_TYPE, SO_SLO_SETTINGS_TYPE]; + const alertingFeatures = sloRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [sloFeatureId, ALERTING_FEATURE_ID], + })); + plugins.features.registerKibanaFeature({ id: sloFeatureId, name: i18n.translate('xpack.slo.featureRegistry.linkSloTitle', { @@ -71,7 +77,7 @@ export class SLOPlugin scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security], app: [sloFeatureId, 'kibana'], catalogue: [sloFeatureId, 'observability'], - alerting: sloRuleTypes, + alerting: alertingFeatures, privileges: { all: { app: [sloFeatureId, 'kibana'], @@ -83,10 +89,10 @@ export class SLOPlugin }, alerting: { rule: { - all: sloRuleTypes, + all: alertingFeatures, }, alert: { - all: sloRuleTypes, + all: alertingFeatures, }, }, ui: ['read', 'write'], @@ -101,10 +107,10 @@ export class SLOPlugin }, alerting: { rule: { - read: sloRuleTypes, + read: alertingFeatures, }, alert: { - read: sloRuleTypes, + read: alertingFeatures, }, }, ui: ['read'], diff --git a/x-pack/plugins/observability_solution/slo/server/routes/register_routes.ts b/x-pack/plugins/observability_solution/slo/server/routes/register_routes.ts index 6e3c02a5b921..ee58618add23 100644 --- a/x-pack/plugins/observability_solution/slo/server/routes/register_routes.ts +++ b/x-pack/plugins/observability_solution/slo/server/routes/register_routes.ts @@ -6,12 +6,11 @@ */ import { CoreSetup, Logger } from '@kbn/core/server'; import { ServerRoute, registerRoutes } from '@kbn/server-route-repository'; -import { ServerRouteCreateOptions } from '@kbn/server-route-repository-utils'; import { SLORequestHandlerContext, SLORoutesDependencies } from './types'; interface RegisterRoutes { core: CoreSetup; - repository: Record<string, ServerRoute<string, any, any, any, ServerRouteCreateOptions>>; + repository: Record<string, ServerRoute<string, any, any, any, any>>; logger: Logger; dependencies: SLORoutesDependencies; isServerless: boolean; diff --git a/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts b/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts index 2081f38df552..ed2542bb67cb 100644 --- a/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts +++ b/x-pack/plugins/observability_solution/slo/server/routes/slo/route.ts @@ -79,9 +79,11 @@ const getSpaceId = async (plugins: SLORoutesDependencies['plugins'], request: Ki const createSLORoute = createSloServerRoute({ endpoint: 'POST /api/observability/slos 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: createSLOParamsSchema, handler: async ({ context, response, params, logger, request, plugins, corePlugins }) => { @@ -134,9 +136,11 @@ const createSLORoute = createSloServerRoute({ const inspectSLORoute = createSloServerRoute({ endpoint: 'POST /internal/observability/slos/_inspect', - options: { - tags: ['access:slo_write'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: createSLOParamsSchema, handler: async ({ context, params, logger, request, plugins, corePlugins }) => { @@ -186,9 +190,11 @@ const inspectSLORoute = createSloServerRoute({ const updateSLORoute = createSloServerRoute({ endpoint: 'PUT /api/observability/slos/{id} 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: updateSLOParamsSchema, handler: async ({ context, request, params, logger, plugins, corePlugins }) => { @@ -239,9 +245,11 @@ const updateSLORoute = createSloServerRoute({ const deleteSLORoute = createSloServerRoute({ endpoint: 'DELETE /api/observability/slos/{id} 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: deleteSLOParamsSchema, handler: async ({ request, response, context, params, logger, plugins }) => { @@ -295,9 +303,11 @@ const deleteSLORoute = createSloServerRoute({ const getSLORoute = createSloServerRoute({ endpoint: 'GET /api/observability/slos/{id} 2023-10-31', - options: { - tags: ['access:slo_read'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: getSLOParamsSchema, handler: async ({ request, context, params, logger, plugins }) => { @@ -321,9 +331,11 @@ const getSLORoute = createSloServerRoute({ const enableSLORoute = createSloServerRoute({ endpoint: 'POST /api/observability/slos/{id}/enable 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: manageSLOParamsSchema, handler: async ({ request, response, context, params, logger, plugins }) => { @@ -366,9 +378,11 @@ const enableSLORoute = createSloServerRoute({ const disableSLORoute = createSloServerRoute({ endpoint: 'POST /api/observability/slos/{id}/disable 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: manageSLOParamsSchema, handler: async ({ response, request, context, params, logger, plugins }) => { @@ -410,9 +424,11 @@ const disableSLORoute = createSloServerRoute({ const resetSLORoute = createSloServerRoute({ endpoint: 'POST /api/observability/slos/{id}/_reset 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: resetSLOParamsSchema, handler: async ({ context, request, params, logger, plugins, corePlugins }) => { @@ -463,9 +479,11 @@ const resetSLORoute = createSloServerRoute({ const findSLORoute = createSloServerRoute({ endpoint: 'GET /api/observability/slos 2023-10-31', - options: { - tags: ['access:slo_read'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: findSLOParamsSchema, handler: async ({ context, request, params, logger, plugins }) => { @@ -485,9 +503,11 @@ const findSLORoute = createSloServerRoute({ const findSLOGroupsRoute = createSloServerRoute({ endpoint: 'GET /internal/observability/slos/_groups', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: findSLOGroupsParamsSchema, handler: async ({ context, request, params, logger, plugins }) => { @@ -504,9 +524,11 @@ const findSLOGroupsRoute = createSloServerRoute({ const getSLOSuggestionsRoute = createSloServerRoute({ endpoint: 'GET /internal/observability/slos/suggestions', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, handler: async ({ context, plugins }) => { await assertPlatinumLicense(plugins); @@ -519,9 +541,11 @@ const getSLOSuggestionsRoute = createSloServerRoute({ const deleteSloInstancesRoute = createSloServerRoute({ endpoint: 'POST /api/observability/slos/_delete_instances 2023-10-31', - options: { - tags: ['access:slo_write'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: deleteSLOInstancesParamsSchema, handler: async ({ response, context, params, plugins }) => { @@ -537,9 +561,11 @@ const deleteSloInstancesRoute = createSloServerRoute({ const findSloDefinitionsRoute = createSloServerRoute({ endpoint: 'GET /api/observability/slos/_definitions 2023-10-31', - options: { - tags: ['access:slo_read'], - access: 'public', + options: { access: 'public' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: findSloDefinitionsParamsSchema, handler: async ({ context, params, logger, plugins }) => { @@ -555,9 +581,11 @@ const findSloDefinitionsRoute = createSloServerRoute({ const fetchHistoricalSummary = createSloServerRoute({ endpoint: 'POST /internal/observability/slos/_historical_summary', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: fetchHistoricalSummaryParamsSchema, handler: async ({ context, params, plugins }) => { @@ -572,9 +600,11 @@ const fetchHistoricalSummary = createSloServerRoute({ const getSLOInstancesRoute = createSloServerRoute({ endpoint: 'GET /internal/observability/slos/{id}/_instances', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: getSLOInstancesParamsSchema, handler: async ({ context, params, logger, plugins }) => { @@ -591,9 +621,12 @@ const getSLOInstancesRoute = createSloServerRoute({ const getDiagnosisRoute = createSloServerRoute({ endpoint: 'GET /internal/observability/slos/_diagnosis', - options: { - tags: [], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + enabled: false, + reason: 'The endpoint is used to diagnose SLOs and does not require any specific privileges.', + }, }, params: undefined, handler: async ({ context, plugins }) => { @@ -614,9 +647,11 @@ const getDiagnosisRoute = createSloServerRoute({ const fetchSloHealthRoute = createSloServerRoute({ endpoint: 'POST /internal/observability/slos/_health', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: fetchSLOHealthParamsSchema, handler: async ({ context, params, logger, plugins }) => { @@ -636,9 +671,11 @@ const fetchSloHealthRoute = createSloServerRoute({ const getSloBurnRates = createSloServerRoute({ endpoint: 'POST /internal/observability/slos/{id}/_burn_rates', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: getSLOBurnRatesParamsSchema, handler: async ({ request, context, params, logger, plugins }) => { @@ -669,9 +706,11 @@ const getSloBurnRates = createSloServerRoute({ const getPreviewData = createSloServerRoute({ endpoint: 'POST /internal/observability/slos/_preview', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: getPreviewDataParamsSchema, handler: async ({ request, context, params, plugins }) => { @@ -690,9 +729,11 @@ const getPreviewData = createSloServerRoute({ const getSloSettingsRoute = createSloServerRoute({ endpoint: 'GET /internal/slo/settings', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, handler: async ({ context, plugins }) => { await assertPlatinumLicense(plugins); @@ -706,9 +747,11 @@ const getSloSettingsRoute = createSloServerRoute({ const putSloSettings = (isServerless?: boolean) => createSloServerRoute({ endpoint: 'PUT /internal/slo/settings', - options: { - tags: ['access:slo_write'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_write'], + }, }, params: isServerless ? putSLOServerlessSettingsParamsSchema : putSLOSettingsParamsSchema, handler: async ({ context, params, plugins }) => { @@ -723,9 +766,11 @@ const putSloSettings = (isServerless?: boolean) => const getSLOsOverview = createSloServerRoute({ endpoint: 'GET /internal/observability/slos/overview', - options: { - tags: ['access:slo_read'], - access: 'internal', + options: { access: 'internal' }, + security: { + authz: { + requiredPrivileges: ['slo_read'], + }, }, params: getOverviewParamsSchema, handler: async ({ context, params, request, logger, plugins }) => { diff --git a/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts index e7c09c352bd6..a8e01fb4681f 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/create_slo.ts @@ -9,6 +9,7 @@ import { TransformPutTransformRequest } from '@elastic/elasticsearch/lib/api/typ import { ElasticsearchClient, IBasePath, IScopedClusterClient, Logger } from '@kbn/core/server'; import { ALL_VALUE, CreateSLOParams, CreateSLOResponse } from '@kbn/slo-schema'; import { asyncForEach } from '@kbn/std'; +import { merge } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; import { SLO_MODEL_VERSION, @@ -46,8 +47,10 @@ export class CreateSLO { const slo = this.toSLO(params); validateSLO(slo); - await this.assertSLOInexistant(slo); - await assertExpectedIndicatorSourceIndexPrivileges(slo, this.esClient); + await Promise.all([ + this.assertSLOInexistant(slo), + assertExpectedIndicatorSourceIndexPrivileges(slo, this.esClient), + ]); const rollbackOperations = []; const createPromise = this.repository.create(slo); @@ -201,11 +204,14 @@ export class CreateSLO { return { ...params, id: params.id ?? uuidv4(), - settings: { - syncDelay: params.settings?.syncDelay ?? new Duration(1, DurationUnit.Minute), - frequency: params.settings?.frequency ?? new Duration(1, DurationUnit.Minute), - preventInitialBackfill: params.settings?.preventInitialBackfill ?? false, - }, + settings: merge( + { + syncDelay: new Duration(1, DurationUnit.Minute), + frequency: new Duration(1, DurationUnit.Minute), + preventInitialBackfill: false, + }, + params.settings + ), revision: params.revision ?? 1, enabled: true, tags: params.tags ?? [], diff --git a/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts b/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts index 2c1ff46f57ef..fb2be7bcbf74 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/get_slos_overview.ts @@ -15,7 +15,7 @@ import { import { RulesClientApi } from '@kbn/alerting-plugin/server/types'; import { AlertsClient } from '@kbn/rule-registry-plugin/server'; import moment from 'moment'; -import { observabilityAlertFeatureIds } from '@kbn/observability-plugin/common'; +import { AlertConsumers, SLO_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { typedSearch } from '../utils/queries'; import { getElasticsearchQueryOrThrow, parseStringFilters } from './transform_generators'; import { getListOfSummaryIndices, getSloSettings } from './slo_settings'; @@ -53,19 +53,6 @@ export class GetSLOsOverview { }, body: { aggs: { - worst: { - top_hits: { - sort: { - errorBudgetRemaining: { - order: 'asc', - }, - }, - _source: { - includes: ['sliValue', 'status', 'slo.id', 'slo.instanceId', 'slo.name'], - }, - size: 1, - }, - }, stale: { filter: { range: { @@ -75,31 +62,42 @@ export class GetSLOsOverview { }, }, }, - violated: { + not_stale: { filter: { - term: { - status: 'VIOLATED', + range: { + summaryUpdatedAt: { + gte: `now-${settings.staleThresholdInHours}h`, + }, }, }, - }, - healthy: { - filter: { - term: { - status: 'HEALTHY', + aggs: { + violated: { + filter: { + term: { + status: 'VIOLATED', + }, + }, }, - }, - }, - degrading: { - filter: { - term: { - status: 'DEGRADING', + healthy: { + filter: { + term: { + status: 'HEALTHY', + }, + }, }, - }, - }, - noData: { - filter: { - term: { - status: 'NO_DATA', + degrading: { + filter: { + term: { + status: 'DEGRADING', + }, + }, + }, + noData: { + filter: { + term: { + status: 'NO_DATA', + }, + }, }, }, }, @@ -110,36 +108,27 @@ export class GetSLOsOverview { const [rules, alerts] = await Promise.all([ this.rulesClient.find({ options: { - search: 'alert.attributes.alertTypeId:("slo.rules.burnRate")', + ruleTypeIds: SLO_RULE_TYPE_IDS, + consumers: [AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], }, }), this.racClient.getAlertSummary({ - featureIds: observabilityAlertFeatureIds, + ruleTypeIds: SLO_RULE_TYPE_IDS, + consumers: [AlertConsumers.SLO, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], gte: moment().subtract(24, 'hours').toISOString(), lte: moment().toISOString(), - filter: [ - { - term: { - 'kibana.alert.rule.rule_type_id': 'slo.rules.burnRate', - }, - }, - ], }), ]); const aggs = response.aggregations; return { - violated: aggs?.violated.doc_count ?? 0, - degrading: aggs?.degrading.doc_count ?? 0, - healthy: aggs?.healthy.doc_count ?? 0, - noData: aggs?.noData.doc_count ?? 0, + violated: aggs?.not_stale?.violated.doc_count ?? 0, + degrading: aggs?.not_stale?.degrading.doc_count ?? 0, + healthy: aggs?.not_stale?.healthy?.doc_count ?? 0, + noData: aggs?.not_stale?.noData.doc_count ?? 0, stale: aggs?.stale.doc_count ?? 0, - worst: { - value: 0, - id: 'id', - }, burnRateRules: rules.total, burnRateActiveAlerts: alerts.activeAlertCount, burnRateRecoveredAlerts: alerts.recoveredAlertCount, diff --git a/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts b/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts index 4f9cf439e8ed..afbdb999fc06 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/slo_repository.ts @@ -9,6 +9,7 @@ import { SavedObjectsClientContract } from '@kbn/core-saved-objects-api-server'; import { Logger } from '@kbn/core/server'; import { ALL_VALUE, Paginated, Pagination, sloDefinitionSchema } from '@kbn/slo-schema'; import { isLeft } from 'fp-ts/lib/Either'; +import { merge } from 'lodash'; import { SLO_MODEL_VERSION } from '../../common/constants'; import { SLODefinition, StoredSLODefinition } from '../domain/models'; import { SLONotFound } from '../errors'; @@ -155,10 +156,10 @@ export class KibanaSavedObjectsSLORepository implements SLORepository { // We would need to call the _reset api on this SLO. version: storedSLO.version ?? 1, // settings.preventInitialBackfill was added in 8.15.0 - settings: { - ...storedSLO.settings, - preventInitialBackfill: storedSLO.settings?.preventInitialBackfill ?? false, - }, + settings: merge( + { preventInitialBackfill: false, syncDelay: '1m', frequency: '1m' }, + storedSLO.settings + ), }); if (isLeft(result)) { diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap index 7d8e989c1140..f49785cf936c 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/__snapshots__/transform_generator.test.ts.snap @@ -63,3 +63,11 @@ Object { }, } `; + +exports[`Transform Generator settings builds the transform settings 1`] = ` +Object { + "frequency": "2m", + "sync_delay": "10m", + "sync_field": "my_timestamp_sync_field", +} +`; diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts index d1f05605dab3..99361fa77678 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_duration.ts @@ -42,7 +42,7 @@ export class ApmTransactionDurationTransformGenerator extends TransformGenerator this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo, slo.indicator), - this.buildSettings(slo), + this.buildSettings(slo, '@timestamp'), slo ); } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts index 6adbd1d3eae9..a65e4ae1d50d 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/apm_transaction_error_rate.ts @@ -41,7 +41,7 @@ export class ApmTransactionErrorRateTransformGenerator extends TransformGenerato this.buildDestination(slo), this.buildGroupBy(slo, slo.indicator), this.buildAggregations(slo), - this.buildSettings(slo), + this.buildSettings(slo, '@timestamp'), slo ); } diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts index e70d406d7539..2df8a1e40eeb 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.test.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { Duration, DurationUnit } from '../../domain/models'; import { createAPMTransactionErrorRateIndicator, createSLO } from '../fixtures/slo'; import { ApmTransactionErrorRateTransformGenerator } from './apm_transaction_error_rate'; import { dataViewsService } from '@kbn/data-views-plugin/server/mocks'; @@ -45,4 +46,46 @@ describe('Transform Generator', () => { expect(runtimeMappings).toEqual({}); }); }); + + describe('settings', () => { + const defaultSettings = { + syncDelay: new Duration(10, DurationUnit.Minute), + frequency: new Duration(2, DurationUnit.Minute), + preventInitialBackfill: true, + }; + + it('builds the transform settings', async () => { + const slo = createSLO({ + settings: { + ...defaultSettings, + syncField: 'my_timestamp_sync_field', + }, + }); + const settings = generator.buildSettings(slo); + expect(settings).toMatchSnapshot(); + }); + + it('builds the transform settings using the provided settings.syncField', async () => { + const slo = createSLO({ + settings: { + ...defaultSettings, + syncField: 'my_timestamp_sync_field', + }, + }); + const settings = generator.buildSettings(slo, '@timestamp'); + expect(settings.sync_field).toEqual('my_timestamp_sync_field'); + }); + + it('builds the transform settings using provided fallback when no settings.syncField is configured', async () => { + const slo = createSLO({ settings: defaultSettings }); + const settings = generator.buildSettings(slo, '@timestamp2'); + expect(settings.sync_field).toEqual('@timestamp2'); + }); + + it("builds the transform settings using '@timestamp' default fallback when no settings.syncField is configured", async () => { + const slo = createSLO({ settings: defaultSettings }); + const settings = generator.buildSettings(slo); + expect(settings.sync_field).toEqual('@timestamp'); + }); + }); }); diff --git a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts index 6c44471fd656..ea27ebbc7aa3 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/transform_generators/transform_generator.ts @@ -88,8 +88,9 @@ export abstract class TransformGenerator { ): TransformSettings { return { frequency: slo.settings.frequency.format(), - sync_field: sourceIndexTimestampField, // timestamp field defined in the source index sync_delay: slo.settings.syncDelay.format(), + // 8.17: use settings.syncField if truthy or default to sourceIndexTimestampField which is the indicator timestampField + sync_field: !!slo.settings.syncField ? slo.settings.syncField : sourceIndexTimestampField, }; } } diff --git a/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts b/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts index d1dfb2e70e00..402ca82acecd 100644 --- a/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts +++ b/x-pack/plugins/observability_solution/slo/server/services/update_slo.ts @@ -43,9 +43,10 @@ export class UpdateSLO { public async execute(sloId: string, params: UpdateSLOParams): Promise<UpdateSLOResponse> { const originalSlo = await this.repository.findById(sloId); - let updatedSlo: SLODefinition = Object.assign({}, originalSlo, params, { + let updatedSlo: SLODefinition = Object.assign({}, originalSlo, { + ...params, groupBy: !!params.groupBy ? params.groupBy : originalSlo.groupBy, - settings: mergePartialSettings(originalSlo.settings, params.settings), + settings: Object.assign({}, originalSlo.settings, params.settings), }); if (isEqual(originalSlo, updatedSlo)) { @@ -263,13 +264,3 @@ export class UpdateSLO { return updateSLOResponseSchema.encode(slo); } } - -/** - * Settings are merged by overwriting the original settings with the optional new partial settings. - */ -function mergePartialSettings( - originalSettings: SLODefinition['settings'], - newPartialSettings: UpdateSLOParams['settings'] -) { - return Object.assign({}, originalSettings, newPartialSettings); -} diff --git a/x-pack/plugins/observability_solution/slo/server/types.ts b/x-pack/plugins/observability_solution/slo/server/types.ts index b9269f49c4d9..9a4054782018 100644 --- a/x-pack/plugins/observability_solution/slo/server/types.ts +++ b/x-pack/plugins/observability_solution/slo/server/types.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PluginSetupContract, PluginStartContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { CloudSetup } from '@kbn/cloud-plugin/server'; import { DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; @@ -31,7 +31,7 @@ export interface SLOServerSetup {} export interface SLOServerStart {} export interface SLOPluginSetupDependencies { - alerting: PluginSetupContract; + alerting: AlertingServerSetup; ruleRegistry: RuleRegistryPluginSetupContract; share: SharePluginSetup; features: FeaturesPluginSetup; @@ -44,7 +44,7 @@ export interface SLOPluginSetupDependencies { } export interface SLOPluginStartDependencies { - alerting: PluginStartContract; + alerting: AlertingServerStart; taskManager: TaskManagerStartContract; spaces?: SpacesPluginStart; ruleRegistry: RuleRegistryPluginStartContract; diff --git a/x-pack/plugins/observability_solution/slo/tsconfig.json b/x-pack/plugins/observability_solution/slo/tsconfig.json index 02a2ea06cc52..3b01431c3fb4 100644 --- a/x-pack/plugins/observability_solution/slo/tsconfig.json +++ b/x-pack/plugins/observability_solution/slo/tsconfig.json @@ -99,6 +99,6 @@ "@kbn/observability-alerting-rule-utils", "@kbn/discover-shared-plugin", "@kbn/server-route-repository-client", - "@kbn/server-route-repository-utils" + "@kbn/security-plugin-types-public", ] } diff --git a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts index 4f525bda1756..8a5812f46c6c 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics_alerts.ts @@ -8,6 +8,8 @@ import type { ActionGroup } from '@kbn/alerting-plugin/common'; import { i18n } from '@kbn/i18n'; +export { SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE } from '@kbn/rule-data-utils'; + export type MonitorStatusActionGroup = | ActionGroup<'xpack.synthetics.alerts.actionGroups.monitorStatus'> | ActionGroup<'xpack.synthetics.alerts.actionGroups.tls'>; @@ -34,14 +36,6 @@ export const ACTION_GROUP_DEFINITIONS: { TLS_CERTIFICATE, }; -export const SYNTHETICS_STATUS_RULE = 'xpack.synthetics.alerts.monitorStatus'; -export const SYNTHETICS_TLS_RULE = 'xpack.synthetics.alerts.tls'; - -export const SYNTHETICS_ALERT_RULE_TYPES = { - MONITOR_STATUS: SYNTHETICS_STATUS_RULE, - TLS: SYNTHETICS_TLS_RULE, -}; - -export const SYNTHETICS_RULE_TYPES = [SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE]; - export const SYNTHETICS_RULE_TYPES_ALERT_CONTEXT = 'observability.uptime'; + +export { SYNTHETICS_RULE_TYPE_IDS as SYNTHETICS_RULE_TYPES } from '@kbn/rule-data-utils'; diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts index dd7ad03b9ac3..3bb2c9a4f5ae 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.test.ts @@ -291,4 +291,77 @@ describe('Alert Actions factory', () => { }, ]); }); + + it('generate expected action for email opsgenie connector', async () => { + const resp = populateAlertActions({ + groupId: SYNTHETICS_MONITOR_STATUS.id, + defaultActions: [ + { + frequency: { + notifyWhen: 'onActionGroupChange', + summary: false, + throttle: null, + }, + actionTypeId: '.opsgenie', + group: 'xpack.synthetics.alerts.actionGroups.monitorStatus', + params: {}, + id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9', + }, + ] as unknown as ActionConnector[], + defaultEmail: { + to: ['test@email.com'], + }, + translations: { + defaultActionMessage: SyntheticsMonitorStatusTranslations.defaultActionMessage, + defaultRecoveryMessage: SyntheticsMonitorStatusTranslations.defaultRecoveryMessage, + defaultSubjectMessage: SyntheticsMonitorStatusTranslations.defaultSubjectMessage, + defaultRecoverySubjectMessage: + SyntheticsMonitorStatusTranslations.defaultRecoverySubjectMessage, + }, + }); + expect(resp).toEqual([ + { + frequency: { + notifyWhen: 'onActionGroupChange', + summary: false, + throttle: null, + }, + group: 'recovered', + id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9', + params: { + subAction: 'closeAlert', + subActionParams: { + alias: '{{rule.id}}:{{alert.id}}', + description: + 'The alert for monitor "{{context.monitorName}}" from {{context.locationNames}} is no longer active: {{context.recoveryReason}}. - Elastic Synthetics\n\nDetails:\n\n- Monitor name: {{context.monitorName}} \n- {{context.monitorUrlLabel}}: {{{context.monitorUrl}}} \n- Monitor type: {{context.monitorType}} \n- From: {{context.locationNames}} \n- Last error received: {{{context.lastErrorMessage}}} \n{{{context.linkMessage}}}', + message: + 'Monitor "{{context.monitorName}}" ({{context.locationNames}}) {{context.recoveryStatus}} - Elastic Synthetics', + priority: 'P2', + tags: ['{{rule.tags}}'], + }, + }, + }, + { + frequency: { + notifyWhen: 'onActionGroupChange', + summary: false, + throttle: null, + }, + group: 'xpack.synthetics.alerts.actionGroups.monitorStatus', + id: 'f2a3b195-ed76-499a-805d-82d24d4eeba9', + params: { + subAction: 'createAlert', + subActionParams: { + alias: '{{rule.id}}:{{alert.id}}', + description: + 'Monitor "{{context.monitorName}}" is {{{context.status}}} from {{context.locationNames}}.{{{context.pendingLastRunAt}}} - Elastic Synthetics\n\nDetails:\n\n- Monitor name: {{context.monitorName}} \n- {{context.monitorUrlLabel}}: {{{context.monitorUrl}}} \n- Monitor type: {{context.monitorType}} \n- Checked at: {{context.checkedAt}} \n- From: {{context.locationNames}} \n- Reason: {{{context.reason}}} \n- Error received: {{{context.lastErrorMessage}}} \n{{{context.linkMessage}}}', + message: + 'Monitor "{{context.monitorName}}" ({{context.locationNames}}) is down - Elastic Synthetics', + priority: 'P2', + tags: ['{{rule.tags}}'], + }, + }, + }, + ]); + }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts index 9b6d9d0992ba..a9981cd257ee 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/alert_actions.ts @@ -14,10 +14,12 @@ import type { WebhookActionParams, EmailActionParams, SlackApiActionParams, + OpsgenieActionParams, } from '@kbn/stack-connectors-plugin/server/connector_types'; import { RuleAction as RuleActionOrig } from '@kbn/alerting-plugin/common'; import { v4 as uuidv4 } from 'uuid'; +import { OpsgenieSubActions } from '@kbn/stack-connectors-plugin/common'; import { ActionConnector, ActionTypeId } from './types'; import { DefaultEmail } from '../runtime_types'; @@ -31,6 +33,7 @@ export const SERVICE_NOW_ACTION_ID: ActionTypeId = '.servicenow'; export const JIRA_ACTION_ID: ActionTypeId = '.jira'; export const WEBHOOK_ACTION_ID: ActionTypeId = '.webhook'; export const EMAIL_ACTION_ID: ActionTypeId = '.email'; +export const OPSGENIE_ACTION_ID: ActionTypeId = '.opsgenie'; export type RuleAction = Omit<RuleActionOrig, 'actionTypeId'>; @@ -128,6 +131,14 @@ export function populateAlertActions({ actions.push(recoveredAction); } break; + case OPSGENIE_ACTION_ID: + // @ts-expect-error + action.params = getOpsgenieActionParams(translations); + // @ts-expect-error + recoveredAction.params = getOpsgenieActionParams(translations, true); + actions.push(recoveredAction); + break; + default: action.params = { message: translations.defaultActionMessage, @@ -293,3 +304,24 @@ function getEmailActionParams( }, }; } + +function getOpsgenieActionParams( + { + defaultActionMessage, + defaultSubjectMessage, + defaultRecoverySubjectMessage, + defaultRecoveryMessage, + }: Translations, + isRecovery?: boolean +): OpsgenieActionParams { + return { + subAction: isRecovery ? OpsgenieSubActions.CloseAlert : OpsgenieSubActions.CreateAlert, + subActionParams: { + alias: '{{rule.id}}:{{alert.id}}', + tags: ['{{rule.tags}}'], + message: isRecovery ? defaultRecoverySubjectMessage : defaultSubjectMessage, + description: isRecovery ? defaultRecoveryMessage : defaultActionMessage, + priority: 'P2', + }, + } as OpsgenieActionParams; +} diff --git a/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts b/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts index a1888a100c17..0186bc8dc525 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/rules/types.ts @@ -16,6 +16,7 @@ import type { TeamsConnectorTypeId, WebhookConnectorTypeId, EmailConnectorTypeId, + OpsgenieConnectorTypeId, } from '@kbn/stack-connectors-plugin/server/connector_types'; import type { ActionConnector as RawActionConnector } from '@kbn/triggers-actions-ui-plugin/public'; @@ -31,6 +32,7 @@ export type ActionTypeId = | typeof ServiceNowConnectorTypeId | typeof JiraConnectorTypeId | typeof WebhookConnectorTypeId - | typeof EmailConnectorTypeId; + | typeof EmailConnectorTypeId + | typeof OpsgenieConnectorTypeId; export type ActionConnector = Omit<RawActionConnector, 'secrets'> & { config?: SlackApiConfig }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx index a4e653bb1ddb..eb97a0d5f396 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/alerts/tls_rule_ui.tsx @@ -9,8 +9,7 @@ import { useDispatch, useSelector } from 'react-redux'; import React, { useEffect } from 'react'; import { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { AlertTlsComponent } from './alert_tls'; -import { getDynamicSettings } from '../../state/settings/api'; -import { selectDynamicSettings } from '../../state/settings'; +import { getDynamicSettingsAction, selectDynamicSettings } from '../../state/settings'; import { TLSParams } from '../../../../../common/runtime_types/alerts/tls'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../common/constants'; @@ -24,7 +23,7 @@ export const TLSRuleComponent: React.FC<{ useEffect(() => { if (typeof settings === 'undefined') { - dispatch(getDynamicSettings()); + dispatch(getDynamicSettingsAction.get()); } }, [dispatch, settings]); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx index 65b9732e217e..4bc09bc9884d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/permissions.tsx @@ -33,15 +33,21 @@ export const FleetPermissionsCallout = () => { export const NoPermissionsTooltip = ({ canEditSynthetics = true, canUsePublicLocations = true, + canManagePrivateLocations = true, children, }: { canEditSynthetics?: boolean; canUsePublicLocations?: boolean; + canManagePrivateLocations?: boolean; children: ReactNode; }) => { const { isServiceAllowed } = useEnablement(); - const disabledMessage = getRestrictionReasonLabel(canEditSynthetics, canUsePublicLocations); + const disabledMessage = getRestrictionReasonLabel( + canEditSynthetics, + canUsePublicLocations, + canManagePrivateLocations + ); if (!isServiceAllowed) { return ( @@ -64,13 +70,18 @@ export const NoPermissionsTooltip = ({ function getRestrictionReasonLabel( canEditSynthetics = true, - canUsePublicLocations = true + canUsePublicLocations = true, + canManagePrivateLocations = true ): string | undefined { const message = !canEditSynthetics ? CANNOT_PERFORM_ACTION_SYNTHETICS : undefined; if (message) { return message; } + if (!canManagePrivateLocations) { + return NEED_PERMISSIONS_PRIVATE_LOCATIONS; + } + return !canUsePublicLocations ? CANNOT_PERFORM_ACTION_PUBLIC_LOCATIONS : undefined; } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts index f81601e3ed41..ee00905ec7bd 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_fetch_active_alerts.ts @@ -6,7 +6,10 @@ */ import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import { + AlertConsumers, + SYNTHETICS_RULE_TYPE_IDS, +} from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { useFetcher } from '@kbn/observability-shared-plugin/public'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useParams } from 'react-router-dom'; @@ -25,7 +28,8 @@ export function useFetchActiveAlerts() { const { loading, data } = useFetcher(async () => { return await http.post<ESSearchResponse>(`${BASE_RAC_ALERTS_API_PATH}/find`, { body: JSON.stringify({ - feature_ids: [AlertConsumers.UPTIME], + rule_type_ids: SYNTHETICS_RULE_TYPE_IDS, + consumers: [AlertConsumers.UPTIME, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY], size: 0, track_total_hits: true, query: { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx index 1737aa21b27d..cb071a877d6e 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitor_details/monitor_alerts/monitor_detail_alerts.tsx @@ -6,7 +6,7 @@ */ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers, SYNTHETICS_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { useParams } from 'react-router-dom'; import { useRefreshedRangeFromUrl } from '../../../hooks'; @@ -44,7 +44,8 @@ export function MonitorDetailsAlerts() { configurationId={AlertConsumers.OBSERVABILITY} id={MONITOR_ALERTS_TABLE_ID} data-test-subj="monitorAlertsTable" - featureIds={[AlertConsumers.UPTIME]} + ruleTypeIds={SYNTHETICS_RULE_TYPE_IDS} + consumers={[AlertConsumers.UPTIME, AlertConsumers.ALERTS, AlertConsumers.OBSERVABILITY]} query={{ bool: { filter: [ diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts index c75bc5e48920..03c2c2ace921 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_create_slo.ts @@ -41,10 +41,6 @@ export function useCreateSLO({ tags: [], }, }, - budgetingMethod: 'occurrences', - objective: { - target: 0.99, - }, tags: tags || [], groupBy: ['monitor.name', 'observer.geo.name', 'monitor.id'], }, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx index 8f8fe31a638c..ac6b471c9046 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/locations_table.tsx @@ -52,7 +52,7 @@ export const PrivateLocationsTable = ({ const { locationMonitors, loading } = useLocationMonitors(); - const { canSave } = useSyntheticsSettingsContext(); + const { canSave, canManagePrivateLocations } = useSyntheticsSettingsContext(); const tagsList = privateLocations.reduce((acc, item) => { const tags = item.tags || []; @@ -128,13 +128,16 @@ export const PrivateLocationsTable = ({ const renderToolRight = () => { return [ - <NoPermissionsTooltip canEditSynthetics={canSave}> + <NoPermissionsTooltip + canEditSynthetics={canSave} + canManagePrivateLocations={canManagePrivateLocations} + key="addPrivateLocationButton" + > <EuiButton - key="addPrivateLocationButton" fill data-test-subj={'addPrivateLocationButton'} isLoading={loading} - disabled={!canSave} + disabled={!canSave || !canManagePrivateLocations} onClick={() => setIsAddingNew(true)} iconType="plusInCircle" > diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx index 24c32569f1f2..5cabd6cf1374 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/settings/private_locations/manage_private_locations.test.tsx @@ -119,6 +119,7 @@ describe('<ManagePrivateLocations />', () => { const privateLocationName = 'Test private location'; jest.spyOn(settingsHooks, 'useSyntheticsSettingsContext').mockReturnValue({ canSave, + canManagePrivateLocations: true, } as SyntheticsSettingsContextValues); jest.spyOn(locationHooks, 'usePrivateLocationsAPI').mockReturnValue({ diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx index d380d95c90aa..518920ee0fd5 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/contexts/synthetics_settings_context.tsx @@ -45,6 +45,7 @@ export interface SyntheticsAppProps { export interface SyntheticsSettingsContextValues { canSave: boolean; + canManagePrivateLocations: boolean; basePath: string; dateRangeStart: string; dateRangeEnd: string; @@ -74,6 +75,7 @@ const defaultContext: SyntheticsSettingsContextValues = { isLogsAvailable: true, isDev: false, canSave: false, + canManagePrivateLocations: false, }; export const SyntheticsSettingsContext = createContext(defaultContext); @@ -96,6 +98,8 @@ export const SyntheticsSettingsContextProvider: React.FC<PropsWithChildren<Synth const { application } = useKibana().services; const canSave = (application?.capabilities.uptime.save ?? false) as boolean; + const canManagePrivateLocations = (application?.capabilities.uptime.canManagePrivateLocations ?? + false) as boolean; const value = useMemo(() => { return { @@ -109,6 +113,7 @@ export const SyntheticsSettingsContextProvider: React.FC<PropsWithChildren<Synth dateRangeStart: dateRangeStart ?? DATE_RANGE_START, dateRangeEnd: dateRangeEnd ?? DATE_RANGE_END, isServerless, + canManagePrivateLocations, }; }, [ canSave, @@ -121,6 +126,7 @@ export const SyntheticsSettingsContextProvider: React.FC<PropsWithChildren<Synth dateRangeEnd, commonlyUsedRanges, isServerless, + canManagePrivateLocations, ]); return <SyntheticsSettingsContext.Provider value={value} children={children} />; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx index c97cefc19406..687c2e833151 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_breadcrumbs.test.tsx @@ -63,6 +63,7 @@ describe('useBreadcrumbs', () => { setBreadcrumbs: core.chrome.setBreadcrumbs, isInfraAvailable: false, isLogsAvailable: false, + canManagePrivateLocations: false, }} > <Component /> diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx index 794747853642..7c8824a8d56c 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/monitor_status.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { ALERT_REASON } from '@kbn/rule-data-utils'; +import { ALERT_REASON, SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import type { ObservabilityRuleTypeModel } from '@kbn/observability-plugin/public'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; @@ -15,7 +15,6 @@ import { getSyntheticsErrorRouteFromMonitorId } from '../../../../../common/util import { STATE_ID } from '../../../../../common/field_names'; import { SyntheticsMonitorStatusTranslations } from '../../../../../common/rules/synthetics/translations'; import type { StatusRuleParams } from '../../../../../common/rules/status_rule'; -import { SYNTHETICS_ALERT_RULE_TYPES } from '../../../../../common/constants/synthetics_alerts'; import type { AlertTypeInitializer } from './types'; const { defaultActionMessage, defaultRecoveryMessage, description } = diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx index 896a84cd1688..10c45ece27a9 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/lib/alert_types/tls.tsx @@ -6,13 +6,12 @@ */ import React from 'react'; -import { ALERT_REASON } from '@kbn/rule-data-utils'; +import { ALERT_REASON, SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import { ObservabilityRuleTypeModel } from '@kbn/observability-plugin/public'; import type { RuleTypeParamsExpressionProps } from '@kbn/triggers-actions-ui-plugin/public'; import { ValidationResult } from '@kbn/triggers-actions-ui-plugin/public'; import { TlsTranslations } from '../../../../../common/rules/synthetics/translations'; import { CERTIFICATES_ROUTE } from '../../../../../common/constants/ui'; -import { SYNTHETICS_ALERT_RULE_TYPES } from '../../../../../common/constants/synthetics_alerts'; import type { TLSParams } from '../../../../../common/runtime_types/alerts/tls'; import type { AlertTypeInitializer } from './types'; diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts index ff4516a86122..1e3f8bf35e06 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts @@ -10,16 +10,14 @@ import { isEmpty } from 'lodash'; import { GetViewInAppRelativeUrlFnOpts, AlertsClientError } from '@kbn/alerting-plugin/server'; import { observabilityPaths } from '@kbn/observability-plugin/common'; import apm from 'elastic-apm-node'; +import { SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import { AlertOverviewStatus } from '../../../common/runtime_types/alert_rules/common'; import { StatusRuleExecutorOptions } from './types'; import { syntheticsRuleFieldMap } from '../../../common/rules/synthetics_rule_field_map'; import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from '../../types'; import { StatusRuleExecutor } from './status_rule_executor'; import { StatusRulePramsSchema } from '../../../common/rules/status_rule'; -import { - MONITOR_STATUS, - SYNTHETICS_ALERT_RULE_TYPES, -} from '../../../common/constants/synthetics_alerts'; +import { MONITOR_STATUS } from '../../../common/constants/synthetics_alerts'; import { setRecoveredAlertsContext, updateState, diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts index 5f8fc43c5d91..111d590a4fd7 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule.ts @@ -14,6 +14,7 @@ import { AlertsClientError, } from '@kbn/alerting-plugin/server'; import { asyncForEach } from '@kbn/std'; +import { SYNTHETICS_ALERT_RULE_TYPES } from '@kbn/rule-data-utils'; import { getAlertDetailsUrl, observabilityPaths } from '@kbn/observability-plugin/common'; import { schema } from '@kbn/config-schema'; import { ObservabilityUptimeAlert } from '@kbn/alerts-as-data-utils'; @@ -22,10 +23,7 @@ import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from '../.. import { getCertSummary, getTLSAlertDocument, setTLSRecoveredAlertsContext } from './message_utils'; import { SyntheticsCommonState } from '../../../common/runtime_types/alert_rules/common'; import { TLSRuleExecutor } from './tls_rule_executor'; -import { - SYNTHETICS_ALERT_RULE_TYPES, - TLS_CERTIFICATE, -} from '../../../common/constants/synthetics_alerts'; +import { TLS_CERTIFICATE } from '../../../common/constants/synthetics_alerts'; import { SyntheticsRuleTypeAlertDefinition, updateState } from '../common'; import { ALERT_DETAILS_URL, getActionVariables } from '../action_variables'; import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; diff --git a/x-pack/plugins/observability_solution/synthetics/server/feature.ts b/x-pack/plugins/observability_solution/synthetics/server/feature.ts index 5a4c4d508853..0e8a08e8aed1 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/feature.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/feature.ts @@ -11,9 +11,10 @@ import { SubFeaturePrivilegeGroupConfig, SubFeaturePrivilegeGroupType, } from '@kbn/features-plugin/common'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; +import { UPTIME_RULE_TYPE_IDS, SYNTHETICS_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { syntheticsMonitorType, syntheticsParamType } from '../common/types/saved_objects'; -import { SYNTHETICS_RULE_TYPES } from '../common/constants/synthetics_alerts'; import { legacyPrivateLocationsSavedObjectName, privateLocationSavedObjectName, @@ -25,22 +26,22 @@ import { } from './saved_objects/synthetics_settings'; import { syntheticsApiKeyObjectType } from './saved_objects/service_api_key'; -const UPTIME_RULE_TYPES = [ - 'xpack.uptime.alerts.tls', - 'xpack.uptime.alerts.tlsCertificate', - 'xpack.uptime.alerts.monitorStatus', - 'xpack.uptime.alerts.durationAnomaly', -]; +export const PRIVATE_LOCATION_WRITE_API = 'private-location-write'; -const ruleTypes = [...UPTIME_RULE_TYPES, ...SYNTHETICS_RULE_TYPES]; +const ruleTypes = [...UPTIME_RULE_TYPE_IDS, ...SYNTHETICS_RULE_TYPE_IDS]; + +const alertingFeatures = ruleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: [PLUGIN.ID, ALERTING_FEATURE_ID], +})); const elasticManagedLocationsEnabledPrivilege: SubFeaturePrivilegeGroupConfig = { groupType: 'independent' as SubFeaturePrivilegeGroupType, privileges: [ { id: 'elastic_managed_locations_enabled', - name: i18n.translate('xpack.synthetics.features.elasticManagedLocations', { - defaultMessage: 'Elastic managed locations enabled', + name: i18n.translate('xpack.synthetics.features.elasticManagedLocations.label', { + defaultMessage: 'Enabled', }), includeIn: 'all', savedObject: { @@ -52,6 +53,25 @@ const elasticManagedLocationsEnabledPrivilege: SubFeaturePrivilegeGroupConfig = ], }; +const canManagePrivateLocationsPrivilege: SubFeaturePrivilegeGroupConfig = { + groupType: 'independent' as SubFeaturePrivilegeGroupType, + privileges: [ + { + id: 'can_manage_private_locations', + name: i18n.translate('xpack.synthetics.features.canManagePrivateLocations', { + defaultMessage: 'Can manage', + }), + includeIn: 'all', + api: [PRIVATE_LOCATION_WRITE_API], + savedObject: { + all: [privateLocationSavedObjectName, legacyPrivateLocationsSavedObjectName], + read: [], + }, + ui: ['canManagePrivateLocations'], + }, + ], +}; + export const syntheticsFeature = { id: PLUGIN.ID, name: PLUGIN.NAME, @@ -63,7 +83,7 @@ export const syntheticsFeature = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: ruleTypes, + alerting: alertingFeatures, privileges: { all: { app: ['uptime', 'kibana', 'synthetics'], @@ -74,20 +94,19 @@ export const syntheticsFeature = { syntheticsSettingsObjectType, syntheticsMonitorType, syntheticsApiKeyObjectType, - privateLocationSavedObjectName, - legacyPrivateLocationsSavedObjectName, syntheticsParamType, + // uptime settings object is also registered here since feature is shared between synthetics and uptime uptimeSettingsObjectType, ], - read: [], + read: [privateLocationSavedObjectName, legacyPrivateLocationsSavedObjectName], }, alerting: { rule: { - all: ruleTypes, + all: alertingFeatures, }, alert: { - all: ruleTypes, + all: alertingFeatures, }, }, management: { @@ -114,10 +133,10 @@ export const syntheticsFeature = { }, alerting: { rule: { - read: ruleTypes, + read: alertingFeatures, }, alert: { - read: ruleTypes, + read: alertingFeatures, }, }, management: { @@ -128,10 +147,24 @@ export const syntheticsFeature = { }, subFeatures: [ { - name: i18n.translate('xpack.synthetics.features.app', { - defaultMessage: 'Synthetics', + name: i18n.translate('xpack.synthetics.features.app.elastic', { + defaultMessage: 'Elastic managed locations', + }), + description: i18n.translate('xpack.synthetics.features.app.elasticDescription', { + defaultMessage: + 'This feature enables users to create monitors that execute tests from Elastic managed infrastructure around the globe. There is an additional charge to use Elastic Managed testing locations. See the Elastic Cloud Pricing https://www.elastic.co/pricing page for current prices.', }), privilegeGroups: [elasticManagedLocationsEnabledPrivilege], }, + { + name: i18n.translate('xpack.synthetics.features.app.private', { + defaultMessage: 'Private locations', + }), + description: i18n.translate('xpack.synthetics.features.app.private,description', { + defaultMessage: + 'This feature allows you to manage your private locations, for example adding, or deleting them.', + }), + privilegeGroups: [canManagePrivateLocationsPrivilege], + }, ], }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/lib.ts b/x-pack/plugins/observability_solution/synthetics/server/lib.ts index 94150c0fb8ee..8a703e1c051e 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/lib.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/lib.ts @@ -158,7 +158,7 @@ export class SyntheticsEsClient { esError, esRequestParams: { index: SYNTHETICS_INDEX_PATTERN, ...request }, esRequestStatus: RequestStatus.OK, - esResponse: res.body.responses[index], + esResponse: res?.body.responses[index], kibanaRequest: this.request!, operationName: operationName ?? '', startTime: startTimeNow, @@ -168,9 +168,10 @@ export class SyntheticsEsClient { } return { - responses: res.body?.responses as unknown as Array< - InferSearchResponseOf<TDocument, TSearchRequest> - >, + responses: + (res?.body?.responses as unknown as Array< + InferSearchResponseOf<TDocument, TSearchRequest> + >) ?? [], }; } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts index 2e2263f6e396..d13395a42ca1 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/default_alerts/default_alert_service.ts @@ -99,7 +99,7 @@ export class DefaultAlertService { } async getExistingAlert(ruleType: DefaultRuleType) { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); const { data } = await rulesClient.find({ options: { @@ -123,7 +123,7 @@ export class DefaultAlertService { } const actions = await this.getAlertActions(ruleType); - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); const { actions: actionsFromRules = [], systemActions = [], @@ -158,7 +158,7 @@ export class DefaultAlertService { minimumRuleInterval ); } else { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); await rulesClient.bulkDeleteRules({ filter: `alert.attributes.alertTypeId:"${SYNTHETICS_STATUS_RULE}" AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, }); @@ -174,7 +174,7 @@ export class DefaultAlertService { minimumRuleInterval ); } else { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); await rulesClient.bulkDeleteRules({ filter: `alert.attributes.alertTypeId:"${SYNTHETICS_TLS_RULE}" AND alert.attributes.tags:"SYNTHETICS_DEFAULT_ALERT"`, }); @@ -182,7 +182,7 @@ export class DefaultAlertService { } async upsertDefaultAlert(ruleType: DefaultRuleType, name: string, interval: string) { - const rulesClient = (await this.context.alerting)?.getRulesClient(); + const rulesClient = await (await this.context.alerting)?.getRulesClient(); const alert = await this.getExistingAlert(ruleType); if (alert) { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts index d460b7103795..2b815313c79c 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/edit_monitor.ts @@ -305,7 +305,7 @@ export const syncEditedMonitor = async ({ }; export const validatePermissions = async ( - { server, response, request }: RouteContext, + routeContext: RouteContext, monitorLocations: MonitorLocations ) => { const hasPublicLocations = monitorLocations?.some((loc) => loc.isServiceManaged); @@ -313,19 +313,26 @@ export const validatePermissions = async ( return; } - const elasticManagedLocationsEnabled = - Boolean( - ( - await server.coreStart?.capabilities.resolveCapabilities(request, { - capabilityPath: 'uptime.*', - }) - ).uptime.elasticManagedLocationsEnabled - ) ?? true; + const { elasticManagedLocationsEnabled } = await validateLocationPermissions(routeContext); if (!elasticManagedLocationsEnabled) { return ELASTIC_MANAGED_LOCATIONS_DISABLED; } }; +export const validateLocationPermissions = async ({ server, request }: RouteContext) => { + const uptimeFeature = await server.coreStart?.capabilities.resolveCapabilities(request, { + capabilityPath: 'uptime.*', + }); + const elasticManagedLocationsEnabled = + Boolean(uptimeFeature.uptime.elasticManagedLocationsEnabled) ?? true; + const canManagePrivateLocations = Boolean(uptimeFeature.uptime.canManagePrivateLocations) ?? true; + + return { + canManagePrivateLocations, + elasticManagedLocationsEnabled, + }; +}; + const getInvalidOriginError = (monitor: SyntheticsMonitor) => { return { body: { diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts index 1feb120b2ea1..fa88de31e3ec 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/add_private_location.ts @@ -6,6 +6,7 @@ */ import { schema, TypeOf } from '@kbn/config-schema'; +import { PRIVATE_LOCATION_WRITE_API } from '../../../feature'; import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { SyntheticsRestApiRouteFactory } from '../../types'; import { getPrivateLocationsAndAgentPolicies } from './get_private_locations'; @@ -38,10 +39,12 @@ export const addPrivateLocationRoute: SyntheticsRestApiRouteFactory<PrivateLocat body: PrivateLocationSchema, }, }, + requiredPrivileges: [PRIVATE_LOCATION_WRITE_API], handler: async (routeContext) => { - await migrateLegacyPrivateLocations(routeContext); + const { response, request, savedObjectsClient, syntheticsMonitorClient, server } = routeContext; + const internalSOClient = server.coreStart.savedObjects.createInternalRepository(); - const { response, request, savedObjectsClient, syntheticsMonitorClient } = routeContext; + await migrateLegacyPrivateLocations(internalSOClient, server.logger); const location = request.body as PrivateLocationObject; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts index bac3907eac87..d01b255dd2b3 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/delete_private_location.ts @@ -7,6 +7,7 @@ import { schema } from '@kbn/config-schema'; import { isEmpty } from 'lodash'; +import { PRIVATE_LOCATION_WRITE_API } from '../../../feature'; import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; import { getMonitorsByLocation } from './get_location_monitors'; import { getPrivateLocationsAndAgentPolicies } from './get_private_locations'; @@ -25,10 +26,13 @@ export const deletePrivateLocationRoute: SyntheticsRestApiRouteFactory<undefined }), }, }, + requiredPrivileges: [PRIVATE_LOCATION_WRITE_API], handler: async (routeContext) => { - await migrateLegacyPrivateLocations(routeContext); - const { savedObjectsClient, syntheticsMonitorClient, request, response, server } = routeContext; + const internalSOClient = server.coreStart.savedObjects.createInternalRepository(); + + await migrateLegacyPrivateLocations(internalSOClient, server.logger); + const { locationId } = request.params as { locationId: string }; const { locations } = await getPrivateLocationsAndAgentPolicies( diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts index d884bba5c2b0..90d2e861379a 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/get_private_locations.ts @@ -31,9 +31,11 @@ export const getPrivateLocationsRoute: SyntheticsRestApiRouteFactory< }, }, handler: async (routeContext) => { - await migrateLegacyPrivateLocations(routeContext); + const { savedObjectsClient, syntheticsMonitorClient, request, response, server } = routeContext; + + const internalSOClient = server.coreStart.savedObjects.createInternalRepository(); + await migrateLegacyPrivateLocations(internalSOClient, server.logger); - const { savedObjectsClient, syntheticsMonitorClient, request, response } = routeContext; const { id } = request.params as { id?: string }; const { locations, agentPolicies } = await getPrivateLocationsAndAgentPolicies( diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts index 2305853aab3f..f1e3101523c2 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.test.ts @@ -6,42 +6,28 @@ */ import { migrateLegacyPrivateLocations } from './migrate_legacy_private_locations'; -import { SyntheticsServerSetup } from '../../../types'; -import { coreMock, savedObjectsClientMock } from '@kbn/core/server/mocks'; +import { savedObjectsRepositoryMock } from '@kbn/core/server/mocks'; import { loggerMock } from '@kbn/logging-mocks'; -import { - type ISavedObjectsRepository, - SavedObjectsClientContract, -} from '@kbn/core-saved-objects-api-server'; +import { type ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; +import { Logger } from '@kbn/logging'; describe('migrateLegacyPrivateLocations', () => { - let serverMock: SyntheticsServerSetup; - let savedObjectsClient: jest.Mocked<SavedObjectsClientContract>; - let repositoryMock: ISavedObjectsRepository; + let loggerMockVal: Logger; + let repositoryMock: jest.Mocked<ISavedObjectsRepository>; beforeEach(() => { - const coreStartMock = coreMock.createStart(); - serverMock = { - coreStart: coreStartMock, - logger: loggerMock.create(), - } as any; - savedObjectsClient = savedObjectsClientMock.create(); - repositoryMock = coreMock.createStart().savedObjects.createInternalRepository(); - - coreStartMock.savedObjects.createInternalRepository.mockReturnValue(repositoryMock); + repositoryMock = savedObjectsRepositoryMock.create(); + loggerMockVal = loggerMock.create(); }); it('should get the legacy private locations', async () => { - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: [{ id: '1', label: 'Location 1' }] }, } as any); - savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + repositoryMock.find.mockResolvedValueOnce({ total: 1 } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); - expect(savedObjectsClient.get).toHaveBeenCalledWith( + expect(repositoryMock.get).toHaveBeenCalledWith( 'synthetics-privates-locations', 'synthetics-privates-locations-singleton' ); @@ -49,43 +35,36 @@ describe('migrateLegacyPrivateLocations', () => { it('should log and return if an error occurs while getting legacy private locations', async () => { const error = new Error('Get error'); - savedObjectsClient.get.mockRejectedValueOnce(error); - - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, + repositoryMock.get.mockResolvedValueOnce({ + attributes: { locations: [{ id: '1', label: 'Location 1' }] }, } as any); + repositoryMock.bulkCreate.mockRejectedValueOnce(error); + + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); - expect(serverMock.logger.error).toHaveBeenCalledWith( - `Error getting legacy private locations: ${error}` + expect(loggerMockVal.error).toHaveBeenCalledWith( + 'Error migrating legacy private locations: Error: Get error' ); - expect(repositoryMock.bulkCreate).not.toHaveBeenCalled(); }); it('should return if there are no legacy locations', async () => { - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: [] }, } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient: savedObjectsClientMock, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); expect(repositoryMock.bulkCreate).not.toHaveBeenCalled(); }); it('should bulk create new private locations if there are legacy locations', async () => { const legacyLocations = [{ id: '1', label: 'Location 1' }]; - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: legacyLocations }, } as any); - savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + repositoryMock.find.mockResolvedValueOnce({ total: 1 } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); expect(repositoryMock.bulkCreate).toHaveBeenCalledWith( legacyLocations.map((location) => ({ @@ -100,17 +79,14 @@ describe('migrateLegacyPrivateLocations', () => { it('should delete legacy private locations if bulk create count matches', async () => { const legacyLocations = [{ id: '1', label: 'Location 1' }]; - savedObjectsClient.get.mockResolvedValueOnce({ + repositoryMock.get.mockResolvedValueOnce({ attributes: { locations: legacyLocations }, } as any); - savedObjectsClient.find.mockResolvedValueOnce({ total: 1 } as any); + repositoryMock.find.mockResolvedValueOnce({ total: 1 } as any); - await migrateLegacyPrivateLocations({ - server: serverMock, - savedObjectsClient, - } as any); + await migrateLegacyPrivateLocations(repositoryMock, loggerMockVal); - expect(savedObjectsClient.delete).toHaveBeenCalledWith( + expect(repositoryMock.delete).toHaveBeenCalledWith( 'synthetics-privates-locations', 'synthetics-privates-locations-singleton', {} diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts index cd73e27b950e..e823e7764f54 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/settings/private_locations/migrate_legacy_private_locations.ts @@ -6,6 +6,8 @@ */ import { SavedObject } from '@kbn/core-saved-objects-server'; +import type { ISavedObjectsRepository } from '@kbn/core-saved-objects-api-server'; +import { Logger } from '@kbn/logging'; import { type PrivateLocationAttributes, SyntheticsPrivateLocationsAttributes, @@ -15,21 +17,20 @@ import { legacyPrivateLocationsSavedObjectName, privateLocationSavedObjectName, } from '../../../../common/saved_objects/private_locations'; -import { RouteContext } from '../../types'; -export const migrateLegacyPrivateLocations = async ({ - server, - savedObjectsClient, -}: RouteContext) => { +export const migrateLegacyPrivateLocations = async ( + soClient: ISavedObjectsRepository, + logger: Logger +) => { try { let obj: SavedObject<SyntheticsPrivateLocationsAttributes> | undefined; try { - obj = await savedObjectsClient.get<SyntheticsPrivateLocationsAttributes>( + obj = await soClient.get<SyntheticsPrivateLocationsAttributes>( legacyPrivateLocationsSavedObjectName, legacyPrivateLocationsSavedObjectId ); } catch (e) { - server.logger.error(`Error getting legacy private locations: ${e}`); + // we don't need to do anything if the legacy object doesn't exist return; } const legacyLocations = obj?.attributes.locations ?? []; @@ -37,8 +38,6 @@ export const migrateLegacyPrivateLocations = async ({ return; } - const soClient = server.coreStart.savedObjects.createInternalRepository(); - await soClient.bulkCreate<PrivateLocationAttributes>( legacyLocations.map((location) => ({ id: location.id, @@ -51,20 +50,21 @@ export const migrateLegacyPrivateLocations = async ({ } ); - const { total } = await savedObjectsClient.find<PrivateLocationAttributes>({ + const { total } = await soClient.find<PrivateLocationAttributes>({ type: privateLocationSavedObjectName, fields: [], perPage: 0, + namespaces: ['*'], }); if (total === legacyLocations.length) { - await savedObjectsClient.delete( + await soClient.delete( legacyPrivateLocationsSavedObjectName, legacyPrivateLocationsSavedObjectId, {} ); } } catch (e) { - server.logger.error(`Error migrating legacy private locations: ${e}`); + logger.error(`Error migrating legacy private locations: ${e}`); } }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts index fa481d16b92b..837197d72d23 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/types.ts @@ -38,6 +38,7 @@ export type SupportedMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; export interface UMServerRoute<T> { method: SupportedMethod; writeAccess?: boolean; + requiredPrivileges?: string[]; handler: T; validation?: VersionedRouteValidation<any, any, any>; streamHandler?: ( diff --git a/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts b/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts index f695662e811e..b7eaea482db9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/runtime_types/private_locations.ts @@ -21,6 +21,7 @@ export const PrivateLocationAttributesCodec = t.intersection([ lon: t.number, }), namespace: t.string, + spaces: t.array(t.string), }), ]); diff --git a/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts b/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts index 697cf93d7421..da3887ac94d5 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/synthetics_route_wrapper.ts @@ -24,7 +24,11 @@ export const syntheticsRouteWrapper: SyntheticsRouteWrapper = ( }, security: { authz: { - requiredPrivileges: ['uptime-read', ...(uptimeRoute?.writeAccess ? ['uptime-write'] : [])], + requiredPrivileges: [ + 'uptime-read', + ...(uptimeRoute.requiredPrivileges ?? []), + ...(uptimeRoute?.writeAccess ? ['uptime-write'] : []), + ], }, }, handler: async (context, request, response) => { diff --git a/x-pack/plugins/observability_solution/synthetics/server/types.ts b/x-pack/plugins/observability_solution/synthetics/server/types.ts index e024721101d1..1a8016830c08 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/types.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/types.ts @@ -17,10 +17,7 @@ import { Logger, SavedObjectsClientContract, } from '@kbn/core/server'; -import { - PluginStartContract as AlertingPluginStart, - PluginSetupContract as AlertingPluginSetup, -} from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { SharePluginSetup } from '@kbn/share-plugin/server'; import { ObservabilityPluginSetup } from '@kbn/observability-plugin/server'; import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/server'; @@ -62,14 +59,14 @@ export interface SyntheticsServerSetup { basePath: IBasePath; isDev?: boolean; coreStart: CoreStart; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; pluginsStart: SyntheticsPluginsStartDependencies; isElasticsearchServerless: boolean; } export interface SyntheticsPluginsSetupDependencies { features: FeaturesPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; observability: ObservabilityPluginSetup; usageCollection: UsageCollectionSetup; ml: MlSetup; @@ -90,7 +87,7 @@ export interface SyntheticsPluginsStartDependencies { taskManager: TaskManagerStartContract; telemetry: TelemetryPluginStart; spaces?: SpacesPluginStart; - alerting: AlertingPluginStart; + alerting: AlertingServerStart; } export type UptimeRequestHandlerContext = CustomRequestHandlerContext<{ diff --git a/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts b/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts index 223b8909de96..5de01b708ea2 100644 --- a/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts +++ b/x-pack/plugins/observability_solution/uptime/common/constants/synthetics_alerts.ts @@ -42,6 +42,4 @@ export const SYNTHETICS_ALERT_RULE_TYPES = { TLS: SYNTHETICS_TLS_RULE, }; -export const SYNTHETICS_RULE_TYPES = [SYNTHETICS_STATUS_RULE, SYNTHETICS_TLS_RULE]; - export const SYNTHETICS_RULE_TYPES_ALERT_CONTEXT = 'observability.uptime'; diff --git a/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts b/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts index 71f6bd1b183f..1a84cf461b3e 100644 --- a/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts +++ b/x-pack/plugins/observability_solution/uptime/common/constants/uptime_alerts.ts @@ -41,9 +41,4 @@ export const CLIENT_ALERT_TYPES = { DURATION_ANOMALY: 'xpack.uptime.alerts.durationAnomaly', }; -export const UPTIME_RULE_TYPES = [ - 'xpack.uptime.alerts.tls', - 'xpack.uptime.alerts.tlsCertificate', - 'xpack.uptime.alerts.monitorStatus', - 'xpack.uptime.alerts.durationAnomaly', -]; +export { UPTIME_RULE_TYPE_IDS as UPTIME_RULE_TYPES } from '@kbn/rule-data-utils'; diff --git a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts index 357d008c4b90..9cfc38b8730c 100644 --- a/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts +++ b/x-pack/plugins/observability_solution/uptime/server/legacy_uptime/routes/monitors/monitors_details.ts @@ -23,7 +23,7 @@ export const createGetMonitorDetailsRoute: UMRestApiRouteFactory = (libs: UMServ handler: async ({ uptimeEsClient, context, request }): Promise<any> => { const { monitorId, dateStart, dateEnd } = request.query; - const rulesClient = (await context.alerting)?.getRulesClient(); + const rulesClient = await (await context.alerting)?.getRulesClient(); return await libs.requests.getMonitorDetails({ uptimeEsClient, diff --git a/x-pack/plugins/observability_solution/ux/public/components/app/rum_dashboard/visitor_breakdown_map/use_layer_list.test.ts b/x-pack/plugins/observability_solution/ux/public/components/app/rum_dashboard/visitor_breakdown_map/use_layer_list.test.ts index f4e733baf6ef..025481c6b879 100644 --- a/x-pack/plugins/observability_solution/ux/public/components/app/rum_dashboard/visitor_breakdown_map/use_layer_list.test.ts +++ b/x-pack/plugins/observability_solution/ux/public/components/app/rum_dashboard/visitor_breakdown_map/use_layer_list.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { mockLayerList } from './__mocks__/regions_layer.mock'; import { useLayerList } from './use_layer_list'; diff --git a/x-pack/plugins/osquery/public/shared_components/osquery_action/use_is_osquery_available_simple.test.ts b/x-pack/plugins/osquery/public/shared_components/osquery_action/use_is_osquery_available_simple.test.ts index 77c91957b10d..c00335e1a397 100644 --- a/x-pack/plugins/osquery/public/shared_components/osquery_action/use_is_osquery_available_simple.test.ts +++ b/x-pack/plugins/osquery/public/shared_components/osquery_action/use_is_osquery_available_simple.test.ts @@ -6,7 +6,7 @@ */ import { useKibana } from '../../common/lib/kibana'; import { useIsOsqueryAvailableSimple } from './use_is_osquery_available_simple'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { createStartServicesMock } from '@kbn/triggers-actions-ui-plugin/public/common/lib/kibana/kibana_react.mock'; import { OSQUERY_INTEGRATION_NAME } from '../../../common'; import { httpServiceMock } from '@kbn/core/public/mocks'; @@ -41,15 +41,13 @@ describe('UseIsOsqueryAvailableSimple', () => { }); }); it('should expect response from API and return enabled flag', async () => { - const { result, waitForValueToChange } = renderHook(() => + const { result } = renderHook(() => useIsOsqueryAvailableSimple({ agentId: '3242332', }) ); expect(result.current).toBe(false); - await waitForValueToChange(() => result.current); - - expect(result.current).toBe(true); + await waitFor(() => expect(result.current).toBe(true)); }); }); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts index 66ef6a73013f..d58d5398f907 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.mock.ts @@ -20,7 +20,6 @@ const createAlertsClientMock = () => { bulkUpdateCases: jest.fn(), find: jest.fn(), getGroupAggregations: jest.fn(), - getFeatureIdsByRegistrationContexts: jest.fn(), getBrowserFields: jest.fn(), getAlertSummary: jest.fn(), ensureAllAlertsAuthorizedRead: jest.fn(), diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.test.ts new file mode 100644 index 000000000000..77215955277d --- /dev/null +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.test.ts @@ -0,0 +1,244 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { coreMock, loggingSystemMock } from '@kbn/core/server/mocks'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { ruleDataServiceMock } from '../rule_data_plugin_service/rule_data_plugin_service.mock'; +import { AlertsClient, ConstructorOptions } from './alerts_client'; +import { fromKueryExpression } from '@kbn/es-query'; + +describe('AlertsClient', () => { + const alertingAuthMock = alertingAuthorizationMock.create(); + const ruleDataService = ruleDataServiceMock.create(); + const requestHandlerContext = coreMock.createRequestHandlerContext(); + const esClientMock = requestHandlerContext.elasticsearch.client.asCurrentUser; + + let alertsClient: AlertsClient; + + beforeEach(() => { + jest.clearAllMocks(); + alertingAuthMock.getSpaceId.mockReturnValue('space-1'); + alertingAuthMock.getAllAuthorizedRuleTypesFindOperation.mockResolvedValue( + new Map([ + [ + 'test-rule-type-1', + { + id: 'test-rule-type-1', + authorizedConsumers: { foo: { all: true, read: true } }, + }, + ], + ]) + ); + + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: fromKueryExpression( + 'alert.attributes.alertTypeId: test-rule-type-1 AND alert.attributes.consumer: foo' + ), + ensureRuleTypeIsAuthorized: jest.fn(), + }); + + const alertsClientParams: ConstructorOptions = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + ruleDataService, + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn(), + }; + + alertsClient = new AlertsClient(alertsClientParams); + }); + + describe('find', () => { + it('creates the ruleTypeIds filter correctly', async () => { + await alertsClient.find({ ruleTypeIds: ['test-rule-type-1', 'test-rule-type-2'] }); + + expect(esClientMock.search.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": Object { + "_source": undefined, + "aggs": undefined, + "fields": Array [ + "kibana.alert.rule.rule_type_id", + "kibana.alert.rule.consumer", + "kibana.alert.workflow_status", + "kibana.space_ids", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "test-rule-type-1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + }, + Object { + "term": Object { + "kibana.space_ids": "space-1", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "test-rule-type-1", + "test-rule-type-2", + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + "runtime_mappings": undefined, + "size": undefined, + "sort": Array [ + Object { + "@timestamp": Object { + "order": "asc", + "unmapped_type": "date", + }, + }, + ], + "track_total_hits": undefined, + }, + "ignore_unavailable": true, + "index": ".alerts-*", + "seq_no_primary_term": true, + } + `); + }); + + it('creates the consumers filter correctly', async () => { + await alertsClient.find({ consumers: ['test-consumer-1', 'test-consumer-2'] }); + + expect(esClientMock.search.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "body": Object { + "_source": undefined, + "aggs": undefined, + "fields": Array [ + "kibana.alert.rule.rule_type_id", + "kibana.alert.rule.consumer", + "kibana.alert.workflow_status", + "kibana.space_ids", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "arguments": Array [ + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.alertTypeId", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "test-rule-type-1", + }, + ], + "function": "is", + "type": "function", + }, + Object { + "arguments": Array [ + Object { + "isQuoted": false, + "type": "literal", + "value": "alert.attributes.consumer", + }, + Object { + "isQuoted": false, + "type": "literal", + "value": "foo", + }, + ], + "function": "is", + "type": "function", + }, + ], + "function": "and", + "type": "function", + }, + Object { + "term": Object { + "kibana.space_ids": "space-1", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "test-consumer-1", + "test-consumer-2", + ], + }, + }, + ], + "must": Array [], + "must_not": Array [], + "should": Array [], + }, + }, + "runtime_mappings": undefined, + "size": undefined, + "sort": Array [ + Object { + "@timestamp": Object { + "order": "asc", + "unmapped_type": "date", + }, + }, + ], + "track_total_hits": undefined, + }, + "ignore_unavailable": true, + "index": ".alerts-*", + "seq_no_primary_term": true, + } + `); + }); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts index ea80a365ccd9..3a898b07fb46 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts @@ -15,29 +15,23 @@ import { ALERT_STATUS, getEsQueryConfig, getSafeSortIds, - isValidFeatureId, STATUS_VALUES, - ValidFeatureId, ALERT_STATUS_RECOVERED, ALERT_END, ALERT_STATUS_ACTIVE, ALERT_CASE_IDS, MAX_CASES_PER_ALERT, - AlertConsumers, + isSiemRuleType, } from '@kbn/rule-data-utils'; import { AggregateName, AggregationsAggregate, - AggregationsMultiBucketAggregateBase, MappingRuntimeFields, QueryDslQueryContainer, SortCombinations, } from '@elastic/elasticsearch/lib/api/types'; -import type { - RuleTypeParams, - PluginStartContract as AlertingStart, -} from '@kbn/alerting-plugin/server'; +import type { RuleTypeParams, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { ReadOperations, AlertingAuthorization, @@ -68,6 +62,8 @@ import { MAX_ALERTS_PAGES, MAX_PAGINATED_ALERTS, } from './constants'; +import { getRuleTypeIdsFilter } from '../lib/get_rule_type_ids_filter'; +import { getConsumersFilter } from '../lib/get_consumers_filter'; // TODO: Fix typings https://github.com/elastic/kibana/issues/101776 type NonNullableProps<Obj extends {}, Props extends keyof Obj> = Omit<Obj, Props> & { @@ -97,7 +93,7 @@ export interface ConstructorOptions { ruleDataService: IRuleDataService; getRuleType: RuleTypeRegistry['get']; getRuleList: RuleTypeRegistry['list']; - getAlertIndicesAlias: AlertingStart['getAlertIndicesAlias']; + getAlertIndicesAlias: AlertingServerStart['getAlertIndicesAlias']; } export interface UpdateOptions<Params extends RuleTypeParams> { @@ -138,7 +134,8 @@ interface GetAlertSummaryParams { id?: string; gte: string; lte: string; - featureIds: string[]; + ruleTypeIds: string[]; + consumers?: string[]; filter?: estypes.QueryDslQueryContainer[]; fixedInterval?: string; } @@ -154,7 +151,8 @@ interface SearchAlertsParams { operation: WriteOperations.Update | ReadOperations.Find | ReadOperations.Get; sort?: estypes.SortOptions[]; lastSortIds?: Array<string | number>; - featureIds?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; runtimeMappings?: MappingRuntimeFields; } @@ -172,7 +170,7 @@ export class AlertsClient { private readonly ruleDataService: IRuleDataService; private readonly getRuleType: RuleTypeRegistry['get']; private readonly getRuleList: RuleTypeRegistry['list']; - private getAlertIndicesAlias!: AlertingStart['getAlertIndicesAlias']; + private getAlertIndicesAlias!: AlertingServerStart['getAlertIndicesAlias']; constructor(options: ConstructorOptions) { this.logger = options.logger; @@ -295,7 +293,8 @@ export class AlertsClient { operation, sort, lastSortIds = [], - featureIds, + ruleTypeIds, + consumers, runtimeMappings, }: SearchAlertsParams) { try { @@ -316,7 +315,8 @@ export class AlertsClient { alertSpaceId, operation, config, - featureIds ? new Set(featureIds) : undefined + ruleTypeIds, + consumers ), aggs, _source, @@ -372,7 +372,9 @@ export class AlertsClient { return result; } catch (error) { - const errorMessage = `Unable to retrieve alert details for alert with id of "${id}" or with query "${query}" and operation ${operation} \nError: ${error}`; + const errorMessage = `Unable to retrieve alert details for alert with id of "${id}" or with query "${JSON.stringify( + query + )}" and operation ${operation} \nError: ${error}`; this.logger.error(errorMessage); throw Boom.notFound(errorMessage); } @@ -457,16 +459,17 @@ export class AlertsClient { alertSpaceId: string, operation: WriteOperations.Update | ReadOperations.Get | ReadOperations.Find, config: EsQueryConfig, - featuresIds?: Set<string> + ruleTypeIds?: string[], + consumers?: string[] ) { try { - const authzFilter = (await getAuthzFilter( - this.authorization, - operation, - featuresIds - )) as Filter; + const authzFilter = (await getAuthzFilter(this.authorization, operation)) as Filter; const spacesFilter = getSpacesFilter(alertSpaceId) as unknown as Filter; + const ruleTypeIdsFilter = getRuleTypeIdsFilter(ruleTypeIds) as unknown as Filter; + const consumersFilter = getConsumersFilter(consumers) as unknown as Filter; + let esQuery; + if (id != null) { esQuery = { query: `_id:${id}`, language: 'kuery' }; } else if (typeof query === 'string') { @@ -474,12 +477,14 @@ export class AlertsClient { } else if (query != null && typeof query === 'object') { esQuery = []; } + const builtQuery = buildEsQuery( undefined, esQuery == null ? { query: ``, language: 'kuery' } : esQuery, - [authzFilter, spacesFilter], + [authzFilter, spacesFilter, ruleTypeIdsFilter, consumersFilter], config ); + if (query != null && typeof query === 'object') { return { ...builtQuery, @@ -639,15 +644,16 @@ export class AlertsClient { public async getAlertSummary({ gte, lte, - featureIds, + ruleTypeIds, + consumers, filter, fixedInterval = '1m', }: GetAlertSummaryParams) { try { - const indexToUse = await this.getAuthorizedAlertsIndices(featureIds); + const indexToUse = await this.getAuthorizedAlertsIndices(ruleTypeIds); if (isEmpty(indexToUse)) { - throw Boom.badRequest('no featureIds were provided for getting alert summary'); + throw Boom.badRequest('no ruleTypeIds were provided for getting alert summary'); } // first search for the alert by id, then use the alert info to check if user has access to it @@ -710,7 +716,8 @@ export class AlertsClient { }, }, size: 0, - featureIds, + ruleTypeIds, + consumers, }); let activeAlertCount = 0; @@ -981,7 +988,8 @@ export class AlertsClient { TAggregations = Record<AggregateName, AggregationsAggregate> >({ aggs, - featureIds, + ruleTypeIds, + consumers, index, query, search_after: searchAfter, @@ -992,7 +1000,8 @@ export class AlertsClient { runtimeMappings, }: { aggs?: object; - featureIds?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; index?: string; query?: object; search_after?: Array<string | number>; @@ -1004,15 +1013,16 @@ export class AlertsClient { }) { try { let indexToUse = index; - if (featureIds && !isEmpty(featureIds)) { - const tempIndexToUse = await this.getAuthorizedAlertsIndices(featureIds); + if (ruleTypeIds && !isEmpty(ruleTypeIds)) { + const tempIndexToUse = await this.getAuthorizedAlertsIndices(ruleTypeIds); if (!isEmpty(tempIndexToUse)) { indexToUse = (tempIndexToUse ?? []).join(); } } const alertsSearchResponse = await this.searchAlerts<TAggregations>({ - featureIds, + ruleTypeIds, + consumers, query, aggs, _source, @@ -1042,7 +1052,8 @@ export class AlertsClient { * Performs a `find` query to extract aggregations on alert groups */ public async getGroupAggregations({ - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, @@ -1051,9 +1062,15 @@ export class AlertsClient { sort = [{ unitsCount: { order: 'desc' } }], }: { /** - * The feature ids the alerts belong to, used for authorization + * The rule type IDs the alerts belong to. + * Used for filtering. + */ + ruleTypeIds: string[]; + /** + * The consumers the alerts belong to. + * Used for filtering. */ - featureIds: string[]; + consumers?: string[]; /** * The field to group by * @example "kibana.alert.rule.name" @@ -1093,9 +1110,10 @@ export class AlertsClient { } const searchResult = await this.find< never, - { groupByFields: AggregationsMultiBucketAggregateBase<{ key: string }> } + { groupByFields: estypes.AggregationsMultiBucketAggregateBase<{ key: string }> } >({ - featureIds, + ruleTypeIds, + consumers, aggs: { groupByFields: { terms: { @@ -1163,14 +1181,15 @@ export class AlertsClient { return searchResult; } - public async getAuthorizedAlertsIndices(featureIds: string[]): Promise<string[] | undefined> { + public async getAuthorizedAlertsIndices(ruleTypeIds?: string[]): Promise<string[] | undefined> { try { - const authorizedRuleTypes = await this.authorization.getAuthorizedRuleTypes( - AlertingAuthorizationEntity.Alert, - new Set(featureIds) - ); + const authorizedRuleTypes = await this.authorization.getAllAuthorizedRuleTypesFindOperation({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + ruleTypeIds, + }); + const indices = this.getAlertIndicesAlias( - authorizedRuleTypes.map((art: { id: any }) => art.id), + Array.from(authorizedRuleTypes.keys()).map((id) => id), this.spaceId ); @@ -1182,48 +1201,13 @@ export class AlertsClient { } } - public async getFeatureIdsByRegistrationContexts( - RegistrationContexts: string[] - ): Promise<string[]> { - try { - const featureIds = - this.ruleDataService.findFeatureIdsByRegistrationContexts(RegistrationContexts); - if (featureIds.length > 0) { - // ATTENTION FUTURE DEVELOPER when you are a super user the augmentedRuleTypes.authorizedRuleTypes will - // return all of the features that you can access and does not care about your featureIds - const augmentedRuleTypes = await this.authorization.getAugmentedRuleTypesWithAuthorization( - featureIds, - [ReadOperations.Find, ReadOperations.Get, WriteOperations.Update], - AlertingAuthorizationEntity.Alert - ); - // As long as the user can read a minimum of one type of rule type produced by the provided feature, - // the user should be provided that features' alerts index. - // Limiting which alerts that user can read on that index will be done via the findAuthorizationFilter - const authorizedFeatures = new Set<string>(); - for (const ruleType of augmentedRuleTypes.authorizedRuleTypes) { - authorizedFeatures.add(ruleType.producer); - } - const validAuthorizedFeatures = Array.from(authorizedFeatures).filter( - (feature): feature is ValidFeatureId => - featureIds.includes(feature) && isValidFeatureId(feature) - ); - return validAuthorizedFeatures; - } - return featureIds; - } catch (exc) { - const errMessage = `getFeatureIdsByRegistrationContexts failed to get feature ids: ${exc}`; - this.logger.error(errMessage); - throw Boom.failedDependency(errMessage); - } - } - public async getBrowserFields({ - featureIds, + ruleTypeIds, indices, metaFields, allowNoIndex, }: { - featureIds: string[]; + ruleTypeIds: string[]; indices: string[]; metaFields: string[]; allowNoIndex: boolean; @@ -1231,13 +1215,15 @@ export class AlertsClient { const indexPatternsFetcherAsInternalUser = new IndexPatternsFetcher(this.esClient); const ruleTypeList = this.getRuleList(); const fieldsForAAD = new Set<string>(); - for (const rule of ruleTypeList) { - if (featureIds.includes(rule.producer) && rule.hasFieldsForAAD) { + + for (const rule of ruleTypeList.values()) { + if (ruleTypeIds.includes(rule.id) && rule.hasFieldsForAAD) { (rule.fieldsForAAD ?? []).forEach((f) => { fieldsForAAD.add(f); }); } } + const { fields } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ pattern: indices, metaFields, @@ -1252,11 +1238,12 @@ export class AlertsClient { } public async getAADFields({ ruleTypeId }: { ruleTypeId: string }) { - const { producer, fieldsForAAD = [] } = this.getRuleType(ruleTypeId); - if (producer === AlertConsumers.SIEM) { + const { fieldsForAAD = [] } = this.getRuleType(ruleTypeId); + if (isSiemRuleType(ruleTypeId)) { throw Boom.badRequest(`Security solution rule type is not supported`); } - const indices = await this.getAuthorizedAlertsIndices([producer]); + + const indices = await this.getAuthorizedAlertsIndices([ruleTypeId]); const indexPatternsFetcherAsInternalUser = new IndexPatternsFetcher(this.esClient); const { fields = [] } = await indexPatternsFetcherAsInternalUser.getFieldsForWildcard({ pattern: indices ?? [], diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts index 367ead5744d5..8613f6135d30 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.test.ts @@ -21,7 +21,7 @@ const alertingAuthMock = alertingAuthorizationMock.create(); const alertsClientFactoryParams: AlertsClientFactoryProps = { logger: loggingSystemMock.create().get(), - getAlertingAuthorization: (_: KibanaRequest) => alertingAuthMock, + getAlertingAuthorization: (_: KibanaRequest) => Promise.resolve(alertingAuthMock), securityPluginSetup, esClient: {} as ElasticsearchClient, ruleDataService: ruleDataServiceMock.create(), diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts index 934074cc4a2e..91449954db61 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client_factory.ts @@ -8,10 +8,7 @@ import { PublicMethodsOf } from '@kbn/utility-types'; import { ElasticsearchClient, KibanaRequest, Logger } from '@kbn/core/server'; import type { RuleTypeRegistry } from '@kbn/alerting-plugin/server/types'; -import { - AlertingAuthorization, - PluginStartContract as AlertingStart, -} from '@kbn/alerting-plugin/server'; +import { AlertingAuthorization, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { IRuleDataService } from '../rule_data_plugin_service'; import { AlertsClient } from './alerts_client'; @@ -19,12 +16,14 @@ import { AlertsClient } from './alerts_client'; export interface AlertsClientFactoryProps { logger: Logger; esClient: ElasticsearchClient; - getAlertingAuthorization: (request: KibanaRequest) => PublicMethodsOf<AlertingAuthorization>; + getAlertingAuthorization: ( + request: KibanaRequest + ) => Promise<PublicMethodsOf<AlertingAuthorization>>; securityPluginSetup: SecurityPluginSetup | undefined; ruleDataService: IRuleDataService | null; getRuleType: RuleTypeRegistry['get']; getRuleList: RuleTypeRegistry['list']; - getAlertIndicesAlias: AlertingStart['getAlertIndicesAlias']; + getAlertIndicesAlias: AlertingServerStart['getAlertIndicesAlias']; } export class AlertsClientFactory { @@ -33,12 +32,12 @@ export class AlertsClientFactory { private esClient!: ElasticsearchClient; private getAlertingAuthorization!: ( request: KibanaRequest - ) => PublicMethodsOf<AlertingAuthorization>; + ) => Promise<PublicMethodsOf<AlertingAuthorization>>; private securityPluginSetup!: SecurityPluginSetup | undefined; private ruleDataService!: IRuleDataService | null; private getRuleType!: RuleTypeRegistry['get']; private getRuleList!: RuleTypeRegistry['list']; - private getAlertIndicesAlias!: AlertingStart['getAlertIndicesAlias']; + private getAlertIndicesAlias!: AlertingServerStart['getAlertIndicesAlias']; public initialize(options: AlertsClientFactoryProps) { /** @@ -61,10 +60,11 @@ export class AlertsClientFactory { public async create(request: KibanaRequest): Promise<AlertsClient> { const { securityPluginSetup, getAlertingAuthorization, logger } = this; + const authorization = await getAlertingAuthorization(request); return new AlertsClient({ logger, - authorization: getAlertingAuthorization(request), + authorization, auditLogger: securityPluginSetup?.audit.asScoped(request), esClient: this.esClient, ruleDataService: this.ruleDataService!, diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts index 28cd76ca6dff..8d2e6cffa0cc 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/bulk_update.test.ts @@ -17,7 +17,6 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; const alertingAuthMock = alertingAuthorizationMock.create(); @@ -36,39 +35,38 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); - alertingAuthMock.getSpaceId.mockImplementation(() => 'test_default_space_id'); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, + }); + + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); const fakeAlertId = 'myfakeid1'; @@ -337,7 +335,7 @@ describe('bulkUpdate()', () => { }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "queryAndAuditAllAlerts threw an error: Unable to retrieve alerts with query \\"kibana.alert.status: active\\" and operation update - Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"kibana.alert.status: active\\" and operation update + Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"\\"kibana.alert.status: active\\"\\" and operation update Error: Error: Unauthorized for fake.rule and apm" `); @@ -404,7 +402,7 @@ describe('bulkUpdate()', () => { }) ).rejects.toThrowErrorMatchingInlineSnapshot(` "queryAndAuditAllAlerts threw an error: Unable to retrieve alerts with query \\"kibana.alert.status: active\\" and operation update - Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"kibana.alert.status: active\\" and operation update + Error: Unable to retrieve alert details for alert with id of \\"null\\" or with query \\"\\"kibana.alert.status: active\\"\\" and operation update Error: Error: Unauthorized for fake.rule and apm" `); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts index 57e877f568cd..c554ee4d61f9 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/find_alerts.test.ts @@ -16,62 +16,107 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; +import { JsonObject } from '@kbn/utility-types'; -const alertingAuthMock = alertingAuthorizationMock.create(); -const esClientMock = elasticsearchClientMock.createElasticsearchClient(); -const auditLogger = auditLoggerMock.create(); +describe('find()', () => { + const alertingAuthMock = alertingAuthorizationMock.create(); + const esClientMock = elasticsearchClientMock.createElasticsearchClient(); + const auditLogger = auditLoggerMock.create(); -const alertsClientParams: jest.Mocked<ConstructorOptions> = { - logger: loggingSystemMock.create().get(), - authorization: alertingAuthMock, - esClient: esClientMock, - auditLogger, - ruleDataService: ruleDataServiceMock.create(), - getRuleType: jest.fn(), - getRuleList: jest.fn(), - getAlertIndicesAlias: jest.fn(), -}; + const alertsClientParams: jest.Mocked<ConstructorOptions> = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + auditLogger, + ruleDataService: ruleDataServiceMock.create(), + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn(), + }; -const DEFAULT_SPACE = 'test_default_space_id'; + const DEFAULT_SPACE = 'test_default_space_id'; + const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], + ]); -beforeEach(() => { - jest.resetAllMocks(); - alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); - }); + const filter = { + bool: { + filter: [ + { + bool: { + should: [ + { + bool: { + filter: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.rule_type_id': '.es-query' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'stackAlerts' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'alerts' } }], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + ], + minimum_should_match: 1, + }, + }, + { term: { 'kibana.space_ids': 'default' } }, + { terms: { 'kibana.alert.rule.rule_type_id': ['.es-query'] } }, + ], + }, + }; - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { + beforeEach(() => { + jest.resetAllMocks(); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: filter as unknown as JsonObject, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, + }); + + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { return Promise.resolve(); } return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); - } - ); -}); + }); + }); -describe('find()', () => { test('calls ES client with given params', async () => { const alertsClient = new AlertsClient(alertsClientParams); const searchAlertsSpy = jest.spyOn(alertsClient as any, 'searchAlerts'); @@ -111,19 +156,25 @@ describe('find()', () => { }); const query = { match: { [ALERT_WORKFLOW_STATUS]: 'open' } }; const index = '.alerts-observability.apm.alerts'; - const featureIds = ['siem']; + const ruleTypeIds = ['siem.esqlRule', 'siem.eqlRule']; + const consumers = ['siem']; + const result = await alertsClient.find({ query, index, - featureIds, + ruleTypeIds, + consumers, }); + expect(searchAlertsSpy).toHaveBeenCalledWith( expect.objectContaining({ query, index, - featureIds, + ruleTypeIds, + consumers, }) ); + expect(result).toMatchInlineSnapshot(` Object { "_shards": Object { @@ -176,12 +227,100 @@ describe('find()', () => { "query": Object { "bool": Object { "filter": Array [ - Object {}, + Object { + "bool": Object { + "filter": Array [ + 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": Object { + "kibana.alert.rule.rule_type_id": ".es-query", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "stackAlerts", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "alerts", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "default", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + ], + }, + }, Object { "term": Object { "kibana.space_ids": "test_default_space_id", }, }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "siem.esqlRule", + "siem.eqlRule", + ], + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "siem", + ], + }, + }, ], "must": Array [ Object { @@ -310,7 +449,80 @@ describe('find()', () => { "query": Object { "bool": Object { "filter": Array [ - Object {}, + Object { + "bool": Object { + "filter": Array [ + 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": Object { + "kibana.alert.rule.rule_type_id": ".es-query", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "stackAlerts", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "alerts", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "default", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + ], + }, + }, Object { "term": Object { "kibana.space_ids": "test_default_space_id", @@ -437,7 +649,7 @@ describe('find()', () => { index: '.alerts-observability.apm.alerts', }) ).rejects.toThrowErrorMatchingInlineSnapshot(` - "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find + "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"{\\"match\\":{\\"kibana.alert.workflow_status\\":\\"open\\"}}\\" and operation find Error: Error: Unauthorized for fake.rule and apm" `); @@ -467,7 +679,7 @@ describe('find()', () => { index: '.alerts-observability.apm.alerts', }) ).rejects.toThrowErrorMatchingInlineSnapshot(` - "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"[object Object]\\" and operation find + "Unable to retrieve alert details for alert with id of \\"undefined\\" or with query \\"{\\"match\\":{\\"kibana.alert.workflow_status\\":\\"open\\"}}\\" and operation find Error: Error: something went wrong" `); }); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts index b48e68c3bf25..b0fcb505d95b 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get.test.ts @@ -17,7 +17,6 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; const alertingAuthMock = alertingAuthorizationMock.create(); @@ -36,41 +35,38 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); describe('get()', () => { @@ -150,7 +146,6 @@ describe('get()', () => { ], }, }, - Object {}, Object { "term": Object { "kibana.space_ids": "test_default_space_id", diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts index 777b3d3e2674..0a7b11e2be9b 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_aad_fields.test.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsClient, ConstructorOptions } from '../alerts_client'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; @@ -38,13 +37,12 @@ beforeEach(() => { describe('getAADFields()', () => { test('should throw an error when a rule type belong to security solution', async () => { getRuleTypeMock.mockImplementation(() => ({ - producer: AlertConsumers.SIEM, fieldsForAAD: [], })); const alertsClient = new AlertsClient(alertsClientParams); await expect( - alertsClient.getAADFields({ ruleTypeId: 'security-type' }) + alertsClient.getAADFields({ ruleTypeId: 'siem.esqlRule' }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"Security solution rule type is not supported"`); }); }); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts index c351de1283c2..2bcafffdeeba 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_group_aggregations.test.ts @@ -5,13 +5,11 @@ * 2.0. */ -import { AlertConsumers } from '@kbn/rule-data-utils'; import { AlertsClient, ConstructorOptions } from '../alerts_client'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; import { DEFAULT_ALERTS_GROUP_BY_FIELD_SIZE, MAX_ALERTS_GROUPING_QUERY_SIZE } from '../constants'; @@ -33,40 +31,38 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); describe('getGroupAggregations()', () => { @@ -74,7 +70,9 @@ describe('getGroupAggregations()', () => { const alertsClient = new AlertsClient(alertsClientParams); alertsClient.find = jest.fn().mockResolvedValue({ aggregations: {} }); - const featureIds = [AlertConsumers.STACK_ALERTS]; + const ruleTypeIds = ['.es-query']; + const consumers = ['stackAlerts']; + const groupByField = 'kibana.alert.rule.name'; const aggregations = { usersCount: { @@ -86,7 +84,8 @@ describe('getGroupAggregations()', () => { const filters = [{ range: { '@timestamp': { gte: 'now-1d/d', lte: 'now/d' } } }]; await alertsClient.getGroupAggregations({ - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, @@ -95,7 +94,8 @@ describe('getGroupAggregations()', () => { }); expect(alertsClient.find).toHaveBeenCalledWith({ - featureIds, + ruleTypeIds, + consumers, aggs: { groupByFields: { terms: { @@ -157,7 +157,7 @@ describe('getGroupAggregations()', () => { }); const result = await alertsClient.getGroupAggregations({ - featureIds: [AlertConsumers.STACK_ALERTS], + ruleTypeIds: ['.es-query'], groupByField: 'kibana.alert.rule.name', aggregations: {}, filters: [], @@ -176,7 +176,7 @@ describe('getGroupAggregations()', () => { await expect(() => alertsClient.getGroupAggregations({ - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], groupByField: 'kibana.alert.rule.name', pageIndex: 101, pageSize: 50, @@ -186,7 +186,7 @@ describe('getGroupAggregations()', () => { ); await expect(() => alertsClient.getGroupAggregations({ - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], groupByField: 'kibana.alert.rule.name', pageIndex: 10, pageSize: 5000, diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_summary.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_summary.test.ts new file mode 100644 index 000000000000..deb3b8205884 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/get_alerts_summary.test.ts @@ -0,0 +1,311 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { AlertsClient, ConstructorOptions } from '../alerts_client'; +import { loggingSystemMock } from '@kbn/core/server/mocks'; +import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; +import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; +import { JsonObject } from '@kbn/utility-types'; + +jest.mock('uuid', () => ({ v4: () => 'unique-value' })); + +const alertingAuthMock = alertingAuthorizationMock.create(); +const esClientMock = elasticsearchClientMock.createElasticsearchClient(); +const auditLogger = auditLoggerMock.create(); + +const alertsClientParams: jest.Mocked<ConstructorOptions> = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + esClient: esClientMock, + auditLogger, + ruleDataService: ruleDataServiceMock.create(), + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: jest.fn().mockReturnValue(['stack-index']), +}; + +const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + '.es-query', + { + producer: 'stackAlerts', + id: '.es-query', + alerts: { + context: 'stack', + }, + authorizedConsumers: {}, + }, + ], +]); + +const filter = { + bool: { + filter: [ + { + bool: { + should: [ + { + bool: { + filter: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.rule_type_id': '.es-query' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'stackAlerts' } }], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [{ match: { 'kibana.alert.rule.consumer': 'alerts' } }], + minimum_should_match: 1, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + ], + minimum_should_match: 1, + }, + }, + { term: { 'kibana.space_ids': 'default' } }, + { terms: { 'kibana.alert.rule.rule_type_id': ['.es-query'] } }, + ], + }, +}; + +describe('getAlertSummary()', () => { + beforeEach(() => { + jest.clearAllMocks(); + alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); + alertingAuthMock.getAllAuthorizedRuleTypesFindOperation.mockResolvedValue(authorizedRuleTypes); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: filter as unknown as JsonObject, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + }); + + test('calls find() with the correct params', async () => { + const alertsClient = new AlertsClient(alertsClientParams) as jest.Mocked<AlertsClient>; + alertsClient.find = jest.fn().mockResolvedValue({ aggregations: {} }); + + const ruleTypeIds = ['.es-query']; + const consumers = ['stackAlerts']; + + await alertsClient.getAlertSummary({ + gte: 'now-1d/d', + lte: 'now/d', + ruleTypeIds, + consumers, + }); + + expect(esClientMock.search.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "body": Object { + "_source": undefined, + "aggs": Object { + "active_alerts_bucket": Object { + "date_histogram": Object { + "extended_bounds": Object { + "max": "now/d", + "min": "now-1d/d", + }, + "field": "kibana.alert.time_range", + "fixed_interval": "1m", + "hard_bounds": Object { + "max": "now/d", + "min": "now-1d/d", + }, + "min_doc_count": 0, + }, + }, + "count": Object { + "terms": Object { + "field": "kibana.alert.status", + }, + }, + "recovered_alerts": Object { + "aggs": Object { + "container": Object { + "date_histogram": Object { + "extended_bounds": Object { + "max": "now/d", + "min": "now-1d/d", + }, + "field": "kibana.alert.end", + "fixed_interval": "1m", + "min_doc_count": 0, + }, + }, + }, + "filter": Object { + "term": Object { + "kibana.alert.status": "recovered", + }, + }, + }, + }, + "fields": Array [ + "kibana.alert.rule.rule_type_id", + "kibana.alert.rule.consumer", + "kibana.alert.workflow_status", + "kibana.space_ids", + ], + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "bool": Object { + "filter": Array [ + 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": Object { + "kibana.alert.rule.rule_type_id": ".es-query", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "stackAlerts", + }, + }, + ], + }, + }, + Object { + "bool": Object { + "minimum_should_match": 1, + "should": Array [ + Object { + "match": Object { + "kibana.alert.rule.consumer": "alerts", + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "default", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + ], + }, + }, + Object { + "term": Object { + "kibana.space_ids": "test_default_space_id", + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + ".es-query", + ], + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "stackAlerts", + ], + }, + }, + ], + "must": Array [ + Object { + "bool": Object { + "filter": Array [ + Object { + "range": Object { + "kibana.alert.time_range": Object { + "gt": "now-1d/d", + "lt": "now/d", + }, + }, + }, + ], + }, + }, + ], + "must_not": Array [], + "should": Array [], + }, + }, + "runtime_mappings": undefined, + "size": 0, + "sort": Array [ + Object { + "@timestamp": Object { + "order": "asc", + "unmapped_type": "date", + }, + }, + ], + "track_total_hits": undefined, + }, + "ignore_unavailable": true, + "index": "stack-index", + "seq_no_primary_term": true, + }, + ], + ] + `); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts b/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts index bd6a1b2695cd..4b9587b8e0ca 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/tests/update.test.ts @@ -16,7 +16,6 @@ import { loggingSystemMock } from '@kbn/core/server/mocks'; import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '../../rule_data_plugin_service/rule_data_plugin_service.mock'; const alertingAuthMock = alertingAuthorizationMock.create(); @@ -35,41 +34,38 @@ const alertsClientParams: jest.Mocked<ConstructorOptions> = { }; const DEFAULT_SPACE = 'test_default_space_id'; +const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', + { + producer: 'apm', + id: 'apm.error_rate', + alerts: { + context: 'observability.apm', + }, + authorizedConsumers: {}, + }, + ], +]); beforeEach(() => { jest.resetAllMocks(); alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); + alertingAuthMock.getAuthorizationFilter.mockResolvedValue({ + filter: undefined, + ensureRuleTypeIsAuthorized: jest.fn(), + }); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); }); describe('update()', () => { diff --git a/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts b/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts index e1524b99f88d..58ea503aa6ed 100644 --- a/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts +++ b/x-pack/plugins/rule_registry/server/lib/get_authz_filter.ts @@ -19,17 +19,15 @@ import { export async function getAuthzFilter( authorization: PublicMethodsOf<AlertingAuthorization>, - operation: WriteOperations.Update | ReadOperations.Get | ReadOperations.Find, - featuresIds?: Set<string> + operation: WriteOperations.Update | ReadOperations.Get | ReadOperations.Find ) { - const { filter } = await authorization.getAuthorizationFilter( - AlertingAuthorizationEntity.Alert, - { + const { filter } = await authorization.getAuthorizationFilter({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + filterOpts: { type: AlertingAuthorizationFilterType.ESDSL, fieldNames: { consumer: ALERT_RULE_CONSUMER, ruleTypeId: ALERT_RULE_TYPE_ID }, }, operation, - featuresIds - ); + }); return filter; } diff --git a/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.test.tsx b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.test.tsx new file mode 100644 index 000000000000..600177e1c33e --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getConsumersFilter } from './get_consumers_filter'; + +describe('getConsumersFilter()', () => { + it('should return a consumers filter', () => { + expect(getConsumersFilter(['foo', 'bar'])).toStrictEqual({ + terms: { + 'kibana.alert.rule.consumer': ['foo', 'bar'], + }, + }); + }); + + it('should return undefined if no consumers are provided', () => { + expect(getConsumersFilter()).toBeUndefined(); + }); + + it('should return undefined if an empty array is provided', () => { + expect(getConsumersFilter([])).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.tsx b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.tsx new file mode 100644 index 000000000000..c5089416b7ef --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_consumers_filter.tsx @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ALERT_RULE_CONSUMER } from '../../common/technical_rule_data_field_names'; + +export function getConsumersFilter(consumers?: string[]) { + return consumers && consumers.length > 0 + ? { terms: { [ALERT_RULE_CONSUMER]: consumers } } + : undefined; +} diff --git a/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.test.tsx b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.test.tsx new file mode 100644 index 000000000000..7254f25256c2 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.test.tsx @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { getRuleTypeIdsFilter } from './get_rule_type_ids_filter'; + +describe('getRuleTypeIdsFilter()', () => { + it('should return a rule type ids filter', () => { + expect(getRuleTypeIdsFilter(['foo', 'bar'])).toStrictEqual({ + terms: { + 'kibana.alert.rule.rule_type_id': ['foo', 'bar'], + }, + }); + }); + + it('should return undefined if no rule type ids are provided', () => { + expect(getRuleTypeIdsFilter()).toBeUndefined(); + }); + + it('should return undefined if an empty array is provided', () => { + expect(getRuleTypeIdsFilter([])).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.tsx b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.tsx new file mode 100644 index 000000000000..f204d6d17acf --- /dev/null +++ b/x-pack/plugins/rule_registry/server/lib/get_rule_type_ids_filter.tsx @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { ALERT_RULE_TYPE_ID } from '../../common/technical_rule_data_field_names'; + +export function getRuleTypeIdsFilter(ruleTypeIds?: string[]) { + return ruleTypeIds && ruleTypeIds.length > 0 + ? { terms: { [ALERT_RULE_TYPE_ID]: ruleTypeIds } } + : undefined; +} diff --git a/x-pack/plugins/rule_registry/server/plugin.ts b/x-pack/plugins/rule_registry/server/plugin.ts index 60ee2256ae37..ae1159843b17 100644 --- a/x-pack/plugins/rule_registry/server/plugin.ts +++ b/x-pack/plugins/rule_registry/server/plugin.ts @@ -18,10 +18,7 @@ import { ServiceStatusLevels, } from '@kbn/core/server'; -import type { - PluginSetupContract as AlertingSetup, - PluginStartContract as AlertingStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { SecurityPluginSetup } from '@kbn/security-plugin/server'; import type { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import type { @@ -40,11 +37,11 @@ import { ruleRegistrySearchStrategyProvider, RULE_SEARCH_STRATEGY_NAME } from '. export interface RuleRegistryPluginSetupDependencies { security?: SecurityPluginSetup; data: DataPluginSetup; - alerting: AlertingSetup; + alerting: AlertingServerSetup; } export interface RuleRegistryPluginStartDependencies { - alerting: AlertingStart; + alerting: AlertingServerStart; data: DataPluginStart; spaces?: SpacesPluginStart; } @@ -56,7 +53,7 @@ export interface RuleRegistryPluginSetupContract { export interface RuleRegistryPluginStartContract { getRacClientWithRequest: (req: KibanaRequest) => Promise<AlertsClient>; - alerting: AlertingStart; + alerting: AlertingServerStart; } export class RuleRegistryPlugin @@ -165,7 +162,7 @@ export class RuleRegistryPlugin logger, esClient: core.elasticsearch.client.asInternalUser, // NOTE: Alerts share the authorization client with the alerting plugin - getAlertingAuthorization(request: KibanaRequest) { + async getAlertingAuthorization(request: KibanaRequest) { return plugins.alerting.getAlertingAuthorizationWithRequest(request); }, securityPluginSetup: security, @@ -175,7 +172,7 @@ export class RuleRegistryPlugin getAlertIndicesAlias: plugins.alerting.getAlertIndicesAlias, }); - const getRacClientWithRequest = (request: KibanaRequest) => { + const getRacClientWithRequest = async (request: KibanaRequest) => { return alertsClientFactory.create(request); }; @@ -190,7 +187,7 @@ export class RuleRegistryPlugin return function alertsRouteHandlerContext(context, request): RacApiRequestHandlerContext { return { getAlertsClient: async () => { - const createdClient = alertsClientFactory.create(request); + const createdClient = await alertsClientFactory.create(request); return createdClient; }, }; diff --git a/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts b/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts index d3857c4c49f1..7f214c95b0fc 100644 --- a/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts +++ b/x-pack/plugins/rule_registry/server/routes/__mocks__/request_responses.ts @@ -12,7 +12,7 @@ export const getReadIndexRequest = () => requestMock.create({ method: 'get', path: `${BASE_RAC_ALERTS_API_PATH}/index`, - query: { features: 'siem' }, + query: { ruleTypeIds: 'siem.esqlRule' }, }); export const getReadRequest = () => @@ -33,18 +33,18 @@ export const getUpdateRequest = () => }, }); -export const getReadFeatureIdsRequest = () => +export const getFindRequest = () => requestMock.create({ - method: 'get', - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - query: { registrationContext: ['security'] }, + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/find`, + body: { rule_type_ids: ['siem.esqlRule'], consumers: ['siem'] }, }); export const getO11yBrowserFields = () => requestMock.create({ method: 'get', path: `${BASE_RAC_ALERTS_API_PATH}/browser_fields`, - query: { featureIds: ['apm', 'logs'] }, + query: { ruleTypeIds: ['apm.anomaly', 'logs.alert.document.count'] }, }); export const getMetricThresholdAADFields = () => @@ -59,7 +59,14 @@ export const getAlertsGroupAggregationsRequest = () => method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + consumers: ['apm'], groupByField: 'kibana.alert.rule.name', aggregations: { unitsCount: { diff --git a/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts b/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts index 6afba9e232c5..1fef218202f2 100644 --- a/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts +++ b/x-pack/plugins/rule_registry/server/routes/__mocks__/response_adapters.ts @@ -39,6 +39,8 @@ const buildResponses = (method: Method, calls: MockCall[]): ResponseCall[] => { status: call.statusCode, body: call.body, })); + case 'notFound': + return calls.map(([call]) => ({ status: 404, body: call.body })); default: throw new Error(`Encountered unexpected call to response.${method}`); } diff --git a/x-pack/plugins/rule_registry/server/routes/find.test.ts b/x-pack/plugins/rule_registry/server/routes/find.test.ts new file mode 100644 index 000000000000..c84868c39f88 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/routes/find.test.ts @@ -0,0 +1,56 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { findAlertsByQueryRoute } from './find'; +import { requestContextMock } from './__mocks__/request_context'; +import { getFindRequest } from './__mocks__/request_responses'; +import { serverMock } from './__mocks__/server'; + +describe('findAlertsByQueryRoute', () => { + let server: ReturnType<typeof serverMock.create>; + let { clients, context } = requestContextMock.createTools(); + + beforeEach(async () => { + server = serverMock.create(); + ({ clients, context } = requestContextMock.createTools()); + + // @ts-expect-error: More properties are not needed + clients.rac.find.mockResolvedValue({ hits: { hits: [] } }); + + findAlertsByQueryRoute(server.router); + }); + + test('returns 200 when querying for alerts', async () => { + const response = await server.inject(getFindRequest(), context); + + expect(response.status).toEqual(200); + expect(response.body).toEqual({ hits: { hits: [] } }); + }); + + test('calls the alerts client correctly', async () => { + const response = await server.inject(getFindRequest(), context); + + expect(response.status).toEqual(200); + expect(clients.rac.find).toHaveBeenCalledWith({ + _source: undefined, + aggs: undefined, + consumers: ['siem'], + index: undefined, + query: undefined, + ruleTypeIds: ['siem.esqlRule'], + search_after: undefined, + size: undefined, + sort: undefined, + track_total_hits: undefined, + }); + }); + + test('accepts not defined ryleTypeIds and consumers', async () => { + const response = await server.inject({ ...getFindRequest(), body: {} }, context); + expect(response.status).toEqual(200); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/routes/find.ts b/x-pack/plugins/rule_registry/server/routes/find.ts index 4ce4567dd35b..d41de4d64f71 100644 --- a/x-pack/plugins/rule_registry/server/routes/find.ts +++ b/x-pack/plugins/rule_registry/server/routes/find.ts @@ -25,7 +25,8 @@ export const findAlertsByQueryRoute = (router: IRouter<RacRequestHandlerContext> t.exact( t.partial({ aggs: t.record(t.string, t.intersection([metricsAggsSchemas, bucketAggsSchemas])), - feature_ids: t.union([t.array(t.string), t.undefined]), + rule_type_ids: t.union([t.array(t.string), t.undefined]), + consumers: t.union([t.array(t.string), t.undefined]), index: t.string, query: t.object, search_after: t.union([t.array(t.number), t.array(t.string), t.undefined]), @@ -50,7 +51,8 @@ export const findAlertsByQueryRoute = (router: IRouter<RacRequestHandlerContext> try { const { aggs, - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, + consumers, index, query, // eslint-disable-next-line @typescript-eslint/naming-convention @@ -65,7 +67,8 @@ export const findAlertsByQueryRoute = (router: IRouter<RacRequestHandlerContext> const alertsClient = await racContext.getAlertsClient(); const alerts = await alertsClient.find({ aggs, - featureIds, + ruleTypeIds, + consumers, index, query, search_after, diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts index b8ef01847d8e..28d901dc5a13 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_index.test.ts @@ -31,6 +31,28 @@ describe('getAlertsIndexRoute', () => { expect(response.body).toEqual({ index_name: ['alerts-security.alerts'] }); }); + test('accepts an array of string ', async () => { + const ruleTypeIds = ['foo', 'bar']; + + await server.inject({ ...getReadIndexRequest(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(ruleTypeIds); + }); + + test('accepts a single string', async () => { + const ruleTypeIds = 'foo'; + + await server.inject({ ...getReadIndexRequest(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith([ruleTypeIds]); + }); + + test('accepts not defined ryleTypeIds', async () => { + await server.inject({ ...getReadIndexRequest(), query: {} }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(undefined); + }); + describe('request validation', () => { test('rejects invalid query params', async () => { await expect( @@ -38,12 +60,12 @@ describe('getAlertsIndexRoute', () => { requestMock.create({ method: 'get', path: `${BASE_RAC_ALERTS_API_PATH}/index`, - query: { features: 4 }, + query: { ruleTypeIds: 4 }, }), context ) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"4\\" supplied to \\"features\\"'"` + `"Request was rejected with message: 'Invalid value \\"4\\" supplied to \\"ruleTypeIds\\"'"` ); }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts index aa3ec89fde7c..e83d784bd4fb 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_index.ts @@ -8,7 +8,6 @@ import { IRouter } from '@kbn/core/server'; import * as t from 'io-ts'; import { transformError } from '@kbn/securitysolution-es-utils'; -import { validFeatureIds } from '@kbn/rule-data-utils'; import { buildRouteValidation } from './utils/route_validation'; import { RacRequestHandlerContext } from '../types'; @@ -22,7 +21,7 @@ export const getAlertsIndexRoute = (router: IRouter<RacRequestHandlerContext>) = query: buildRouteValidation( t.exact( t.partial({ - features: t.string, + ruleTypeIds: t.union([t.string, t.array(t.string)]), }) ) ), @@ -40,10 +39,17 @@ export const getAlertsIndexRoute = (router: IRouter<RacRequestHandlerContext>) = try { const racContext = await context.rac; const alertsClient = await racContext.getAlertsClient(); - const { features } = request.query; - const indexName = await alertsClient.getAuthorizedAlertsIndices( - features?.split(',') ?? validFeatureIds - ); + const { ruleTypeIds } = request.query; + + const ruleTypeIdsAsArray = + ruleTypeIds != null + ? Array.isArray(ruleTypeIds) + ? ruleTypeIds + : [ruleTypeIds] + : ruleTypeIds; + + const indexName = await alertsClient.getAuthorizedAlertsIndices(ruleTypeIdsAsArray); + return response.ok({ body: { index_name: indexName }, }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts index e15f2d40dc82..961b33310bfc 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.test.ts @@ -35,7 +35,7 @@ describe('getAlertSummaryRoute', () => { requestMock.create({ method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, - body: { gte: 4, lte: 3, featureIds: ['logs'] }, + body: { gte: 4, lte: 3, ruleTypeIds: ['logs'] }, }), context ) @@ -52,7 +52,7 @@ describe('getAlertSummaryRoute', () => { body: { gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16', - featureIds: ['logs'], + ruleTypeIds: ['logs'], }, }), context @@ -76,7 +76,7 @@ describe('getAlertSummaryRoute', () => { body: { gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16T16:00:00.000Z', - featureIds: ['logs'], + ruleTypeIds: ['logs'], fixed_interval: 'xx', }, }), @@ -102,7 +102,7 @@ describe('getAlertSummaryRoute', () => { body: { gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16T16:00:00.000Z', - featureIds: ['logs'], + ruleTypeIds: ['logs'], boop: 'unknown', }, }), @@ -112,5 +112,68 @@ describe('getAlertSummaryRoute', () => { `"Request was rejected with message: 'invalid keys \\"boop\\"'"` ); }); + + test('rejects without ruleTypeIds', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, + body: { + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + }, + }), + context + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` + ); + }); + + test('accepts consumers', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, + body: { + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + consumers: ['foo'], + ruleTypeIds: ['bar'], + }, + }), + context + ) + ).resolves.not.toThrow(); + }); + + test('calls the alerts client correctly', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, + body: { + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + consumers: ['foo'], + ruleTypeIds: ['bar'], + }, + }), + context + ) + ).resolves.not.toThrow(); + + expect(clients.rac.getAlertSummary).toHaveBeenCalledWith({ + consumers: ['foo'], + filter: undefined, + fixedInterval: undefined, + gte: '2020-12-16T15:00:00.000Z', + lte: '2020-12-16T16:00:00.000Z', + ruleTypeIds: ['bar'], + }); + }); }); }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts index e33b0137a932..9be3de57fdc0 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alert_summary.ts @@ -27,13 +27,14 @@ export const getAlertSummaryRoute = (router: IRouter<RacRequestHandlerContext>) t.type({ gte: t.string, lte: t.string, - featureIds: t.array(t.string), + ruleTypeIds: t.array(t.string), }) ), t.exact( t.partial({ fixed_interval: t.string, filter: t.array(t.object), + consumers: t.array(t.string), }) ), ]) @@ -52,7 +53,14 @@ export const getAlertSummaryRoute = (router: IRouter<RacRequestHandlerContext>) try { const racContext = await context.rac; const alertsClient = await racContext.getAlertsClient(); - const { gte, lte, featureIds, filter, fixed_interval: fixedInterval } = request.body; + const { + gte, + lte, + ruleTypeIds, + consumers, + filter, + fixed_interval: fixedInterval, + } = request.body; if ( !( moment(gte, 'YYYY-MM-DDTHH:mm:ss.SSSZ', true).isValid() && @@ -71,7 +79,8 @@ export const getAlertSummaryRoute = (router: IRouter<RacRequestHandlerContext>) const aggs = await alertsClient.getAlertSummary({ gte, lte, - featureIds, + ruleTypeIds, + consumers, filter: filter as estypes.QueryDslQueryContainer[], fixedInterval, }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts index 1ce32adc37e6..5bf3a4a1622c 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.test.ts @@ -200,7 +200,7 @@ describe('getAlertsGroupAggregations', () => { context ) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"featureIds\\"'"` + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` ); }); @@ -211,7 +211,13 @@ describe('getAlertsGroupAggregations', () => { method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], groupByField: 'kibana.alert.rule.name', aggregations: { scriptedAggregation: { @@ -231,7 +237,13 @@ describe('getAlertsGroupAggregations', () => { method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], groupByField: 'kibana.alert.rule.name', filters: [ { @@ -256,7 +268,13 @@ describe('getAlertsGroupAggregations', () => { method: 'post', path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, body: { - featureIds: ['apm', 'infrastructure', 'logs', 'observability', 'slo', 'uptime'], + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], groupByField: 'kibana.alert.rule.name', aggregations: {}, runtimeMappings: {}, @@ -280,4 +298,84 @@ describe('getAlertsGroupAggregations', () => { message: 'Unable to get alerts', }); }); + + test('rejects without ruleTypeIds', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, + body: { + groupByField: 'kibana.alert.rule.name', + }, + }), + context + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` + ); + }); + + test('accepts consumers', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, + body: { + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + groupByField: 'kibana.alert.rule.name', + consumers: ['foo'], + }, + }), + context + ) + ).resolves.not.toThrow(); + }); + + test('calls the alerts client correctly', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'post', + path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, + body: { + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + groupByField: 'kibana.alert.rule.name', + consumers: ['foo'], + }, + }), + context + ) + ).resolves.not.toThrow(); + + expect(clients.rac.getGroupAggregations).toHaveBeenCalledWith({ + aggregations: undefined, + consumers: ['foo'], + filters: undefined, + groupByField: 'kibana.alert.rule.name', + pageIndex: 0, + pageSize: 10, + ruleTypeIds: [ + 'apm.anomaly', + 'logs.alert.document.count', + 'metrics.alert.threshold', + 'slo.rules.burnRate', + 'xpack.uptime.alerts.durationAnomaly', + ], + sort: undefined, + }); + }); }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts index 34c56b7691a1..6924025f2b33 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_alerts_group_aggregations.ts @@ -22,17 +22,24 @@ export const getAlertsGroupAggregations = (router: IRouter<RacRequestHandlerCont path: `${BASE_RAC_ALERTS_API_PATH}/_group_aggregations`, validate: { body: buildRouteValidation( - t.exact( - t.type({ - featureIds: t.array(t.string), - groupByField: t.string, - aggregations: t.union([alertsAggregationsSchema, t.undefined]), - filters: t.union([t.array(alertsGroupFilterSchema), t.undefined]), - sort: t.union([t.array(t.object), t.undefined]), - pageIndex: t.union([t.number, t.undefined]), - pageSize: t.union([t.number, t.undefined]), - }) - ) + t.intersection([ + t.exact( + t.type({ + ruleTypeIds: t.array(t.string), + groupByField: t.string, + aggregations: t.union([alertsAggregationsSchema, t.undefined]), + filters: t.union([t.array(alertsGroupFilterSchema), t.undefined]), + sort: t.union([t.array(t.object), t.undefined]), + pageIndex: t.union([t.number, t.undefined]), + pageSize: t.union([t.number, t.undefined]), + }) + ), + t.exact( + t.partial({ + consumers: t.array(t.string), + }) + ), + ]) ), }, security: { @@ -46,7 +53,8 @@ export const getAlertsGroupAggregations = (router: IRouter<RacRequestHandlerCont }, async (context, request, response) => { const { - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, @@ -58,7 +66,8 @@ export const getAlertsGroupAggregations = (router: IRouter<RacRequestHandlerCont const racContext = await context.rac; const alertsClient = await racContext.getAlertsClient(); const alerts = await alertsClient.getGroupAggregations({ - featureIds, + ruleTypeIds, + consumers, groupByField, aggregations, filters, diff --git a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.test.ts b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.test.ts deleted file mode 100644 index 49e559c9f4c2..000000000000 --- a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; -import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_feature_id'; -import { requestContextMock } from './__mocks__/request_context'; -import { getO11yBrowserFields } from './__mocks__/request_responses'; -import { requestMock, serverMock } from './__mocks__/server'; - -describe('getBrowserFieldsByFeatureId', () => { - let server: ReturnType<typeof serverMock.create>; - let { clients, context } = requestContextMock.createTools(); - const path = `${BASE_RAC_ALERTS_API_PATH}/browser_fields`; - - beforeEach(async () => { - server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); - }); - - describe('when racClient returns o11y indices', () => { - beforeEach(() => { - clients.rac.getAuthorizedAlertsIndices.mockResolvedValue([ - '.alerts-observability.logs.alerts-default', - ]); - - getBrowserFieldsByFeatureId(server.router); - }); - - test('route registered', async () => { - const response = await server.inject(getO11yBrowserFields(), context); - - expect(response.status).toEqual(200); - }); - - test('rejects invalid featureId type', async () => { - await expect( - server.inject( - requestMock.create({ - method: 'get', - path, - query: { featureIds: undefined }, - }), - context - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"featureIds\\"'"` - ); - }); - - test('returns error status if rac client "getAuthorizedAlertsIndices" fails', async () => { - clients.rac.getAuthorizedAlertsIndices.mockRejectedValue(new Error('Unable to get index')); - const response = await server.inject(getO11yBrowserFields(), context); - - expect(response.status).toEqual(500); - expect(response.body).toEqual({ - attributes: { success: false }, - message: 'Unable to get index', - }); - }); - }); -}); diff --git a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.test.ts b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.test.ts new file mode 100644 index 000000000000..819ed89bc7c0 --- /dev/null +++ b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.test.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; +import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_rule_type_ids'; +import { requestContextMock } from './__mocks__/request_context'; +import { getO11yBrowserFields } from './__mocks__/request_responses'; +import { requestMock, serverMock } from './__mocks__/server'; + +describe('getBrowserFieldsByFeatureId', () => { + let server: ReturnType<typeof serverMock.create>; + let { clients, context } = requestContextMock.createTools(); + const path = `${BASE_RAC_ALERTS_API_PATH}/browser_fields`; + + beforeEach(async () => { + server = serverMock.create(); + ({ clients, context } = requestContextMock.createTools()); + + clients.rac.getAuthorizedAlertsIndices.mockResolvedValue([ + '.alerts-observability.logs.alerts-default', + ]); + + clients.rac.getBrowserFields.mockResolvedValue({ browserFields: {}, fields: [] }); + + getBrowserFieldsByFeatureId(server.router); + }); + + test('route registered', async () => { + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(200); + }); + + test('it calls getAuthorizedAlertsIndices with o11y rule types', async () => { + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(200); + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith([ + 'apm.anomaly', + 'logs.alert.document.count', + ]); + }); + + test('it calls getAuthorizedAlertsIndices only for o11y rule types when siem rule types are mixed', async () => { + const response = await server.inject( + { + ...getO11yBrowserFields(), + query: { ruleTypeIds: ['apm.anomaly', 'siem.esqlRuleType'] }, + }, + context + ); + + expect(response.status).toEqual(200); + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(['apm.anomaly']); + }); + + test('it does not call getAuthorizedAlertsIndices with siem rule types', async () => { + const response = await server.inject( + { + ...getO11yBrowserFields(), + query: { ruleTypeIds: ['siem.esqlRuleType'] }, + }, + context + ); + + expect(response.status).toEqual(200); + expect(clients.rac.getAuthorizedAlertsIndices).not.toHaveBeenCalledWith(); + }); + + test('accepts an array of string ', async () => { + const ruleTypeIds = ['foo', 'bar']; + + await server.inject({ ...getO11yBrowserFields(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith(ruleTypeIds); + }); + + test('accepts a single string', async () => { + const ruleTypeIds = 'foo'; + + await server.inject({ ...getO11yBrowserFields(), query: { ruleTypeIds } }, context); + + expect(clients.rac.getAuthorizedAlertsIndices).toHaveBeenCalledWith([ruleTypeIds]); + }); + + test('returns 404 when getAuthorizedAlertsIndices returns an empty array', async () => { + clients.rac.getAuthorizedAlertsIndices.mockResolvedValue([]); + + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(404); + }); + + test('rejects invalid ruleTypeIds', async () => { + await expect( + server.inject( + requestMock.create({ + method: 'get', + path, + query: { ruleTypeIds: undefined }, + }), + context + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Request was rejected with message: 'Invalid value \\"undefined\\" supplied to \\"ruleTypeIds\\"'"` + ); + }); + + test('returns error status if rac client "getAuthorizedAlertsIndices" fails', async () => { + clients.rac.getAuthorizedAlertsIndices.mockRejectedValue(new Error('Unable to get index')); + const response = await server.inject(getO11yBrowserFields(), context); + + expect(response.status).toEqual(500); + expect(response.body).toEqual({ + attributes: { success: false }, + message: 'Unable to get index', + }); + }); +}); diff --git a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.ts similarity index 83% rename from x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts rename to x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.ts index 20a3781be697..4c27095ae77c 100644 --- a/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_feature_id.ts +++ b/x-pack/plugins/rule_registry/server/routes/get_browser_fields_by_rule_type_ids.ts @@ -9,6 +9,7 @@ import { IRouter } from '@kbn/core/server'; import { transformError } from '@kbn/securitysolution-es-utils'; import * as t from 'io-ts'; +import { isSiemRuleType } from '@kbn/rule-data-utils'; import { RacRequestHandlerContext } from '../types'; import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; import { buildRouteValidation } from './utils/route_validation'; @@ -21,7 +22,7 @@ export const getBrowserFieldsByFeatureId = (router: IRouter<RacRequestHandlerCon query: buildRouteValidation( t.exact( t.type({ - featureIds: t.union([t.string, t.array(t.string)]), + ruleTypeIds: t.union([t.string, t.array(t.string)]), }) ) ), @@ -39,18 +40,21 @@ export const getBrowserFieldsByFeatureId = (router: IRouter<RacRequestHandlerCon try { const racContext = await context.rac; const alertsClient = await racContext.getAlertsClient(); - const { featureIds = [] } = request.query; - const onlyO11yFeatureIds = (Array.isArray(featureIds) ? featureIds : [featureIds]).filter( - (fId) => fId !== 'siem' - ); + const { ruleTypeIds = [] } = request.query; + + const onlyO11yRuleTypeIds = ( + Array.isArray(ruleTypeIds) ? ruleTypeIds : [ruleTypeIds] + ).filter((ruleTypeId) => !isSiemRuleType(ruleTypeId)); + const o11yIndices = - (onlyO11yFeatureIds - ? await alertsClient.getAuthorizedAlertsIndices(onlyO11yFeatureIds) + (onlyO11yRuleTypeIds + ? await alertsClient.getAuthorizedAlertsIndices(onlyO11yRuleTypeIds) : []) ?? []; + if (o11yIndices.length === 0) { return response.notFound({ body: { - message: `No alerts-observability indices found for featureIds [${featureIds}]`, + message: `No alerts-observability indices found for rule type ids [${onlyO11yRuleTypeIds}]`, attributes: { success: false }, }, }); @@ -58,10 +62,11 @@ export const getBrowserFieldsByFeatureId = (router: IRouter<RacRequestHandlerCon const fields = await alertsClient.getBrowserFields({ indices: o11yIndices, - featureIds: onlyO11yFeatureIds, + ruleTypeIds: onlyO11yRuleTypeIds, metaFields: ['_id', '_index'], allowNoIndex: true, }); + return response.ok({ body: fields, }); diff --git a/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.test.ts b/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.test.ts deleted file mode 100644 index 80f2b4e6026d..000000000000 --- a/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.test.ts +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; -import { getFeatureIdsByRegistrationContexts } from './get_feature_ids_by_registration_contexts'; -import { requestContextMock } from './__mocks__/request_context'; -import { getReadFeatureIdsRequest } from './__mocks__/request_responses'; -import { requestMock, serverMock } from './__mocks__/server'; - -describe('getFeatureIdsByRegistrationContexts', () => { - let server: ReturnType<typeof serverMock.create>; - let { clients, context } = requestContextMock.createTools(); - - beforeEach(async () => { - server = serverMock.create(); - ({ clients, context } = requestContextMock.createTools()); - - clients.rac.getFeatureIdsByRegistrationContexts.mockResolvedValue(['siem']); - - getFeatureIdsByRegistrationContexts(server.router); - }); - - test('returns 200 when querying for features ids', async () => { - const response = await server.inject(getReadFeatureIdsRequest(), context); - - expect(response.status).toEqual(200); - expect(response.body).toEqual(['siem']); - }); - - describe('request validation', () => { - test('rejects invalid query params', async () => { - await expect( - server.inject( - requestMock.create({ - method: 'get', - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - query: { registrationContext: 4 }, - }), - context - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'Invalid value \\"4\\" supplied to \\"registrationContext\\"'"` - ); - }); - - test('rejects unknown query params', async () => { - await expect( - server.inject( - requestMock.create({ - method: 'get', - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - query: { boop: 'siem' }, - }), - context - ) - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Request was rejected with message: 'invalid keys \\"boop\\"'"` - ); - }); - }); - - test('returns error status if rac client "getFeatureIdsByRegistrationContexts" fails', async () => { - clients.rac.getFeatureIdsByRegistrationContexts.mockRejectedValue( - new Error('Unable to get feature ids') - ); - const response = await server.inject(getReadFeatureIdsRequest(), context); - - expect(response.status).toEqual(500); - expect(response.body).toEqual({ - attributes: { success: false }, - message: 'Unable to get feature ids', - }); - }); -}); diff --git a/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.ts b/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.ts deleted file mode 100644 index 43bd491daafb..000000000000 --- a/x-pack/plugins/rule_registry/server/routes/get_feature_ids_by_registration_contexts.ts +++ /dev/null @@ -1,71 +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 { IRouter } from '@kbn/core/server'; -import * as t from 'io-ts'; -import { transformError } from '@kbn/securitysolution-es-utils'; - -import { RacRequestHandlerContext } from '../types'; -import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; -import { buildRouteValidation } from './utils/route_validation'; - -export const getFeatureIdsByRegistrationContexts = (router: IRouter<RacRequestHandlerContext>) => { - router.get( - { - path: `${BASE_RAC_ALERTS_API_PATH}/_feature_ids`, - validate: { - query: buildRouteValidation( - t.exact( - t.partial({ - registrationContext: t.union([t.string, t.array(t.string)]), - }) - ) - ), - }, - security: { - authz: { - requiredPrivileges: ['rac'], - }, - }, - options: { - access: 'internal', - }, - }, - async (context, request, response) => { - try { - const racContext = await context.rac; - const alertsClient = await racContext.getAlertsClient(); - const { registrationContext = [] } = request.query; - const featureIds = await alertsClient.getFeatureIdsByRegistrationContexts( - Array.isArray(registrationContext) ? registrationContext : [registrationContext] - ); - return response.ok({ - body: featureIds, - }); - } catch (exc) { - const err = transformError(exc); - const contentType = { - 'content-type': 'application/json', - }; - const defaultedHeaders = { - ...contentType, - }; - - return response.customError({ - headers: defaultedHeaders, - statusCode: err.statusCode, - body: { - message: err.message, - attributes: { - success: false, - }, - }, - }); - } - } - ); -}; diff --git a/x-pack/plugins/rule_registry/server/routes/index.ts b/x-pack/plugins/rule_registry/server/routes/index.ts index ae9f113ee0ac..72ecfc4c9b8e 100644 --- a/x-pack/plugins/rule_registry/server/routes/index.ts +++ b/x-pack/plugins/rule_registry/server/routes/index.ts @@ -13,8 +13,7 @@ import { updateAlertByIdRoute } from './update_alert_by_id'; import { getAlertsIndexRoute } from './get_alert_index'; import { bulkUpdateAlertsRoute } from './bulk_update_alerts'; import { findAlertsByQueryRoute } from './find'; -import { getFeatureIdsByRegistrationContexts } from './get_feature_ids_by_registration_contexts'; -import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_feature_id'; +import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_rule_type_ids'; import { getAlertSummaryRoute } from './get_alert_summary'; import { getAADFieldsByRuleType } from './get_aad_fields_by_rule_type'; @@ -25,7 +24,6 @@ export function defineRoutes(router: IRouter<RacRequestHandlerContext>) { bulkUpdateAlertsRoute(router); findAlertsByQueryRoute(router); getAlertsGroupAggregations(router); - getFeatureIdsByRegistrationContexts(router); getBrowserFieldsByFeatureId(router); getAlertSummaryRoute(router); getAADFieldsByRuleType(router); diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts index 9b279a541b3e..cfbfafd0092b 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.mock.ts @@ -17,7 +17,6 @@ export const ruleDataServiceMock = { initializeIndex: jest.fn(), findIndexByName: jest.fn(), findIndexByFeature: jest.fn(), - findFeatureIdsByRegistrationContexts: jest.fn(), }), }; diff --git a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts index efe4a5dd4f32..91192848830e 100644 --- a/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts +++ b/x-pack/plugins/rule_registry/server/rule_data_plugin_service/rule_data_plugin_service.ts @@ -78,12 +78,6 @@ export interface IRuleDataService { * Note: features are used in RBAC. */ findIndexByFeature(featureId: ValidFeatureId, dataset: Dataset): IndexInfo | null; - - /** - * Looks up Kibana "feature" associated with the given registration context. - * Note: features are used in RBAC. - */ - findFeatureIdsByRegistrationContexts(registrationContexts: string[]): string[]; } // TODO: This is a leftover. Remove its usage from the "observability" plugin and delete it. @@ -248,17 +242,6 @@ export class RuleDataService implements IRuleDataService { return this.indicesByBaseName.get(baseName) ?? null; } - public findFeatureIdsByRegistrationContexts(registrationContexts: string[]): string[] { - const featureIds: string[] = []; - registrationContexts.forEach((rc) => { - const featureId = this.registrationContextByFeatureId.get(rc); - if (featureId) { - featureIds.push(featureId); - } - }); - return featureIds; - } - public findIndexByFeature(featureId: ValidFeatureId, dataset: Dataset): IndexInfo | null { const foundIndices = this.indicesByFeatureId.get(featureId) ?? []; if (dataset && foundIndices.length > 0) { diff --git a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts index 4dabfb3feb39..1086714ab758 100644 --- a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts +++ b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.test.ts @@ -4,12 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { of } from 'rxjs'; +import { lastValueFrom, of } from 'rxjs'; import { merge } from 'lodash'; import { loggerMock } from '@kbn/logging-mocks'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { ALERT_EVENTS_FIELDS } from '@kbn/alerts-as-data-utils'; -import { ruleRegistrySearchStrategyProvider, EMPTY_RESPONSE } from './search_strategy'; +import { ruleRegistrySearchStrategyProvider } from './search_strategy'; import { dataPluginMock } from '@kbn/data-plugin/server/mocks'; import { SearchStrategyDependencies } from '@kbn/data-plugin/server'; import { alertsMock } from '@kbn/alerting-plugin/server/mocks'; @@ -18,6 +17,9 @@ import { spacesMock } from '@kbn/spaces-plugin/server/mocks'; import type { RuleRegistrySearchRequest } from '../../common'; import * as getAuthzFilterImport from '../lib/get_authz_filter'; import { getIsKibanaRequest } from '../lib/get_is_kibana_request'; +import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; +import { Boom } from '@hapi/boom'; +import { KbnSearchError } from '@kbn/data-plugin/server/search/report_search_error'; jest.mock('../lib/get_is_kibana_request'); @@ -53,8 +55,10 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const security = securityMock.createSetup(); const spaces = spacesMock.createStart(); const logger = loggerMock.create(); + const authorizationMock = alertingAuthorizationMock.create(); const getAuthorizedRuleTypesMock = jest.fn(); const getAlertIndicesAliasMock = jest.fn(); + const response = getBasicResponse({ rawResponse: { hits: { @@ -73,13 +77,19 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const searchStrategySearch = jest.fn().mockImplementation(() => of(response)); beforeEach(() => { + jest.clearAllMocks(); + getAuthorizedRuleTypesMock.mockResolvedValue([]); getAlertIndicesAliasMock.mockReturnValue(['test']); - const authorizationMock = { - getAuthorizedRuleTypes: getAuthorizedRuleTypesMock, - } as never; alerting.getAlertingAuthorizationWithRequest.mockResolvedValue(authorizationMock); alerting.getAlertIndicesAlias = getAlertIndicesAliasMock; + alerting.listTypes.mockReturnValue( + // @ts-expect-error: rule type properties are not needed for the test + new Map([ + ['.es-query', {}], + ['siem.esqlRule', {}], + ]) + ); data.search.getSearchStrategy.mockImplementation(() => { return { @@ -115,7 +125,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => { getAuthorizedRuleTypesMock.mockResolvedValue([]); getAlertIndicesAliasMock.mockReturnValue(['observability-logs']); const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], }; const options = {}; const deps = { @@ -124,16 +134,16 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - const result = await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + const result = await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); expect(result).toEqual(response); }); it('should return an empty response if no valid indices are found', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], }; const options = {}; const deps = { @@ -145,15 +155,30 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - const result = await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); - expect(result).toBe(EMPTY_RESPONSE); + const result = await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + + expect(result).toMatchInlineSnapshot(` + Object { + "inspect": Object { + "dsl": Array [ + "{}", + ], + }, + "rawResponse": Object { + "hits": Object { + "hits": Array [], + "total": 0, + }, + }, + } + `); }); - it('should not apply rbac filters for siem', async () => { + it('should not apply rbac filters for siem rule types', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], }; const options = {}; const deps = { @@ -165,15 +190,16 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect(getAuthzFilterSpy).not.toHaveBeenCalled(); }); - it('should throw an error if requesting multiple featureIds and one is SIEM', async () => { + it('should throw an error if requesting multiple rule types and one is for siem', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM, AlertConsumers.LOGS], + ruleTypeIds: ['.es-query', 'siem.esqlRule'], }; const options = {}; const deps = { @@ -186,19 +212,70 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); let err; + try { - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); } catch (e) { err = e; } - expect(err).toBeDefined(); + + expect(err.statusCode).toBe(400); + expect(err.message).toBe( + 'The privateRuleRegistryAlertsSearchStrategy search strategy is unable to accommodate requests containing multiple rule types with mixed authorization.' + ); + }); + + it('should not throw an error with empty rule type ids', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: [], + }; + + const options = {}; + const deps = { + request: {}, + }; + + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue([]); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await expect( + lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ) + ).resolves.not.toThrow(); + }); + + it('should filter out invalid rule types', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query', 'not-exist'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await expect( + lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ) + ).resolves.not.toThrow(); + + expect(authorizationMock.getAllAuthorizedRuleTypesFindOperation).toHaveBeenCalledWith({ + authorizationEntity: 'alert', + ruleTypeIds: ['.es-query'], + }); }); it('should use internal user when requesting o11y alerts as RBAC is applied', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], }; const options = {}; const deps = { @@ -209,16 +286,17 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect(data.search.searchAsInternalUser.search).toHaveBeenCalled(); expect(searchStrategySearch).not.toHaveBeenCalled(); }); it('should use scoped user when requesting siem alerts as RBAC is not applied', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], }; const options = {}; const deps = { @@ -230,16 +308,17 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect(data.search.searchAsInternalUser.search as jest.Mock).not.toHaveBeenCalled(); expect(searchStrategySearch).toHaveBeenCalled(); }); it('should support pagination', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], pagination: { pageSize: 10, pageIndex: 0, @@ -254,9 +333,10 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect((data.search.searchAsInternalUser.search as jest.Mock).mock.calls.length).toBe(1); expect( (data.search.searchAsInternalUser.search as jest.Mock).mock.calls[0][0].params.body.size @@ -268,7 +348,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => { it('should support sorting', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['.es-query'], sort: [ { test: { @@ -286,9 +366,10 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + expect((data.search.searchAsInternalUser.search as jest.Mock).mock.calls.length).toBe(1); expect( (data.search.searchAsInternalUser.search as jest.Mock).mock.calls[0][0].params.body.sort @@ -297,7 +378,7 @@ describe('ruleRegistrySearchStrategyProvider()', () => { it('passes the query ids if provided', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], query: { ids: { values: ['test-id'] }, }, @@ -311,21 +392,24 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + const arg0 = searchStrategySearch.mock.calls[0][0]; expect(arg0.params.body.fields.length).toEqual( // +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and // fields.push({ field: 'signal.*', include_unmapped: false }); ALERT_EVENTS_FIELDS.length + 2 ); + expect.arrayContaining([ expect.objectContaining({ x: 2, y: 3, }), ]); + expect(arg0).toEqual( expect.objectContaining({ id: undefined, @@ -355,9 +439,9 @@ describe('ruleRegistrySearchStrategyProvider()', () => { ); }); - it('passes the fields if provided', async () => { + it('passes the fields if provided for siem rule types', async () => { const request: RuleRegistrySearchRequest = { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: ['siem.esqlRule'], query: { ids: { values: ['test-id'] }, }, @@ -372,42 +456,264 @@ describe('ruleRegistrySearchStrategyProvider()', () => { const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); - await strategy - .search(request, options, deps as unknown as SearchStrategyDependencies) - .toPromise(); + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); const arg0 = searchStrategySearch.mock.calls[0][0]; - expect(arg0.params.body.fields.length).toEqual( + const fields = arg0.params.body.fields; + + expect(fields.length).toEqual( // +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and // fields.push({ field: 'signal.*', include_unmapped: false }); + my-super-field ALERT_EVENTS_FIELDS.length + 3 ); - expect(arg0).toEqual( - expect.objectContaining({ - id: undefined, - params: expect.objectContaining({ - allow_no_indices: true, - body: expect.objectContaining({ - _source: false, - fields: expect.arrayContaining([ - expect.objectContaining({ - field: 'my-super-field', - include_unmapped: true, - }), - ]), - from: 0, - query: { - ids: { - values: ['test-id'], + + const siemField = fields.find((field: { field: string }) => field.field === 'signal.*'); + const kibanaField = fields.find((field: { field: string }) => field.field === 'kibana.alert.*'); + const myField = fields.find((field: { field: string }) => field.field === 'my-super-field'); + + expect(siemField).toMatchInlineSnapshot(` + Object { + "field": "signal.*", + "include_unmapped": false, + } + `); + + expect(kibanaField).toMatchInlineSnapshot(` + Object { + "field": "kibana.alert.*", + "include_unmapped": false, + } + `); + + expect(myField).toMatchInlineSnapshot(` + Object { + "field": "my-super-field", + "include_unmapped": true, + } + `); + }); + + it('passes the fields if provided for o11y rule types', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + query: { + ids: { values: ['test-id'] }, + }, + fields: [{ field: 'my-super-field', include_unmapped: true }], + }; + const options = {}; + const deps = { + request: {}, + }; + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue(['security-siem']); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + + const arg0 = (data.search.searchAsInternalUser.search as jest.Mock).mock.calls[0][0]; + const fields = arg0.params.body.fields; + + expect(fields.length).toEqual( + // +2 because of fields.push({ field: 'kibana.alert.*', include_unmapped: false }); and + // fields.push({ field: '*', include_unmapped: false }); + my-super-field + 3 + ); + + const allField = fields.find((field: { field: string }) => field.field === '*'); + const kibanaField = fields.find((field: { field: string }) => field.field === 'kibana.alert.*'); + const myField = fields.find((field: { field: string }) => field.field === 'my-super-field'); + + expect(allField).toMatchInlineSnapshot(` + Object { + "field": "*", + "include_unmapped": true, + } + `); + + expect(kibanaField).toMatchInlineSnapshot(` + Object { + "field": "kibana.alert.*", + "include_unmapped": false, + } + `); + + expect(myField).toMatchInlineSnapshot(` + Object { + "field": "my-super-field", + "include_unmapped": true, + } + `); + }); + + it('should handle Boom errors correctly', async () => { + getAuthzFilterSpy.mockRejectedValue(new Boom('boom error message', { statusCode: 400 })); + + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + let err; + + try { + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + } catch (e) { + err = e; + } + + expect(err.statusCode).toBe(400); + expect(err.message).toBe('boom error message'); + }); + + it('should handle KbnSearchError errors correctly', async () => { + getAuthzFilterSpy.mockRejectedValue(new KbnSearchError('kbn search error message', 403)); + + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + let err; + + try { + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + } catch (e) { + err = e; + } + + expect(err.statusCode).toBe(403); + expect(err.message).toBe('kbn search error message'); + }); + + it('should convert errors to KbnSearchError errors correctly', async () => { + getAuthzFilterSpy.mockRejectedValue(new Error('plain error message')); + + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['.es-query'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + let err; + + try { + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + } catch (e) { + err = e; + } + + expect(err.statusCode).toBe(500); + expect(err.message).toBe('plain error message'); + }); + + it('should apply the rule type IDs filter', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['siem.esqlRule'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue(['security-siem']); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) + ); + + const arg0 = searchStrategySearch.mock.calls[0][0]; + expect(arg0.params.body.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "siem.esqlRule", + ], }, }, - size: 1000, - sort: [], - }), - ignore_unavailable: true, - index: ['security-siem'], - }), - }) + ], + }, + } + `); + }); + + it('should apply the consumers filter', async () => { + const request: RuleRegistrySearchRequest = { + ruleTypeIds: ['siem.esqlRule'], + consumers: ['alerts'], + }; + + const options = {}; + const deps = { + request: {}, + }; + + getAuthorizedRuleTypesMock.mockResolvedValue([]); + getAlertIndicesAliasMock.mockReturnValue(['security-siem']); + + const strategy = ruleRegistrySearchStrategyProvider(data, alerting, logger, security, spaces); + + await lastValueFrom( + strategy.search(request, options, deps as unknown as SearchStrategyDependencies) ); + + const arg0 = searchStrategySearch.mock.calls[0][0]; + expect(arg0.params.body.query).toMatchInlineSnapshot(` + Object { + "bool": Object { + "filter": Array [ + Object { + "terms": Object { + "kibana.alert.rule.consumer": Array [ + "alerts", + ], + }, + }, + Object { + "terms": Object { + "kibana.alert.rule.rule_type_id": Array [ + "siem.esqlRule", + ], + }, + }, + ], + }, + } + `); }); }); diff --git a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts index a497008086c8..246b38aaf733 100644 --- a/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts +++ b/x-pack/plugins/rule_registry/server/search_strategy/search_strategy.ts @@ -4,28 +4,36 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { map, mergeMap, catchError } from 'rxjs'; + +import Boom from '@hapi/boom'; +import { map, mergeMap, catchError, of } from 'rxjs'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { Logger } from '@kbn/core/server'; -import { from, of } from 'rxjs'; -import { isValidFeatureId, AlertConsumers } from '@kbn/rule-data-utils'; +import { from } from 'rxjs'; import { ENHANCED_ES_SEARCH_STRATEGY } from '@kbn/data-plugin/common'; import { ISearchStrategy, PluginStart } from '@kbn/data-plugin/server'; import { ReadOperations, - PluginStartContract as AlertingStart, + AlertingServerStart, AlertingAuthorizationEntity, } from '@kbn/alerting-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; import { buildAlertFieldsRequest } from '@kbn/alerts-as-data-utils'; +import { partition } from 'lodash'; +import { isSiemRuleType } from '@kbn/rule-data-utils'; +import { KbnSearchError } from '@kbn/data-plugin/server/search/report_search_error'; import type { RuleRegistrySearchRequest, RuleRegistrySearchResponse } from '../../common'; import { MAX_ALERT_SEARCH_SIZE } from '../../common/constants'; import { AlertAuditAction, alertAuditEvent } from '..'; import { getSpacesFilter, getAuthzFilter } from '../lib'; +import { getRuleTypeIdsFilter } from '../lib/get_rule_type_ids_filter'; +import { getConsumersFilter } from '../lib/get_consumers_filter'; export const EMPTY_RESPONSE: RuleRegistrySearchResponse = { - rawResponse: {} as RuleRegistrySearchResponse['rawResponse'], + rawResponse: { + hits: { total: 0, hits: [] }, + } as unknown as RuleRegistrySearchResponse['rawResponse'], }; export const RULE_SEARCH_STRATEGY_NAME = 'privateRuleRegistryAlertsSearchStrategy'; @@ -35,7 +43,7 @@ const EXCLUDED_RULE_TYPE_IDS = ['siem.notifications']; export const ruleRegistrySearchStrategyProvider = ( data: PluginStart, - alerting: AlertingStart, + alerting: AlertingServerStart, logger: Logger, security?: SecurityPluginSetup, spaces?: SpacesPluginStart @@ -44,57 +52,69 @@ export const ruleRegistrySearchStrategyProvider = ( const requestUserEs = data.search.getSearchStrategy(ENHANCED_ES_SEARCH_STRATEGY); return { search: (request, options, deps) => { + let params = {}; + // SIEM uses RBAC fields in their alerts but also utilizes ES DLS which // is different than every other solution so we need to special case // those requests. - let siemRequest = false; - let params = {}; - if (request.featureIds.length === 1 && request.featureIds[0] === AlertConsumers.SIEM) { - siemRequest = true; - } else if (request.featureIds.includes(AlertConsumers.SIEM)) { - throw new Error( - `The ${RULE_SEARCH_STRATEGY_NAME} search strategy is unable to accommodate requests containing multiple feature IDs and one of those IDs is SIEM.` + const isAnyRuleTypeESAuthorized = request.ruleTypeIds.some(isSiemRuleType); + const isEachRuleTypeESAuthorized = + // every returns true for empty arrays + request.ruleTypeIds.length > 0 && request.ruleTypeIds.every(isSiemRuleType); + + const registeredRuleTypes = alerting.listTypes(); + + const [validRuleTypeIds, invalidRuleTypeIds] = partition(request.ruleTypeIds, (ruleTypeId) => + registeredRuleTypes.has(ruleTypeId) + ); + + if (isAnyRuleTypeESAuthorized && !isEachRuleTypeESAuthorized) { + throw new KbnSearchError( + `The ${RULE_SEARCH_STRATEGY_NAME} search strategy is unable to accommodate requests containing multiple rule types with mixed authorization.`, + 400 ); } - request.featureIds.forEach((featureId) => { - if (!isValidFeatureId(featureId)) { - logger.warn( - `Found invalid feature '${featureId}' while using ${RULE_SEARCH_STRATEGY_NAME} search strategy. No alert data from this feature will be searched.` - ); - } + + invalidRuleTypeIds.forEach((ruleTypeId) => { + logger.warn( + `Found invalid rule type '${ruleTypeId}' while using ${RULE_SEARCH_STRATEGY_NAME} search strategy. No alert data from this rule type will be searched.` + ); }); const securityAuditLogger = security?.audit.asScoped(deps.request); const getActiveSpace = async () => spaces?.spacesService.getActiveSpace(deps.request); - const getAsync = async (featureIds: string[]) => { + + const getAsync = async (ruleTypeIds: string[]) => { const [space, authorization] = await Promise.all([ getActiveSpace(), alerting.getAlertingAuthorizationWithRequest(deps.request), ]); + let authzFilter; - const fIds = new Set(featureIds); - if (!siemRequest && featureIds.length > 0) { + + if (!isAnyRuleTypeESAuthorized && ruleTypeIds.length > 0) { authzFilter = (await getAuthzFilter( authorization, - ReadOperations.Find, - fIds + ReadOperations.Find )) as estypes.QueryDslQueryContainer; } - const authorizedRuleTypes = - featureIds.length > 0 - ? await authorization.getAuthorizedRuleTypes(AlertingAuthorizationEntity.Alert, fIds) - : []; + const authorizedRuleTypes = await authorization.getAllAuthorizedRuleTypesFindOperation({ + authorizationEntity: AlertingAuthorizationEntity.Alert, + ruleTypeIds, + }); return { space, authzFilter, authorizedRuleTypes }; }; - return from(getAsync(request.featureIds)).pipe( + return from(getAsync(validRuleTypeIds)).pipe( mergeMap(({ space, authzFilter, authorizedRuleTypes }) => { - const allRuleTypes = authorizedRuleTypes.map((art: { id: string }) => art.id); - const ruleTypes = (allRuleTypes ?? []).filter( + const authorizedRuleTypesIds = Array.from(authorizedRuleTypes.keys()); + const ruleTypes = (authorizedRuleTypesIds ?? []).filter( (ruleTypeId: string) => !EXCLUDED_RULE_TYPE_IDS.includes(ruleTypeId) ); + const indices = alerting.getAlertIndicesAlias(ruleTypes, space?.id); + if (indices.length === 0) { return of(EMPTY_RESPONSE); } @@ -104,13 +124,26 @@ export const ruleRegistrySearchStrategyProvider = ( ? request.query?.bool?.filter : [request.query?.bool?.filter] : []; + if (authzFilter) { filter.push(authzFilter); } + if (space?.id) { filter.push(getSpacesFilter(space.id) as estypes.QueryDslQueryContainer); } + const ruleTypeFilter = getRuleTypeIdsFilter(request.ruleTypeIds); + const consumersFilter = getConsumersFilter(request.consumers); + + if (consumersFilter) { + filter.push(consumersFilter); + } + + if (ruleTypeFilter) { + filter.push(ruleTypeFilter); + } + const sort = request.sort ?? []; const query = { @@ -123,10 +156,11 @@ export const ruleRegistrySearchStrategyProvider = ( }, }), }; + let fields = request?.fields ?? []; fields.push({ field: 'kibana.alert.*', include_unmapped: false }); - if (siemRequest) { + if (isAnyRuleTypeESAuthorized) { fields.push({ field: 'signal.*', include_unmapped: false }); fields = fields.concat(buildAlertFieldsRequest([], false)); } else { @@ -149,7 +183,7 @@ export const ruleRegistrySearchStrategyProvider = ( ...(request.runtimeMappings ? { runtime_mappings: request.runtimeMappings } : {}), }, }; - return (siemRequest ? requestUserEs : internalUserEs).search( + return (isAnyRuleTypeESAuthorized ? requestUserEs : internalUserEs).search( { id: request.id, params }, options, deps @@ -180,7 +214,6 @@ export const ruleRegistrySearchStrategyProvider = ( return response; }), catchError((err) => { - // check if auth error, if yes, write to ecs logger if (securityAuditLogger != null && err?.output?.statusCode === 403) { securityAuditLogger.log( alertAuditEvent({ @@ -191,7 +224,15 @@ export const ruleRegistrySearchStrategyProvider = ( ); } - throw err; + if (Boom.isBoom(err)) { + throw new KbnSearchError(err.output.payload.message, err.output.statusCode); + } + + if (err instanceof KbnSearchError) { + throw err; + } + + throw new KbnSearchError(err.message, 500); }) ); }, diff --git a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts index afdc63712ba8..9900c889ae73 100644 --- a/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts +++ b/x-pack/plugins/rule_registry/server/utils/create_persistence_rule_type_wrapper.ts @@ -570,7 +570,9 @@ export const createPersistenceRuleTypeWrapper: CreatePersistenceRuleTypeWrapper const bulkResponse = await ruleDataClientWriter.bulk({ body: [...duplicateAlertUpdates, ...mapAlertsToBulkCreate(augmentedAlerts)], - refresh: true, + // On serverless we can force a refresh to we don't wait for the longer refresh interval + // When too many refresh calls are done in a short period of time, they are throttled by stateless Elasticsearch + refresh: options.isServerless ? true : 'wait_for', }); if (bulkResponse == null) { diff --git a/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts b/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts index 357703c7b752..ca7291e2fc2e 100644 --- a/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts +++ b/x-pack/plugins/rule_registry/server/utils/rule_executor.test_helpers.ts @@ -99,4 +99,5 @@ export const createDefaultAlertExecutorOptions = < const date = new Date(Date.now()).toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }); diff --git a/x-pack/plugins/search_assistant/public/plugin.tsx b/x-pack/plugins/search_assistant/public/plugin.tsx index 15c1443045cd..ef65f256d7b3 100644 --- a/x-pack/plugins/search_assistant/public/plugin.tsx +++ b/x-pack/plugins/search_assistant/public/plugin.tsx @@ -54,8 +54,9 @@ export class SearchAssistantPlugin pluginsStart, }); const isEnabled = appService.isEnabled(); + const aiAssistantIsEnabled = coreStart.application.capabilities.observabilityAIAssistant?.show; - if (!isEnabled) { + if (!isEnabled || !aiAssistantIsEnabled) { return {}; } diff --git a/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx b/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx index cdd773f4e6a8..e84ca5bd47be 100644 --- a/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx +++ b/x-pack/plugins/search_indices/public/components/index_documents/add_documents_code_example.tsx @@ -60,7 +60,7 @@ export const AddDocumentsCodeExample = ({ generateSampleDocument(codeSampleMappings, `Example text ${num}`) ); }, [codeSampleMappings]); - const { apiKey, apiKeyIsVisible } = useSearchApiKey(); + const { apiKey } = useSearchApiKey(); const codeParams: IngestCodeSnippetParameters = useMemo(() => { return { indexName, @@ -68,17 +68,9 @@ export const AddDocumentsCodeExample = ({ sampleDocuments, indexHasMappings, mappingProperties: codeSampleMappings, - apiKey: apiKeyIsVisible && apiKey ? apiKey : undefined, + apiKey: apiKey || undefined, }; - }, [ - indexName, - elasticsearchUrl, - sampleDocuments, - codeSampleMappings, - indexHasMappings, - apiKeyIsVisible, - apiKey, - ]); + }, [indexName, elasticsearchUrl, sampleDocuments, codeSampleMappings, indexHasMappings, apiKey]); return ( <EuiPanel diff --git a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx index cdd5f1240848..9df28ccec4bd 100644 --- a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx +++ b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stat.tsx @@ -18,6 +18,7 @@ import { EuiText, useEuiTheme, useGeneratedHtmlId, + EuiIconTip, } from '@elastic/eui'; interface BaseQuickStatProps { @@ -33,6 +34,7 @@ interface BaseQuickStatProps { }>; setOpen: (open: boolean) => void; first?: boolean; + tooltipContent?: string; } export const QuickStat: React.FC<BaseQuickStatProps> = ({ @@ -45,6 +47,7 @@ export const QuickStat: React.FC<BaseQuickStatProps> = ({ secondaryTitle, iconColor, content, + tooltipContent, ...rest }) => { const { euiTheme } = useEuiTheme(); @@ -93,6 +96,11 @@ export const QuickStat: React.FC<BaseQuickStatProps> = ({ {secondaryTitle} </EuiText> </EuiFlexItem> + {tooltipContent && ( + <EuiFlexItem> + <EuiIconTip content={tooltipContent} /> + </EuiFlexItem> + )} </EuiFlexGroup> </EuiPanel> } diff --git a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx index e051fee17d2e..de1ebe0a8dcc 100644 --- a/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx +++ b/x-pack/plugins/search_indices/public/components/quick_stats/quick_stats.tsx @@ -28,6 +28,7 @@ export interface QuickStatsProps { index: Index; mappings: Mappings; indexDocuments: IndexDocuments; + tooltipContent?: string; } export const SetupAISearchButton: React.FC = () => { @@ -107,6 +108,10 @@ export const QuickStats: React.FC<QuickStatsProps> = ({ index, mappings, indexDo description: index.size ?? '0b', }, ]} + tooltipContent={i18n.translate('xpack.searchIndices.quickStats.documentCountTooltip', { + defaultMessage: + 'This excludes nested documents, which Elasticsearch uses internally to store chunks of vectors.', + })} first /> </EuiFlexItem> diff --git a/x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx b/x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx index 14e9162fb970..c169179bf298 100644 --- a/x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx +++ b/x-pack/plugins/search_indices/public/components/shared/create_index_code_view.tsx @@ -44,15 +44,15 @@ export const CreateIndexCodeView = ({ const selectedCodeExamples = useCreateIndexCodingExamples(); const elasticsearchUrl = useElasticsearchUrl(); - const { apiKey, apiKeyIsVisible } = useSearchApiKey(); + const { apiKey } = useSearchApiKey(); const codeParams = useMemo(() => { return { indexName: indexName || undefined, elasticsearchURL: elasticsearchUrl, - apiKey: apiKeyIsVisible && apiKey ? apiKey : undefined, + apiKey: apiKey || undefined, }; - }, [indexName, elasticsearchUrl, apiKeyIsVisible, apiKey]); + }, [indexName, elasticsearchUrl, apiKey]); const selectedCodeExample = useMemo(() => { return selectedCodeExamples[selectedLanguage]; }, [selectedLanguage, selectedCodeExamples]); diff --git a/x-pack/plugins/search_inference_endpoints/common/doc_links.ts b/x-pack/plugins/search_inference_endpoints/common/doc_links.ts index bb426180a36e..483803e970d8 100644 --- a/x-pack/plugins/search_inference_endpoints/common/doc_links.ts +++ b/x-pack/plugins/search_inference_endpoints/common/doc_links.ts @@ -15,7 +15,7 @@ class InferenceEndpointsDocLinks { constructor() {} setDocLinks(newDocLinks: DocLinks) { - this.createInferenceEndpoint = newDocLinks.enterpriseSearch.inferenceApiCreate; + this.createInferenceEndpoint = newDocLinks.inferenceManagement.inferenceAPIDocumentation; this.semanticSearchElser = newDocLinks.enterpriseSearch.elser; this.semanticSearchE5 = newDocLinks.enterpriseSearch.e5Model; } diff --git a/x-pack/plugins/search_inference_endpoints/common/translations.ts b/x-pack/plugins/search_inference_endpoints/common/translations.ts index 0f1aa4a8abcf..8b63725c59f9 100644 --- a/x-pack/plugins/search_inference_endpoints/common/translations.ts +++ b/x-pack/plugins/search_inference_endpoints/common/translations.ts @@ -26,49 +26,6 @@ export const MANAGE_INFERENCE_ENDPOINTS_LABEL = i18n.translate( } ); -export const CREATE_FIRST_INFERENCE_ENDPOINT_DESCRIPTION = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.createFirstInferenceEndpointDescription', - { - defaultMessage: - "Inference endpoints enable you to perform inference tasks using NLP models provided by third-party services or Elastic's built-in models like ELSER and E5. Set up tasks such as text embedding, completions, reranking, and more by using the Create Inference API.", - } -); - -export const START_WITH_PREPARED_ENDPOINTS_LABEL = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.startWithPreparedEndpointsLabel', - { - defaultMessage: 'Learn more about built-in NLP models:', - } -); - -export const ELSER_TITLE = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.elserTitle', - { - defaultMessage: 'ELSER', - } -); - -export const LEARN_HOW_TO_CREATE_INFERENCE_ENDPOINTS_LINK = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.learnHowToCreateInferenceEndpoints', - { - defaultMessage: 'Learn how to create inference endpoints', - } -); - -export const SEMANTIC_SEARCH_WITH_ELSER_LINK = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithElser', - { - defaultMessage: 'Semantic search with ELSER', - } -); - -export const SEMANTIC_SEARCH_WITH_E5_LINK = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithE5', - { - defaultMessage: 'Semantic search with E5 Multilingual', - } -); - export const VIEW_YOUR_MODELS_LINK = i18n.translate( 'xpack.searchInferenceEndpoints.viewYourModels', { @@ -83,25 +40,6 @@ export const API_DOCUMENTATION_LINK = i18n.translate( } ); -export const ELSER_DESCRIPTION = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.elserDescription', - { - defaultMessage: "ELSER is Elastic's sparse vector NLP model for semantic search in English.", - } -); - -export const E5_TITLE = i18n.translate('xpack.searchInferenceEndpoints.addEmptyPrompt.e5Title', { - defaultMessage: 'E5 Multilingual', -}); - -export const E5_DESCRIPTION = i18n.translate( - 'xpack.searchInferenceEndpoints.addEmptyPrompt.e5Description', - { - defaultMessage: - 'E5 is a third-party NLP model that enables you to perform multilingual semantic search by using dense vector representations.', - } -); - export const ERROR_TITLE = i18n.translate('xpack.searchInferenceEndpoints.inferenceId.errorTitle', { defaultMessage: 'Error adding inference endpoint', }); diff --git a/x-pack/plugins/search_inference_endpoints/kibana.jsonc b/x-pack/plugins/search_inference_endpoints/kibana.jsonc index f535a9df27e9..25b7b391b955 100644 --- a/x-pack/plugins/search_inference_endpoints/kibana.jsonc +++ b/x-pack/plugins/search_inference_endpoints/kibana.jsonc @@ -24,6 +24,7 @@ "optionalPlugins": [ "cloud", "console", + "serverless" ], "requiredBundles": [ "kibanaReact" diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/constants.ts b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/constants.ts index 7ce1e578f1db..931994c46afc 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/constants.ts +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/constants.ts @@ -34,3 +34,4 @@ export const DEFAULT_INFERENCE_ENDPOINTS_TABLE_STATE: AllInferenceEndpointsTable }; export const PIPELINE_URL = 'ingest/ingest_pipelines'; +export const SERVERLESS_INDEX_MANAGEMENT_URL = 'index_details'; diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/multi_select_filter.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/multi_select_filter.tsx index 790bb5ec0991..371b204e0acd 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/multi_select_filter.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/multi_select_filter.tsx @@ -33,6 +33,7 @@ interface UseFilterParams { options: MultiSelectFilterOption[]; renderOption?: (option: MultiSelectFilterOption) => React.ReactNode; selectedOptionKeys?: string[]; + dataTestSubj?: string; } export const MultiSelectFilter: React.FC<UseFilterParams> = ({ @@ -41,6 +42,7 @@ export const MultiSelectFilter: React.FC<UseFilterParams> = ({ options: rawOptions, selectedOptionKeys = [], renderOption, + dataTestSubj, }) => { const { euiTheme } = useEuiTheme(); const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -55,7 +57,7 @@ export const MultiSelectFilter: React.FC<UseFilterParams> = ({ ); return ( - <EuiFilterGroup> + <EuiFilterGroup data-test-subj={dataTestSubj}> <EuiPopover ownFocus button={ diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/service_provider_filter.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/service_provider_filter.tsx index 3d7f9568428e..56420f98bfac 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/service_provider_filter.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/service_provider_filter.tsx @@ -38,6 +38,7 @@ export const ServiceProviderFilter: React.FC<Props> = ({ optionKeys, onChange }) options={options} renderOption={(option) => option.label} selectedOptionKeys={optionKeys} + dataTestSubj="service-field-endpoints" /> ); }; diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/task_type_filter.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/task_type_filter.tsx index e9c32503dba7..071069a880b3 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/task_type_filter.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/filter/task_type_filter.tsx @@ -38,6 +38,7 @@ export const TaskTypeFilter: React.FC<Props> = ({ optionKeys, onChange }) => { options={options} renderOption={(option) => option.label} selectedOptionKeys={optionKeys} + dataTestSubj="type-field-endpoints" /> ); }; diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/index_item.test.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/index_item.test.tsx new file mode 100644 index 000000000000..bfdc1edd31bd --- /dev/null +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/index_item.test.tsx @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { render, fireEvent, screen } from '@testing-library/react'; +import React from 'react'; + +import { IndexItem } from './index_item'; +import { InferenceUsageInfo } from '../../../../types'; +import { useKibana } from '../../../../../../hooks/use_kibana'; + +jest.mock('../../../../../../hooks/use_kibana'); +const mockUseKibana = useKibana as jest.Mock; +const mockNavigateToApp = jest.fn(); + +describe('Index Item', () => { + const item: InferenceUsageInfo = { + id: 'index-1', + type: 'Index', + }; + beforeEach(() => { + mockUseKibana.mockReturnValue({ + services: { + application: { + navigateToApp: mockNavigateToApp, + }, + }, + }); + + render(<IndexItem usageItem={item} />); + }); + + it('renders', () => { + expect(screen.getByText('index-1')).toBeInTheDocument(); + expect(screen.getByText('Index')).toBeInTheDocument(); + }); + + it('opens index in a new tab', () => { + fireEvent.click(screen.getByRole('button')); + expect(mockNavigateToApp).toHaveBeenCalledWith('enterpriseSearchContent', { + openInNewTab: true, + path: 'search_indices/index-1', + }); + }); +}); diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/usage_item.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/index_item.tsx similarity index 77% rename from x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/usage_item.tsx rename to x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/index_item.tsx index 577b9f8aa0e2..a62a9b9f3cae 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/usage_item.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/index_item.tsx @@ -16,34 +16,35 @@ import { EuiIcon, EuiSpacer, } from '@elastic/eui'; -import React from 'react'; +import React, { useCallback } from 'react'; import { ENTERPRISE_SEARCH_CONTENT_APP_ID } from '@kbn/deeplinks-search'; -import { MANAGEMENT_APP_ID } from '@kbn/deeplinks-management/constants'; + +import { SEARCH_INDICES } from '@kbn/deeplinks-search/constants'; import { useKibana } from '../../../../../../hooks/use_kibana'; import { InferenceUsageInfo } from '../../../../types'; -import { PIPELINE_URL } from '../../../../constants'; +import { SERVERLESS_INDEX_MANAGEMENT_URL } from '../../../../constants'; interface UsageProps { usageItem: InferenceUsageInfo; } -export const UsageItem: React.FC<UsageProps> = ({ usageItem }) => { +export const IndexItem: React.FC<UsageProps> = ({ usageItem }) => { const { - services: { application }, + services: { application, serverless }, } = useKibana(); - const handleNavigateToIndex = () => { - if (usageItem.type === 'Index') { - application?.navigateToApp(ENTERPRISE_SEARCH_CONTENT_APP_ID, { - path: `search_indices/${usageItem.id}`, + const navigateToIndex = useCallback(() => { + if (serverless) { + application?.navigateToApp(SEARCH_INDICES, { + path: `${SERVERLESS_INDEX_MANAGEMENT_URL}/${usageItem.id}/data`, openInNewTab: true, }); - } else if (usageItem.type === 'Pipeline') { - application?.navigateToApp(MANAGEMENT_APP_ID, { - path: `${PIPELINE_URL}?pipeline=${usageItem.id}`, + } else { + application?.navigateToApp(ENTERPRISE_SEARCH_CONTENT_APP_ID, { + path: `search_indices/${usageItem.id}`, openInNewTab: true, }); } - }; + }, [application, serverless, usageItem.id]); return ( <EuiFlexGroup gutterSize="s" direction="column" data-test-subj="usageItem"> @@ -62,7 +63,7 @@ export const UsageItem: React.FC<UsageProps> = ({ usageItem }) => { </EuiFlexGroup> </EuiFlexItem> <EuiFlexItem grow={false}> - <EuiLink data-test-subj="navigateToIndexPage" onClick={handleNavigateToIndex}> + <EuiLink data-test-subj="navigateToIndexPage" onClick={navigateToIndex}> <EuiIcon size="s" type="popout" /> </EuiLink> </EuiFlexItem> diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/list_usage_results.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/list_usage_results.tsx index d42b0f673525..05aaaa8bb9ea 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/list_usage_results.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/list_usage_results.tsx @@ -10,7 +10,8 @@ import { EuiFieldSearch, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { InferenceUsageInfo } from '../../../../types'; import * as i18n from '../delete/confirm_delete_endpoint/translations'; -import { UsageItem } from './usage_item'; +import { IndexItem } from './index_item'; +import { PipelineItem } from './pipeline_item'; interface ListUsageResultsProps { list: InferenceUsageInfo[]; @@ -35,9 +36,13 @@ export const ListUsageResults: React.FC<ListUsageResultsProps> = ({ list }) => { <EuiFlexItem> {list .filter((item) => item.id.toLowerCase().includes(term.toLowerCase())) - .map((item, id) => ( - <UsageItem usageItem={item} key={id} /> - ))} + .map((item, id) => { + if (item.type === 'Pipeline') { + return <PipelineItem usageItem={item} key={id} />; + } else { + return <IndexItem usageItem={item} key={id} />; + } + })} </EuiFlexItem> </EuiFlexGroup> ); diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/usage_item.test.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/pipeline_item.test.tsx similarity index 59% rename from x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/usage_item.test.tsx rename to x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/pipeline_item.test.tsx index 6c6899c71922..8a1bc7a78cab 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/usage_item.test.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/pipeline_item.test.tsx @@ -8,7 +8,7 @@ import { render, fireEvent, screen } from '@testing-library/react'; import React from 'react'; -import { UsageItem } from './usage_item'; +import { PipelineItem } from './pipeline_item'; import { InferenceUsageInfo } from '../../../../types'; import { useKibana } from '../../../../../../hooks/use_kibana'; @@ -16,7 +16,11 @@ jest.mock('../../../../../../hooks/use_kibana'); const mockUseKibana = useKibana as jest.Mock; const mockNavigateToApp = jest.fn(); -describe('UsageItem', () => { +describe('Pipeline item', () => { + const item: InferenceUsageInfo = { + id: 'pipeline-1', + type: 'Pipeline', + }; beforeEach(() => { mockUseKibana.mockReturnValue({ services: { @@ -25,41 +29,10 @@ describe('UsageItem', () => { }, }, }); - }); - - describe('index', () => { - const item: InferenceUsageInfo = { - id: 'index-1', - type: 'Index', - }; - - beforeEach(() => { - render(<UsageItem usageItem={item} />); - }); - - it('renders', () => { - expect(screen.getByText('index-1')).toBeInTheDocument(); - expect(screen.getByText('Index')).toBeInTheDocument(); - }); - - it('opens index in a new tab', () => { - fireEvent.click(screen.getByRole('button')); - expect(mockNavigateToApp).toHaveBeenCalledWith('enterpriseSearchContent', { - openInNewTab: true, - path: 'search_indices/index-1', - }); - }); + render(<PipelineItem usageItem={item} />); }); describe('pipeline', () => { - const item: InferenceUsageInfo = { - id: 'pipeline-1', - type: 'Pipeline', - }; - - beforeEach(() => { - render(<UsageItem usageItem={item} />); - }); it('renders', () => { expect(screen.getByText('pipeline-1')).toBeInTheDocument(); expect(screen.getByText('Pipeline')).toBeInTheDocument(); diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/pipeline_item.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/pipeline_item.tsx new file mode 100644 index 000000000000..1a2e8ead2908 --- /dev/null +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/pipeline_item.tsx @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { + EuiBadge, + EuiFlexGroup, + EuiFlexItem, + EuiHorizontalRule, + EuiLink, + EuiText, + EuiTextTruncate, + EuiIcon, + EuiSpacer, +} from '@elastic/eui'; +import React, { useCallback } from 'react'; +import { MANAGEMENT_APP_ID } from '@kbn/deeplinks-management/constants'; + +import { useKibana } from '../../../../../../hooks/use_kibana'; +import { InferenceUsageInfo } from '../../../../types'; +import { PIPELINE_URL } from '../../../../constants'; + +interface UsageProps { + usageItem: InferenceUsageInfo; +} +export const PipelineItem: React.FC<UsageProps> = ({ usageItem }) => { + const { + services: { application }, + } = useKibana(); + const navigateToPipeline = useCallback(() => { + application?.navigateToApp(MANAGEMENT_APP_ID, { + path: `${PIPELINE_URL}?pipeline=${usageItem.id}`, + openInNewTab: true, + }); + }, [application, usageItem.id]); + + return ( + <EuiFlexGroup gutterSize="s" direction="column" data-test-subj="usageItem"> + <EuiFlexItem grow={false}> + <EuiFlexGroup> + <EuiFlexItem> + <EuiFlexGroup gutterSize="xs" justifyContent="spaceBetween"> + <EuiFlexItem> + <EuiText size="s"> + <EuiTextTruncate text={usageItem.id} /> + </EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiBadge color="hollow">{usageItem.type}</EuiBadge> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiLink data-test-subj="navigateToPipelinePage" onClick={navigateToPipeline}> + <EuiIcon size="s" type="popout" /> + </EuiLink> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + <EuiFlexItem> + <EuiHorizontalRule margin="none" /> + <EuiSpacer size="s" /> + </EuiFlexItem> + </EuiFlexGroup> + ); +}; diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/scan_usage_results.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/scan_usage_results.tsx index 33d7a4dae891..cab278f5e1ed 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/scan_usage_results.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/component/scan_usage_results.tsx @@ -19,6 +19,7 @@ import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/react'; import { ENTERPRISE_SEARCH_CONTENT_APP_ID } from '@kbn/deeplinks-search'; +import { SEARCH_INDICES } from '@kbn/deeplinks-search/constants'; import { InferenceUsageInfo } from '../../../../types'; import { useKibana } from '../../../../../../hooks/use_kibana'; import { RenderMessageWithIcon } from './render_message_with_icon'; @@ -37,13 +38,19 @@ export const ScanUsageResults: React.FC<ScanUsageResultsProps> = ({ onIgnoreWarningCheckboxChange, }) => { const { - services: { application }, + services: { application, serverless }, } = useKibana(); const handleNavigateToIndexManagement = () => { - application?.navigateToApp(ENTERPRISE_SEARCH_CONTENT_APP_ID, { - path: 'search_indices', - openInNewTab: true, - }); + if (serverless) { + application?.navigateToApp(SEARCH_INDICES, { + openInNewTab: true, + }); + } else { + application?.navigateToApp(ENTERPRISE_SEARCH_CONTENT_APP_ID, { + path: `search_indices`, + openInNewTab: true, + }); + } }; return ( diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/delete/confirm_delete_endpoint/index.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/delete/confirm_delete_endpoint/index.tsx index 06bd585c0eb2..345f0f81b092 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/delete/confirm_delete_endpoint/index.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/render_table_columns/render_actions/actions/delete/confirm_delete_endpoint/index.tsx @@ -86,6 +86,7 @@ export const ConfirmDeleteEndpointModal: React.FC<ConfirmDeleteEndpointModalProp font-family: ${euiThemeVars.euiCodeFontFamily}; font-weight: ${euiThemeVars.euiCodeFontWeightBold}; `} + data-test-subj="deleteModalInferenceEndpointName" > {inferenceEndpoint.endpoint} </EuiText> diff --git a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/tabular_page.tsx b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/tabular_page.tsx index 4cf4b3112396..0ea17fa6408a 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/tabular_page.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/all_inference_endpoints/tabular_page.tsx @@ -52,6 +52,7 @@ export const TabularPage: React.FC<TabularPageProps> = ({ inferenceEndpoints }) { field: 'endpoint', name: i18n.ENDPOINT, + 'data-test-subj': 'endpointCell', render: (endpoint: string) => { if (endpoint) { return <EndpointInfo inferenceId={endpoint} />; @@ -65,6 +66,7 @@ export const TabularPage: React.FC<TabularPageProps> = ({ inferenceEndpoints }) { field: 'provider', name: i18n.SERVICE_PROVIDER, + 'data-test-subj': 'providerCell', render: (provider: InferenceAPIConfigResponse) => { if (provider) { return <ServiceProvider providerEndpoint={provider} />; @@ -78,6 +80,7 @@ export const TabularPage: React.FC<TabularPageProps> = ({ inferenceEndpoints }) { field: 'type', name: i18n.TASK_TYPE, + 'data-test-subj': 'typeCell', render: (type: TaskTypes) => { if (type) { return <TaskType type={type} />; @@ -149,6 +152,7 @@ export const TabularPage: React.FC<TabularPageProps> = ({ inferenceEndpoints }) onChange={handleTableChange} pagination={pagination} sorting={sorting} + data-test-subj="inferenceEndpointTable" /> </EuiFlexItem> </EuiFlexGroup> diff --git a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.scss b/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.scss deleted file mode 100644 index b85859948b0b..000000000000 --- a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.scss +++ /dev/null @@ -1,3 +0,0 @@ -.addEmptyPrompt { - max-width: 860px; -} \ No newline at end of file diff --git a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.test.tsx b/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.test.tsx deleted file mode 100644 index 755c1f0a1de5..000000000000 --- a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.test.tsx +++ /dev/null @@ -1,47 +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 { screen } from '@testing-library/react'; -import { AddEmptyPrompt } from './add_empty_prompt'; - -import { renderReactTestingLibraryWithI18n as render } from '@kbn/test-jest-helpers'; -import '@testing-library/jest-dom'; - -describe('When empty prompt is loaded', () => { - beforeEach(() => { - render(<AddEmptyPrompt />); - }); - - it('should display the description for creation of the first inference endpoint', () => { - expect( - screen.getByText( - /Inference endpoints enable you to perform inference tasks using NLP models provided by third-party services/ - ) - ).toBeInTheDocument(); - }); - - it('should have a learn-more link', () => { - const learnMoreLink = screen.getByTestId('learn-how-to-create-inference-endpoints'); - expect(learnMoreLink).toBeInTheDocument(); - }); - - it('should have a view-your-models link', () => { - const learnMoreLink = screen.getByTestId('view-your-models'); - expect(learnMoreLink).toBeInTheDocument(); - }); - - it('should have a semantic-search-with-elser link', () => { - const learnMoreLink = screen.getByTestId('semantic-search-with-elser'); - expect(learnMoreLink).toBeInTheDocument(); - }); - - it('should have a semantic-search-with-e5 link', () => { - const learnMoreLink = screen.getByTestId('semantic-search-with-e5'); - expect(learnMoreLink).toBeInTheDocument(); - }); -}); diff --git a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.tsx b/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.tsx deleted file mode 100644 index 782994975ada..000000000000 --- a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/add_empty_prompt.tsx +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; - -import { - EuiPageTemplate, - EuiFlexGroup, - EuiFlexItem, - EuiImage, - EuiSpacer, - EuiLink, -} from '@elastic/eui'; -import { docLinks } from '../../../common/doc_links'; - -import * as i18n from '../../../common/translations'; - -import inferenceEndpoint from '../../assets/images/inference_endpoint.svg'; - -import { EndpointPrompt } from './endpoint_prompt'; -import { useTrainedModelPageUrl } from '../../hooks/use_trained_model_page_url'; - -import './add_empty_prompt.scss'; - -export const AddEmptyPrompt: React.FC = () => { - const trainedModelPageUrl = useTrainedModelPageUrl(); - - return ( - <EuiPageTemplate.EmptyPrompt - layout="horizontal" - restrictWidth - color="plain" - hasShadow - icon={<EuiImage size="fullWidth" src={inferenceEndpoint} alt="" />} - title={<h2>{i18n.INFERENCE_ENDPOINT_LABEL}</h2>} - body={ - <EuiFlexGroup direction="column"> - <EuiFlexItem data-test-subj="createFirstInferenceEndpointDescription"> - {i18n.CREATE_FIRST_INFERENCE_ENDPOINT_DESCRIPTION} - </EuiFlexItem> - <EuiFlexItem> - <EuiLink - href={docLinks.createInferenceEndpoint} - target="_blank" - data-test-subj="learn-how-to-create-inference-endpoints" - > - {i18n.LEARN_HOW_TO_CREATE_INFERENCE_ENDPOINTS_LINK} - </EuiLink> - </EuiFlexItem> - <EuiFlexItem> - <EuiLink href={trainedModelPageUrl} target="_blank" data-test-subj="view-your-models"> - {i18n.VIEW_YOUR_MODELS_LINK} - </EuiLink> - </EuiFlexItem> - </EuiFlexGroup> - } - footer={ - <EuiFlexGroup gutterSize="xs" direction="column"> - <EuiFlexItem> - <strong>{i18n.START_WITH_PREPARED_ENDPOINTS_LABEL}</strong> - </EuiFlexItem> - <EuiSpacer size="s" /> - <EuiFlexGroup> - <EuiFlexItem> - <EndpointPrompt - title={i18n.ELSER_TITLE} - description={i18n.ELSER_DESCRIPTION} - footer={ - <EuiLink - href={docLinks.semanticSearchElser} - target="_blank" - data-test-subj="semantic-search-with-elser" - > - {i18n.SEMANTIC_SEARCH_WITH_ELSER_LINK} - </EuiLink> - } - /> - </EuiFlexItem> - <EuiFlexItem> - <EndpointPrompt - title={i18n.E5_TITLE} - description={i18n.E5_DESCRIPTION} - footer={ - <EuiLink - href={docLinks.semanticSearchE5} - target="_blank" - data-test-subj="semantic-search-with-e5" - > - {i18n.SEMANTIC_SEARCH_WITH_E5_LINK} - </EuiLink> - } - /> - </EuiFlexItem> - </EuiFlexGroup> - </EuiFlexGroup> - } - /> - ); -}; diff --git a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/endpoint_prompt.tsx b/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/endpoint_prompt.tsx deleted file mode 100644 index aa6ff9d582e1..000000000000 --- a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/endpoint_prompt.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import React from 'react'; -import { EuiCard } from '@elastic/eui'; - -interface EndpointPromptProps { - title: string; - description: string; - footer: React.ReactElement; -} - -export const EndpointPrompt: React.FC<EndpointPromptProps> = ({ title, description, footer }) => ( - <EuiCard - display="plain" - textAlign="left" - data-test-subj="multilingualE5PromptForEmptyState" - title={title} - titleSize="xs" - description={description} - footer={footer} - /> -); diff --git a/x-pack/plugins/search_inference_endpoints/public/components/inference_endpoints.tsx b/x-pack/plugins/search_inference_endpoints/public/components/inference_endpoints.tsx index e1dae72d402f..c39bc69fc300 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/inference_endpoints.tsx +++ b/x-pack/plugins/search_inference_endpoints/public/components/inference_endpoints.tsx @@ -11,7 +11,6 @@ import { EuiPageTemplate } from '@elastic/eui'; import { useQueryInferenceEndpoints } from '../hooks/use_inference_endpoints'; import { TabularPage } from './all_inference_endpoints/tabular_page'; -import { AddEmptyPrompt } from './empty_prompt/add_empty_prompt'; import { InferenceEndpointsHeader } from './inference_endpoints_header'; export const InferenceEndpoints: React.FC = () => { @@ -21,13 +20,9 @@ export const InferenceEndpoints: React.FC = () => { return ( <> - {inferenceEndpoints.length > 0 && <InferenceEndpointsHeader />} - <EuiPageTemplate.Section className="eui-yScroll"> - {inferenceEndpoints.length === 0 ? ( - <AddEmptyPrompt /> - ) : ( - <TabularPage inferenceEndpoints={inferenceEndpoints} /> - )} + <InferenceEndpointsHeader /> + <EuiPageTemplate.Section className="eui-yScroll" data-test-subj="inferenceManagementPage"> + <TabularPage inferenceEndpoints={inferenceEndpoints} /> </EuiPageTemplate.Section> </> ); diff --git a/x-pack/plugins/search_inference_endpoints/public/locators.ts b/x-pack/plugins/search_inference_endpoints/public/locators.ts new file mode 100644 index 000000000000..5b32e5648cc7 --- /dev/null +++ b/x-pack/plugins/search_inference_endpoints/public/locators.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { LocatorDefinition } from '@kbn/share-plugin/common'; +import type { SharePluginSetup } from '@kbn/share-plugin/public'; +import type { SerializableRecord } from '@kbn/utility-types'; + +import { PLUGIN_ID } from '../common/constants'; +import { SEARCH_INFERENCE_ENDPOINTS_PATH } from './routes'; + +export function registerLocators(share: SharePluginSetup) { + share.url.locators.create<SerializableRecord>(new SearchInferenceEndpointLocatorDefinition()); +} + +class SearchInferenceEndpointLocatorDefinition implements LocatorDefinition<SerializableRecord> { + public readonly getLocation = async () => { + return { + app: PLUGIN_ID, + path: SEARCH_INFERENCE_ENDPOINTS_PATH, + state: {}, + }; + }; + + public readonly id = 'SEARCH_INFERENCE_ENDPOINTS'; +} diff --git a/x-pack/plugins/search_inference_endpoints/public/plugin.ts b/x-pack/plugins/search_inference_endpoints/public/plugin.ts index a864b7c0fcdd..cb60f611b3bb 100644 --- a/x-pack/plugins/search_inference_endpoints/public/plugin.ts +++ b/x-pack/plugins/search_inference_endpoints/public/plugin.ts @@ -12,16 +12,20 @@ import { Plugin, PluginInitializerContext, } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; import { PLUGIN_ID, PLUGIN_NAME } from '../common/constants'; import { docLinks } from '../common/doc_links'; import { InferenceEndpoints, getInferenceEndpointsProvider } from './embeddable'; import { + AppPluginSetupDependencies, AppPluginStartDependencies, SearchInferenceEndpointsConfigType, SearchInferenceEndpointsPluginSetup, SearchInferenceEndpointsPluginStart, } from './types'; import { INFERENCE_ENDPOINTS_UI_FLAG } from '.'; +import { registerLocators } from './locators'; +import { INFERENCE_ENDPOINTS_PATH } from './components/routes'; export class SearchInferenceEndpointsPlugin implements Plugin<SearchInferenceEndpointsPluginSetup, SearchInferenceEndpointsPluginStart> @@ -33,7 +37,8 @@ export class SearchInferenceEndpointsPlugin } public setup( - core: CoreSetup<AppPluginStartDependencies, SearchInferenceEndpointsPluginStart> + core: CoreSetup<AppPluginStartDependencies, SearchInferenceEndpointsPluginStart>, + plugins: AppPluginSetupDependencies ): SearchInferenceEndpointsPluginSetup { if ( !this.config.ui?.enabled && @@ -42,7 +47,16 @@ export class SearchInferenceEndpointsPlugin return {}; core.application.register({ id: PLUGIN_ID, - appRoute: '/app/search_inference_endpoints', + appRoute: '/app/elasticsearch/relevance', + deepLinks: [ + { + id: 'inferenceEndpoints', + path: `/${INFERENCE_ENDPOINTS_PATH}`, + title: i18n.translate('xpack.searchInferenceEndpoints.InferenceEndpointsLinkLabel', { + defaultMessage: 'Inference Endpoints', + }), + }, + ], title: PLUGIN_NAME, async mount({ element, history }: AppMountParameters) { const { renderApp } = await import('./application'); @@ -56,6 +70,8 @@ export class SearchInferenceEndpointsPlugin }, }); + registerLocators(plugins.share); + return {}; } diff --git a/x-pack/plugins/search_inference_endpoints/public/types.ts b/x-pack/plugins/search_inference_endpoints/public/types.ts index 4bd83521cf8d..9f73d0d0033b 100644 --- a/x-pack/plugins/search_inference_endpoints/public/types.ts +++ b/x-pack/plugins/search_inference_endpoints/public/types.ts @@ -5,12 +5,14 @@ * 2.0. */ -import type { ConsolePluginStart } from '@kbn/console-plugin/public'; +import type { ConsolePluginSetup, ConsolePluginStart } from '@kbn/console-plugin/public'; import { HttpStart } from '@kbn/core-http-browser'; import { AppMountParameters } from '@kbn/core/public'; import { MlPluginStart } from '@kbn/ml-plugin/public'; -import { SharePluginStart } from '@kbn/share-plugin/public'; +import { SharePluginSetup, SharePluginStart } from '@kbn/share-plugin/public'; import React from 'react'; + +import type { ServerlessPluginStart } from '@kbn/serverless/public'; import type { App } from './components/app'; import type { InferenceEndpointsProvider } from './providers/inference_endpoints_provider'; @@ -27,12 +29,21 @@ export interface AppPluginStartDependencies { history: AppMountParameters['history']; share: SharePluginStart; console?: ConsolePluginStart; + serverless?: ServerlessPluginStart; +} + +export interface AppPluginSetupDependencies { + history: AppMountParameters['history']; + share: SharePluginSetup; + console?: ConsolePluginSetup; } export interface AppServicesContext { http: HttpStart; ml?: MlPluginStart; console?: ConsolePluginStart; + serverless?: ServerlessPluginStart; + share: SharePluginStart; } export interface InferenceUsageResponse { diff --git a/x-pack/plugins/search_inference_endpoints/tsconfig.json b/x-pack/plugins/search_inference_endpoints/tsconfig.json index d454be99b65f..9a5b160779e7 100644 --- a/x-pack/plugins/search_inference_endpoints/tsconfig.json +++ b/x-pack/plugins/search_inference_endpoints/tsconfig.json @@ -33,7 +33,9 @@ "@kbn/features-plugin", "@kbn/ui-theme", "@kbn/deeplinks-search", - "@kbn/deeplinks-management" + "@kbn/deeplinks-management", + "@kbn/serverless", + "@kbn/utility-types" ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/search_playground/kibana.jsonc b/x-pack/plugins/search_playground/kibana.jsonc index 37562347e9f3..3c4eaaddc81a 100644 --- a/x-pack/plugins/search_playground/kibana.jsonc +++ b/x-pack/plugins/search_playground/kibana.jsonc @@ -18,6 +18,7 @@ "actions", "data", "encryptedSavedObjects", + "ml", "navigation", "share", "security", diff --git a/x-pack/plugins/search_playground/public/components/select_indices_flyout.test.tsx b/x-pack/plugins/search_playground/public/components/select_indices_flyout.test.tsx index 246d7b2ebf24..59a606fddafd 100644 --- a/x-pack/plugins/search_playground/public/components/select_indices_flyout.test.tsx +++ b/x-pack/plugins/search_playground/public/components/select_indices_flyout.test.tsx @@ -49,6 +49,7 @@ describe('SelectIndicesFlyout', () => { mockedUseQueryIndices.mockReturnValue({ indices: ['index1', 'index2', 'index3'], isLoading: false, + isFetched: true, }); }); diff --git a/x-pack/plugins/search_playground/public/components/select_indices_flyout.tsx b/x-pack/plugins/search_playground/public/components/select_indices_flyout.tsx index d98a6fc9de8b..fa3868cb392c 100644 --- a/x-pack/plugins/search_playground/public/components/select_indices_flyout.tsx +++ b/x-pack/plugins/search_playground/public/components/select_indices_flyout.tsx @@ -35,7 +35,7 @@ interface SelectIndicesFlyout { export const SelectIndicesFlyout: React.FC<SelectIndicesFlyout> = ({ onClose }) => { const [query, setQuery] = useState<string>(''); - const { indices, isLoading: isIndicesLoading } = useQueryIndices(query); + const { indices, isLoading: isIndicesLoading } = useQueryIndices({ query }); const { indices: selectedIndices, setIndices: setSelectedIndices } = useSourceIndicesFields(); const [selectedTempIndices, setSelectedTempIndices] = useState<string[]>(selectedIndices); const handleSelectOptions = (options: EuiSelectableOption[]) => { diff --git a/x-pack/plugins/search_playground/public/hooks/use_indices_validation.ts b/x-pack/plugins/search_playground/public/hooks/use_indices_validation.ts new file mode 100644 index 000000000000..45b3848bb85e --- /dev/null +++ b/x-pack/plugins/search_playground/public/hooks/use_indices_validation.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useState } from 'react'; +import { useQueryIndices } from './use_query_indices'; + +export const useIndicesValidation = (unvalidatedIndices: string[]) => { + const [isValidated, setIsValidated] = useState<boolean>(false); + const [validIndices, setValidIndices] = useState<string[]>([]); + const { indices, isFetched: isIndicesLoaded } = useQueryIndices({ + query: unvalidatedIndices.join(','), + exact: true, + }); + + useEffect(() => { + if (isIndicesLoaded) { + setValidIndices(indices.filter((index) => unvalidatedIndices.includes(index))); + setIsValidated(true); + } + }, [unvalidatedIndices, indices, isIndicesLoaded]); + + return { isValidated, validIndices }; +}; diff --git a/x-pack/plugins/search_playground/public/hooks/use_query_indices.ts b/x-pack/plugins/search_playground/public/hooks/use_query_indices.ts index d011b471a68d..cc5812306097 100644 --- a/x-pack/plugins/search_playground/public/hooks/use_query_indices.ts +++ b/x-pack/plugins/search_playground/public/hooks/use_query_indices.ts @@ -11,26 +11,41 @@ import { useKibana } from './use_kibana'; import { APIRoutes } from '../types'; export const useQueryIndices = ( - query: string = '' -): { indices: IndexName[]; isLoading: boolean } => { + { + query, + exact, + }: { + query?: string; + exact?: boolean; + } = { query: '', exact: false } +): { indices: IndexName[]; isLoading: boolean; isFetched: boolean } => { const { services } = useKibana(); - const { data, isLoading } = useQuery({ + const { data, isLoading, isFetched } = useQuery({ queryKey: ['indices', query], queryFn: async () => { - const response = await services.http.get<{ - indices: string[]; - }>(APIRoutes.GET_INDICES, { - query: { - search_query: query, - size: 10, - }, - }); + try { + const response = await services.http.get<{ + indices: string[]; + }>(APIRoutes.GET_INDICES, { + query: { + search_query: query, + exact, + size: 50, + }, + }); - return response.indices; + return response.indices; + } catch (err) { + if (err?.response?.status === 404) { + return []; + } + + throw err; + } }, initialData: [], }); - return { indices: data, isLoading }; + return { indices: data, isLoading, isFetched }; }; diff --git a/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx b/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx index 96c86ad18493..e0205f01f1e6 100644 --- a/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx +++ b/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx @@ -19,6 +19,9 @@ jest.mock('../hooks/use_llms_models'); jest.mock('react-router-dom-v5-compat', () => ({ useSearchParams: jest.fn(() => [{ get: jest.fn() }]), })); +jest.mock('../hooks/use_indices_validation', () => ({ + useIndicesValidation: jest.fn((indices) => ({ isValidated: true, validIndices: indices })), +})); let formHookSpy: jest.SpyInstance; @@ -216,6 +219,7 @@ describe('FormProvider', () => { }); it('updates indices from search params', async () => { + expect.assertions(1); const mockSearchParams = new URLSearchParams(); mockSearchParams.get = jest.fn().mockReturnValue('new-index'); mockUseSearchParams.mockReturnValue([mockSearchParams]); @@ -237,10 +241,12 @@ describe('FormProvider', () => { </FormProvider> ); - const { getValues } = formHookSpy.mock.results[0].value; + await act(async () => { + const { getValues } = formHookSpy.mock.results[0].value; - await waitFor(() => { - expect(getValues(ChatFormFields.indices)).toEqual(['new-index']); + await waitFor(() => { + expect(getValues(ChatFormFields.indices)).toEqual(['new-index']); + }); }); }); }); diff --git a/x-pack/plugins/search_playground/public/providers/form_provider.tsx b/x-pack/plugins/search_playground/public/providers/form_provider.tsx index f352688fe89f..e1b27e66a98d 100644 --- a/x-pack/plugins/search_playground/public/providers/form_provider.tsx +++ b/x-pack/plugins/search_playground/public/providers/form_provider.tsx @@ -7,6 +7,7 @@ import { FormProvider as ReactHookFormProvider, useForm } from 'react-hook-form'; import React, { useEffect, useMemo } from 'react'; import { useSearchParams } from 'react-router-dom-v5-compat'; +import { useIndicesValidation } from '../hooks/use_indices_validation'; import { useLoadFieldsByIndices } from '../hooks/use_load_fields_by_indices'; import { ChatForm, ChatFormFields } from '../types'; import { useLLMsModels } from '../hooks/use_llms_models'; @@ -53,16 +54,27 @@ export const FormProvider: React.FC<React.PropsWithChildren<FormProviderProps>> }) => { const models = useLLMsModels(); const [searchParams] = useSearchParams(); - const index = useMemo(() => searchParams.get('default-index'), [searchParams]); + const defaultIndex = useMemo(() => { + const index = searchParams.get('default-index'); + + return index ? [index] : null; + }, [searchParams]); const sessionState = useMemo(() => getLocalSession(storage), [storage]); const form = useForm<ChatForm>({ defaultValues: { ...sessionState, - indices: index ? [index] : sessionState.indices, + indices: [], search_query: '', }, }); - useLoadFieldsByIndices({ watch: form.watch, setValue: form.setValue, getValues: form.getValues }); + const { isValidated: isValidatedIndices, validIndices } = useIndicesValidation( + defaultIndex || sessionState.indices || [] + ); + useLoadFieldsByIndices({ + watch: form.watch, + setValue: form.setValue, + getValues: form.getValues, + }); useEffect(() => { const subscription = form.watch((values) => @@ -80,5 +92,11 @@ export const FormProvider: React.FC<React.PropsWithChildren<FormProviderProps>> } }, [form, models]); + useEffect(() => { + if (isValidatedIndices) { + form.setValue(ChatFormFields.indices, validIndices); + } + }, [form, isValidatedIndices, validIndices]); + return <ReactHookFormProvider {...form}>{children}</ReactHookFormProvider>; }; diff --git a/x-pack/plugins/search_playground/server/lib/fetch_indices.ts b/x-pack/plugins/search_playground/server/lib/fetch_indices.ts index 51b72790028c..c60e6b508261 100644 --- a/x-pack/plugins/search_playground/server/lib/fetch_indices.ts +++ b/x-pack/plugins/search_playground/server/lib/fetch_indices.ts @@ -21,11 +21,12 @@ function isClosed(index: IndicesIndexState): boolean { export const fetchIndices = async ( client: ElasticsearchClient, - searchQuery: string | undefined + searchQuery: string | undefined, + { exact }: { exact?: boolean } = { exact: false } ): Promise<{ indexNames: string[]; }> => { - const indexPattern = searchQuery ? `*${searchQuery}*` : '*'; + const indexPattern = exact && searchQuery ? searchQuery : searchQuery ? `*${searchQuery}*` : '*'; const allIndexMatches = await client.indices.get({ expand_wildcards: ['open'], // for better performance only compute aliases and settings of indices but not mappings diff --git a/x-pack/plugins/search_playground/server/routes.ts b/x-pack/plugins/search_playground/server/routes.ts index 3cdebe11c02c..115b55d34146 100644 --- a/x-pack/plugins/search_playground/server/routes.ts +++ b/x-pack/plugins/search_playground/server/routes.ts @@ -198,17 +198,17 @@ export function defineRoutes({ query: schema.object({ search_query: schema.maybe(schema.string()), size: schema.number({ defaultValue: 10, min: 0 }), + exact: schema.maybe(schema.boolean({ defaultValue: false })), }), }, }, errorHandler(logger)(async (context, request, response) => { - const { search_query: searchQuery, size } = request.query; + const { search_query: searchQuery, exact, size } = request.query; const { client: { asCurrentUser }, } = (await context.core).elasticsearch; - const { indexNames } = await fetchIndices(asCurrentUser, searchQuery); - + const { indexNames } = await fetchIndices(asCurrentUser, searchQuery, { exact }); const indexNameSlice = indexNames.slice(0, size).filter(isNotNullish); return response.ok({ diff --git a/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx b/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx index e78ed371468f..ec0c12aa3bc1 100644 --- a/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx +++ b/x-pack/plugins/security/public/account_management/user_profile/user_profile.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, renderHook } from '@testing-library/react'; import { mount } from 'enzyme'; import type { FC, PropsWithChildren } from 'react'; import React from 'react'; diff --git a/x-pack/plugins/security/public/components/use_badge.test.tsx b/x-pack/plugins/security/public/components/use_badge.test.tsx index 07d026123530..643ebeffa899 100644 --- a/x-pack/plugins/security/public/components/use_badge.test.tsx +++ b/x-pack/plugins/security/public/components/use_badge.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { coreMock } from '@kbn/core/public/mocks'; diff --git a/x-pack/plugins/security/public/components/use_capabilities.test.tsx b/x-pack/plugins/security/public/components/use_capabilities.test.tsx index 5e8491199a5d..8a5a8eb3ebda 100644 --- a/x-pack/plugins/security/public/components/use_capabilities.test.tsx +++ b/x-pack/plugins/security/public/components/use_capabilities.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import React from 'react'; import { coreMock } from '@kbn/core/public/mocks'; diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts index 19378bfd8488..72b9e44da3f4 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.test.ts @@ -26,6 +26,7 @@ describe('Security UsageCollector', () => { allowAccessAgreement = true, allowAuditLogging = true, allowRbac = true, + allowFips = true, isLicenseAvailable, }: Partial<SecurityLicenseFeatures> & { isLicenseAvailable: boolean }) => { const license = licenseMock.create(); @@ -34,6 +35,7 @@ describe('Security UsageCollector', () => { allowAccessAgreement, allowAuditLogging, allowRbac, + allowFips, } as SecurityLicenseFeatures); return license; }; @@ -44,6 +46,7 @@ describe('Security UsageCollector', () => { accessAgreementEnabled: false, authProviderCount: 1, enabledAuthProviders: ['basic'], + fipsModeEnabled: false, loginSelectorEnabled: false, httpAuthSchemes: ['apikey', 'bearer'], sessionIdleTimeoutInMinutes: 4320, @@ -106,6 +109,7 @@ describe('Security UsageCollector', () => { accessAgreementEnabled: false, authProviderCount: 0, enabledAuthProviders: [], + fipsModeEnabled: false, loginSelectorEnabled: false, httpAuthSchemes: [], sessionIdleTimeoutInMinutes: 0, @@ -426,6 +430,55 @@ describe('Security UsageCollector', () => { }); }); + describe('fipsMode enabled', () => { + it('reports when fipsMode is enabled', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + fipsMode: { + enabled: true, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ + isLicenseAvailable: true, + allowFips: true, + }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(collectorFetchContext); + + expect(usage).toEqual({ + ...DEFAULT_USAGE, + fipsModeEnabled: true, + }); + }); + + it('does not report fipsMode when the license does not permit it', async () => { + const config = createSecurityConfig( + ConfigSchema.validate({ + fipsMode: { + enabled: true, + }, + }) + ); + const usageCollection = usageCollectionPluginMock.createSetupContract(); + const license = createSecurityLicense({ isLicenseAvailable: true, allowFips: false }); + registerSecurityUsageCollector({ usageCollection, config, license }); + + const usage = await usageCollection + .getCollectorByType('security') + ?.fetch(collectorFetchContext); + + expect(usage).toEqual({ + ...DEFAULT_USAGE, + fipsModeEnabled: false, + }); + }); + }); + describe('http auth schemes', () => { it('reports customized http auth schemes', async () => { const config = createSecurityConfig( diff --git a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts index fc761fb13a50..575fea2bf32c 100644 --- a/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts +++ b/x-pack/plugins/security/server/usage_collector/security_usage_collector.ts @@ -16,6 +16,7 @@ interface Usage { accessAgreementEnabled: boolean; authProviderCount: number; enabledAuthProviders: string[]; + fipsModeEnabled: boolean; httpAuthSchemes: string[]; sessionIdleTimeoutInMinutes: number; sessionLifespanInMinutes: number; @@ -93,6 +94,12 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens }, }, }, + fipsModeEnabled: { + type: 'boolean', + _meta: { + description: 'Indicates if Kibana is being run in FIPS mode.', + }, + }, httpAuthSchemes: { type: 'array', items: { @@ -139,7 +146,8 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens }, }, fetch: () => { - const { allowRbac, allowAccessAgreement, allowAuditLogging } = license.getFeatures(); + const { allowRbac, allowAccessAgreement, allowAuditLogging, allowFips } = + license.getFeatures(); if (!allowRbac) { return { auditLoggingEnabled: false, @@ -147,6 +155,7 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens accessAgreementEnabled: false, authProviderCount: 0, enabledAuthProviders: [], + fipsModeEnabled: false, httpAuthSchemes: [], sessionIdleTimeoutInMinutes: 0, sessionLifespanInMinutes: 0, @@ -171,6 +180,8 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens WELL_KNOWN_AUTH_SCHEMES.includes(scheme.toLowerCase()) ); + const fipsModeEnabled = allowFips && config.fipsMode.enabled; + const sessionExpirations = config.session.getExpirationTimeouts(undefined); // use `undefined` to get global expiration values const sessionIdleTimeoutInMinutes = sessionExpirations.idleTimeout?.asMinutes() ?? 0; const sessionLifespanInMinutes = sessionExpirations.lifespan?.asMinutes() ?? 0; @@ -202,6 +213,7 @@ export function registerSecurityUsageCollector({ usageCollection, config, licens accessAgreementEnabled, authProviderCount, enabledAuthProviders, + fipsModeEnabled, httpAuthSchemes, sessionIdleTimeoutInMinutes, sessionLifespanInMinutes, diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts index 7e419dbe6453..25c47e838d85 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.gen.ts @@ -39,6 +39,37 @@ export const EngineDescriptor = z.object({ error: z.object({}).optional(), }); +export type EngineComponentResource = z.infer<typeof EngineComponentResource>; +export const EngineComponentResource = z.enum([ + 'entity_engine', + 'entity_definition', + 'index', + 'component_template', + 'index_template', + 'ingest_pipeline', + 'enrich_policy', + 'task', + 'transform', +]); +export type EngineComponentResourceEnum = typeof EngineComponentResource.enum; +export const EngineComponentResourceEnum = EngineComponentResource.enum; + +export type EngineComponentStatus = z.infer<typeof EngineComponentStatus>; +export const EngineComponentStatus = z.object({ + id: z.string(), + installed: z.boolean(), + resource: EngineComponentResource, + health: z.enum(['green', 'yellow', 'red', 'unknown']).optional(), + errors: z + .array( + z.object({ + title: z.string().optional(), + message: z.string().optional(), + }) + ) + .optional(), +}); + export type StoreStatus = z.infer<typeof StoreStatus>; export const StoreStatus = z.enum(['not_installed', 'installing', 'running', 'stopped', 'error']); export type StoreStatusEnum = typeof StoreStatus.enum; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml index 9a42191a556a..5adb6fe038dc 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/common.schema.yaml @@ -42,6 +42,49 @@ components: - updating - error + EngineComponentStatus: + type: object + required: + - id + - installed + - resource + properties: + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/EngineComponentResource' + health: + type: string + enum: + - green + - yellow + - red + - unknown + errors: + type: array + items: + type: object + properties: + title: + type: string + message: + type: string + + EngineComponentResource: + type: string + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + StoreStatus: type: string enum: diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.gen.ts similarity index 78% rename from x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.gen.ts rename to x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.gen.ts index 9644a1a333d1..70a58bf02be6 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.gen.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.gen.ts @@ -16,13 +16,7 @@ import { z } from '@kbn/zod'; -import { IndexPattern, EngineDescriptor, StoreStatus } from './common.gen'; - -export type GetEntityStoreStatusResponse = z.infer<typeof GetEntityStoreStatusResponse>; -export const GetEntityStoreStatusResponse = z.object({ - status: StoreStatus.optional(), - engines: z.array(EngineDescriptor).optional(), -}); +import { IndexPattern, EngineDescriptor } from './common.gen'; export type InitEntityStoreRequestBody = z.infer<typeof InitEntityStoreRequestBody>; export const InitEntityStoreRequestBody = z.object({ diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.schema.yaml similarity index 65% rename from x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.schema.yaml rename to x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.schema.yaml index 306e876dfc4a..81eec22d9ade 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enablement.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/enable.schema.yaml @@ -41,24 +41,3 @@ paths: type: array items: $ref: './common.schema.yaml#/components/schemas/EngineDescriptor' - - /api/entity_store/status: - get: - x-labels: [ess, serverless] - x-codegen-enabled: true - operationId: GetEntityStoreStatus - summary: Get the status of the Entity Store - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - properties: - status: - $ref: './common.schema.yaml#/components/schemas/StoreStatus' - engines: - type: array - items: - $ref: './common.schema.yaml#/components/schemas/EngineDescriptor' diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts index b21308de36f1..32bc0a4efc07 100644 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/index.ts @@ -10,6 +10,5 @@ export * from './get.gen'; export * from './init.gen'; export * from './list.gen'; export * from './start.gen'; -export * from './stats.gen'; export * from './stop.gen'; export * from './apply_dataview_indices.gen'; diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.gen.ts deleted file mode 100644 index 8b2cb4494753..000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.gen.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -/* - * NOTICE: Do not edit this file manually. - * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. - * - * info: - * title: Get Entity Engine stats - * version: 2023-10-31 - */ - -import { z } from '@kbn/zod'; - -import { EntityType, IndexPattern, EngineStatus } from '../common.gen'; - -export type GetEntityEngineStatsRequestParams = z.infer<typeof GetEntityEngineStatsRequestParams>; -export const GetEntityEngineStatsRequestParams = z.object({ - /** - * The entity type of the engine (either 'user' or 'host'). - */ - entityType: EntityType, -}); -export type GetEntityEngineStatsRequestParamsInput = z.input< - typeof GetEntityEngineStatsRequestParams ->; - -export type GetEntityEngineStatsResponse = z.infer<typeof GetEntityEngineStatsResponse>; -export const GetEntityEngineStatsResponse = z.object({ - type: EntityType.optional(), - indexPattern: IndexPattern.optional(), - status: EngineStatus.optional(), - transforms: z.array(z.object({})).optional(), - indices: z.array(z.object({})).optional(), -}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.schema.yaml deleted file mode 100644 index 25c010acc92c..000000000000 --- a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/engine/stats.schema.yaml +++ /dev/null @@ -1,41 +0,0 @@ -openapi: 3.0.0 - -info: - title: Get Entity Engine stats - version: '2023-10-31' -paths: - /api/entity_store/engines/{entityType}/stats: - post: - x-labels: [ess, serverless] - x-codegen-enabled: true - operationId: GetEntityEngineStats - summary: Get Entity Engine stats - parameters: - - name: entityType - in: path - required: true - schema: - $ref: '../common.schema.yaml#/components/schemas/EntityType' - description: The entity type of the engine (either 'user' or 'host'). - responses: - '200': - description: Successful response - content: - application/json: - schema: - type: object - properties: - type: - $ref : '../common.schema.yaml#/components/schemas/EntityType' - indexPattern: - $ref : '../common.schema.yaml#/components/schemas/IndexPattern' - status: - $ref : '../common.schema.yaml#/components/schemas/EngineStatus' - transforms: - type: array - items: - type: object - indices: - type: array - items: - type: object diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.gen.ts b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.gen.ts new file mode 100644 index 000000000000..76249a787a43 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.gen.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + * + * info: + * title: Enable Entity Store + * version: 2023-10-31 + */ + +import { z } from '@kbn/zod'; +import { BooleanFromString } from '@kbn/zod-helpers'; + +import { StoreStatus, EngineDescriptor, EngineComponentStatus } from './common.gen'; + +export type GetEntityStoreStatusRequestQuery = z.infer<typeof GetEntityStoreStatusRequestQuery>; +export const GetEntityStoreStatusRequestQuery = z.object({ + /** + * If true returns a detailed status of the engine including all it's components + */ + include_components: BooleanFromString.optional(), +}); +export type GetEntityStoreStatusRequestQueryInput = z.input< + typeof GetEntityStoreStatusRequestQuery +>; + +export type GetEntityStoreStatusResponse = z.infer<typeof GetEntityStoreStatusResponse>; +export const GetEntityStoreStatusResponse = z.object({ + status: StoreStatus, + engines: z.array( + EngineDescriptor.merge( + z.object({ + components: z.array(EngineComponentStatus).optional(), + }) + ) + ), +}); diff --git a/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.schema.yaml b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.schema.yaml new file mode 100644 index 000000000000..a1be66282328 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/entity_analytics/entity_store/status.schema.yaml @@ -0,0 +1,44 @@ +openapi: 3.0.0 + +info: + title: Enable Entity Store + version: '2023-10-31' +paths: + /api/entity_store/status: + get: + x-labels: [ess, serverless] + x-codegen-enabled: true + operationId: GetEntityStoreStatus + summary: Get the status of the Entity Store + + parameters: + - name: include_components + in: query + schema: + type: boolean + description: If true returns a detailed status of the engine including all it's components + + responses: + '200': + description: Successful response + content: + application/json: + schema: + type: object + required: + - status + - engines + properties: + status: + $ref: './common.schema.yaml#/components/schemas/StoreStatus' + engines: + type: array + items: + allOf: + - $ref: './common.schema.yaml#/components/schemas/EngineDescriptor' + - type: object + properties: + components: + type: array + items: + $ref: './common.schema.yaml#/components/schemas/EngineComponentStatus' diff --git a/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts b/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts index 5a1cf49baecd..d86a04f343a8 100644 --- a/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts +++ b/x-pack/plugins/security_solution/common/api/quickstart_client.gen.ts @@ -232,10 +232,9 @@ import type { UploadAssetCriticalityRecordsResponse, } from './entity_analytics/asset_criticality/upload_asset_criticality_csv.gen'; import type { - GetEntityStoreStatusResponse, InitEntityStoreRequestBodyInput, InitEntityStoreResponse, -} from './entity_analytics/entity_store/enablement.gen'; +} from './entity_analytics/entity_store/enable.gen'; import type { ApplyEntityEngineDataviewIndicesResponse } from './entity_analytics/entity_store/engine/apply_dataview_indices.gen'; import type { DeleteEntityEngineRequestQueryInput, @@ -257,10 +256,6 @@ import type { StartEntityEngineRequestParamsInput, StartEntityEngineResponse, } from './entity_analytics/entity_store/engine/start.gen'; -import type { - GetEntityEngineStatsRequestParamsInput, - GetEntityEngineStatsResponse, -} from './entity_analytics/entity_store/engine/stats.gen'; import type { StopEntityEngineRequestParamsInput, StopEntityEngineResponse, @@ -269,6 +264,10 @@ import type { ListEntitiesRequestQueryInput, ListEntitiesResponse, } from './entity_analytics/entity_store/entities/list_entities.gen'; +import type { + GetEntityStoreStatusRequestQueryInput, + GetEntityStoreStatusResponse, +} from './entity_analytics/entity_store/status.gen'; import type { CleanUpRiskEngineResponse } from './entity_analytics/risk_engine/engine_cleanup_route.gen'; import type { DisableRiskEngineResponse } from './entity_analytics/risk_engine/engine_disable_route.gen'; import type { EnableRiskEngineResponse } from './entity_analytics/risk_engine/engine_enable_route.gen'; @@ -360,6 +359,11 @@ import type { GetRuleMigrationResourcesResponse, GetRuleMigrationStatsRequestParamsInput, GetRuleMigrationStatsResponse, + InstallMigrationRulesRequestParamsInput, + InstallMigrationRulesRequestBodyInput, + InstallMigrationRulesResponse, + InstallTranslatedMigrationRulesRequestParamsInput, + InstallTranslatedMigrationRulesResponse, StartRuleMigrationRequestParamsInput, StartRuleMigrationRequestBodyInput, StartRuleMigrationResponse, @@ -1290,19 +1294,7 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } - async getEntityEngineStats(props: GetEntityEngineStatsProps) { - this.log.info(`${new Date().toISOString()} Calling API GetEntityEngineStats`); - return this.kbnClient - .request<GetEntityEngineStatsResponse>({ - path: replaceParams('/api/entity_store/engines/{entityType}/stats', props.params), - headers: { - [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', - }, - method: 'POST', - }) - .catch(catchAxiosErrorFormatAndThrow); - } - async getEntityStoreStatus() { + async getEntityStoreStatus(props: GetEntityStoreStatusProps) { this.log.info(`${new Date().toISOString()} Calling API GetEntityStoreStatus`); return this.kbnClient .request<GetEntityStoreStatusResponse>({ @@ -1311,6 +1303,8 @@ finalize it. [ELASTIC_HTTP_VERSION_HEADER]: '2023-10-31', }, method: 'GET', + + query: props.query, }) .catch(catchAxiosErrorFormatAndThrow); } @@ -1570,6 +1564,22 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } + /** + * Installs migration rules + */ + async installMigrationRules(props: InstallMigrationRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API InstallMigrationRules`); + return this.kbnClient + .request<InstallMigrationRulesResponse>({ + path: replaceParams('/internal/siem_migrations/rules/{migration_id}/install', props.params), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + body: props.body, + }) + .catch(catchAxiosErrorFormatAndThrow); + } /** * Install and update all Elastic prebuilt detection rules and Timelines. */ @@ -1601,6 +1611,24 @@ finalize it. }) .catch(catchAxiosErrorFormatAndThrow); } + /** + * Installs all translated migration rules + */ + async installTranslatedMigrationRules(props: InstallTranslatedMigrationRulesProps) { + this.log.info(`${new Date().toISOString()} Calling API InstallTranslatedMigrationRules`); + return this.kbnClient + .request<InstallTranslatedMigrationRulesResponse>({ + path: replaceParams( + '/internal/siem_migrations/rules/{migration_id}/install_translated', + props.params + ), + headers: { + [ELASTIC_HTTP_VERSION_HEADER]: '1', + }, + method: 'POST', + }) + .catch(catchAxiosErrorFormatAndThrow); + } async internalUploadAssetCriticalityRecords(props: InternalUploadAssetCriticalityRecordsProps) { this.log.info(`${new Date().toISOString()} Calling API InternalUploadAssetCriticalityRecords`); return this.kbnClient @@ -2285,8 +2313,8 @@ export interface GetEndpointSuggestionsProps { export interface GetEntityEngineProps { params: GetEntityEngineRequestParamsInput; } -export interface GetEntityEngineStatsProps { - params: GetEntityEngineStatsRequestParamsInput; +export interface GetEntityStoreStatusProps { + query: GetEntityStoreStatusRequestQueryInput; } export interface GetNotesProps { query: GetNotesRequestQueryInput; @@ -2335,9 +2363,16 @@ export interface InitEntityEngineProps { export interface InitEntityStoreProps { body: InitEntityStoreRequestBodyInput; } +export interface InstallMigrationRulesProps { + params: InstallMigrationRulesRequestParamsInput; + body: InstallMigrationRulesRequestBodyInput; +} export interface InstallPrepackedTimelinesProps { body: InstallPrepackedTimelinesRequestBodyInput; } +export interface InstallTranslatedMigrationRulesProps { + params: InstallTranslatedMigrationRulesRequestParamsInput; +} export interface InternalUploadAssetCriticalityRecordsProps { attachment: FormData; } diff --git a/x-pack/plugins/security_solution/common/endpoint/types/workflow_insights.ts b/x-pack/plugins/security_solution/common/endpoint/types/workflow_insights.ts new file mode 100644 index 000000000000..11cbc1bfd7cd --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/types/workflow_insights.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Moment } from 'moment'; + +import type { DefendInsightType } from '@kbn/elastic-assistant-common'; +import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +export enum Category { + Endpoint = 'endpoint', +} + +export enum SourceType { + LlmConnector = 'llm-connector', +} + +export enum TargetType { + Endpoint = 'endpoint', +} + +export enum ActionType { + Refreshed = 'refreshed', // new or refreshed + Remediated = 'remediated', + Suppressed = 'suppressed', // temporarily supressed, can be refreshed + Dismissed = 'dismissed', // "permanently" dismissed, cannot be normally refreshed +} + +export type ExceptionListRemediationType = Pick< + ExceptionListItemSchema, + 'list_id' | 'name' | 'description' | 'entries' | 'tags' | 'os_types' +>; + +export interface SecurityWorkflowInsight { + id?: string; + '@timestamp': Moment; + message: string; + category: Category; + type: DefendInsightType; + source: { + type: SourceType; + id: string; + data_range_start: Moment; + data_range_end: Moment; + }; + target: { + type: TargetType; + ids: string[]; + }; + action: { + type: ActionType; + timestamp: Moment; + }; + value: string; + remediation: { + exception_list_items?: ExceptionListRemediationType[]; + }; + metadata: { + notes?: Record<string, string>; + message_variables?: string[]; + }; +} + +export interface SearchParams { + size?: number; + from?: number; + ids?: string[]; + categories?: Category[]; + types?: DefendInsightType[]; + sourceTypes?: SourceType[]; + sourceIds?: string[]; + targetTypes?: TargetType[]; + targetIds?: string[]; + actionTypes: ActionType[]; +} diff --git a/x-pack/plugins/security_solution/common/experimental_features.ts b/x-pack/plugins/security_solution/common/experimental_features.ts index 7fcdabad3b36..369735936561 100644 --- a/x-pack/plugins/security_solution/common/experimental_features.ts +++ b/x-pack/plugins/security_solution/common/experimental_features.ts @@ -15,7 +15,7 @@ export const allowedExperimentalValues = Object.freeze({ // FIXME:PT delete? excludePoliciesInFilterEnabled: false, - kubernetesEnabled: true, + kubernetesEnabled: false, donutChartEmbeddablesEnabled: false, // Depends on https://github.com/elastic/kibana/issues/136409 item 2 - 6 /** diff --git a/x-pack/plugins/security_solution/common/siem_migrations/constants.ts b/x-pack/plugins/security_solution/common/siem_migrations/constants.ts index 8a2d6cf3775c..565091e39a8d 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/constants.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/constants.ts @@ -5,6 +5,8 @@ * 2.0. */ +import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; + export const SIEM_MIGRATIONS_PATH = '/internal/siem_migrations' as const; export const SIEM_RULE_MIGRATIONS_PATH = `${SIEM_MIGRATIONS_PATH}/rules` as const; @@ -14,9 +16,19 @@ export const SIEM_RULE_MIGRATION_START_PATH = `${SIEM_RULE_MIGRATION_PATH}/start export const SIEM_RULE_MIGRATION_RETRY_PATH = `${SIEM_RULE_MIGRATION_PATH}/retry` as const; export const SIEM_RULE_MIGRATION_STATS_PATH = `${SIEM_RULE_MIGRATION_PATH}/stats` as const; export const SIEM_RULE_MIGRATION_STOP_PATH = `${SIEM_RULE_MIGRATION_PATH}/stop` as const; +export const SIEM_RULE_MIGRATION_INSTALL_PATH = `${SIEM_RULE_MIGRATION_PATH}/install` as const; +export const SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH = + `${SIEM_RULE_MIGRATION_PATH}/install_translated` as const; export const SIEM_RULE_MIGRATION_RESOURCES_PATH = `${SIEM_RULE_MIGRATION_PATH}/resources` as const; +export enum SiemMigrationTaskStatus { + READY = 'ready', + RUNNING = 'running', + STOPPED = 'stopped', + FINISHED = 'finished', +} + export enum SiemMigrationStatus { PENDING = 'pending', PROCESSING = 'processing', @@ -29,3 +41,6 @@ export enum SiemMigrationRuleTranslationResult { PARTIAL = 'partial', UNTRANSLATABLE = 'untranslatable', } + +export const DEFAULT_TRANSLATION_RISK_SCORE = 21; +export const DEFAULT_TRANSLATION_SEVERITY: Severity = 'low'; diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts index ac15080f2e0a..77a0fc94408f 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.gen.ts @@ -22,9 +22,8 @@ import { ElasticRulePartial, RuleMigrationTranslationResult, RuleMigrationComments, - RuleMigrationAllTaskStats, - RuleMigration, RuleMigrationTaskStats, + RuleMigration, RuleMigrationResourceData, RuleMigrationResourceType, RuleMigrationResource, @@ -44,7 +43,7 @@ export const CreateRuleMigrationResponse = z.object({ }); export type GetAllStatsRuleMigrationResponse = z.infer<typeof GetAllStatsRuleMigrationResponse>; -export const GetAllStatsRuleMigrationResponse = RuleMigrationAllTaskStats; +export const GetAllStatsRuleMigrationResponse = z.array(RuleMigrationTaskStats); export type GetRuleMigrationRequestParams = z.infer<typeof GetRuleMigrationRequestParams>; export const GetRuleMigrationRequestParams = z.object({ @@ -89,6 +88,48 @@ export type GetRuleMigrationStatsRequestParamsInput = z.input< export type GetRuleMigrationStatsResponse = z.infer<typeof GetRuleMigrationStatsResponse>; export const GetRuleMigrationStatsResponse = RuleMigrationTaskStats; +export type InstallMigrationRulesRequestParams = z.infer<typeof InstallMigrationRulesRequestParams>; +export const InstallMigrationRulesRequestParams = z.object({ + migration_id: NonEmptyString, +}); +export type InstallMigrationRulesRequestParamsInput = z.input< + typeof InstallMigrationRulesRequestParams +>; + +export type InstallMigrationRulesRequestBody = z.infer<typeof InstallMigrationRulesRequestBody>; +export const InstallMigrationRulesRequestBody = z.array(NonEmptyString); +export type InstallMigrationRulesRequestBodyInput = z.input< + typeof InstallMigrationRulesRequestBody +>; + +export type InstallMigrationRulesResponse = z.infer<typeof InstallMigrationRulesResponse>; +export const InstallMigrationRulesResponse = z.object({ + /** + * Indicates rules migrations have been installed. + */ + installed: z.boolean(), +}); + +export type InstallTranslatedMigrationRulesRequestParams = z.infer< + typeof InstallTranslatedMigrationRulesRequestParams +>; +export const InstallTranslatedMigrationRulesRequestParams = z.object({ + migration_id: NonEmptyString, +}); +export type InstallTranslatedMigrationRulesRequestParamsInput = z.input< + typeof InstallTranslatedMigrationRulesRequestParams +>; + +export type InstallTranslatedMigrationRulesResponse = z.infer< + typeof InstallTranslatedMigrationRulesResponse +>; +export const InstallTranslatedMigrationRulesResponse = z.object({ + /** + * Indicates rules migrations have been installed. + */ + installed: z.boolean(), +}); + export type StartRuleMigrationRequestParams = z.infer<typeof StartRuleMigrationRequestParams>; export const StartRuleMigrationRequestParams = z.object({ migration_id: NonEmptyString, @@ -168,16 +209,7 @@ export type UpsertRuleMigrationResourcesRequestParamsInput = z.input< export type UpsertRuleMigrationResourcesRequestBody = z.infer< typeof UpsertRuleMigrationResourcesRequestBody >; -export const UpsertRuleMigrationResourcesRequestBody = z.array( - RuleMigrationResourceData.merge( - z.object({ - /** - * The rule resource migration id - */ - id: NonEmptyString, - }) - ) -); +export const UpsertRuleMigrationResourcesRequestBody = z.array(RuleMigrationResourceData); export type UpsertRuleMigrationResourcesRequestBodyInput = z.input< typeof UpsertRuleMigrationResourcesRequestBody >; diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml index 778530467112..f57a809bb204 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/api/rules/rule_migration.schema.yaml @@ -10,6 +10,7 @@ paths: summary: Creates a new rule migration operationId: CreateRuleMigration x-codegen-enabled: true + x-internal: true description: Creates a new SIEM rules migration using the original vendor rules provided tags: - SIEM Rule Migrations @@ -39,6 +40,7 @@ paths: summary: Updates rules migrations operationId: UpdateRuleMigration x-codegen-enabled: true + x-internal: true description: Updates rules migrations attributes tags: - SIEM Rule Migrations @@ -79,11 +81,79 @@ paths: type: boolean description: Indicates rules migrations have been updated. + /internal/siem_migrations/rules/{migration_id}/install: + post: + summary: Installs translated migration rules + operationId: InstallMigrationRules + x-codegen-enabled: true + description: Installs migration rules + tags: + - SIEM Rule Migrations + parameters: + - name: migration_id + in: path + required: true + schema: + description: The migration id to isnstall rules for + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + description: The rule migration id + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Indicates rules migrations have been installed correctly. + content: + application/json: + schema: + type: object + required: + - installed + properties: + installed: + type: boolean + description: Indicates rules migrations have been installed. + + /internal/siem_migrations/rules/{migration_id}/install_translated: + post: + summary: Installs all translated migration rules + operationId: InstallTranslatedMigrationRules + x-codegen-enabled: true + description: Installs all translated migration rules + tags: + - SIEM Rule Migrations + parameters: + - name: migration_id + in: path + required: true + schema: + description: The migration id to install translated rules for + $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + responses: + 200: + description: Indicates rules migrations have been installed correctly. + content: + application/json: + schema: + type: object + required: + - installed + properties: + installed: + type: boolean + description: Indicates rules migrations have been installed. + /internal/siem_migrations/rules/stats: get: summary: Retrieves the stats for all rule migrations operationId: GetAllStatsRuleMigration x-codegen-enabled: true + x-internal: true description: Retrieves the rule migrations stats for all migrations stored in the system tags: - SIEM Rule Migrations @@ -93,7 +163,9 @@ paths: content: application/json: schema: - $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationAllTaskStats' + type: array + items: + $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationTaskStats' ## Specific rule migration APIs @@ -102,6 +174,7 @@ paths: summary: Retrieves all the rules of a migration operationId: GetRuleMigration x-codegen-enabled: true + x-internal: true description: Retrieves the rule documents stored in the system given the rule migration id tags: - SIEM Rule Migrations @@ -129,6 +202,7 @@ paths: summary: Starts a rule migration operationId: StartRuleMigration x-codegen-enabled: true + x-internal: true description: Starts a SIEM rules migration using the migration id provided tags: - SIEM Rule Migrations @@ -173,6 +247,7 @@ paths: summary: Gets a rule migration task stats operationId: GetRuleMigrationStats x-codegen-enabled: true + x-internal: true description: Retrieves the stats of a SIEM rules migration using the migration id provided tags: - SIEM Rule Migrations @@ -198,6 +273,7 @@ paths: summary: Stops an existing rule migration operationId: StopRuleMigration x-codegen-enabled: true + x-internal: true description: Stops a running SIEM rules migration using the migration id provided tags: - SIEM Rule Migrations @@ -231,6 +307,7 @@ paths: summary: Creates or updates rule migration resources for a migration operationId: UpsertRuleMigrationResources x-codegen-enabled: true + x-internal: true description: Creates or updates resources for an existing SIEM rules migration tags: - SIEM Rule Migrations @@ -249,15 +326,7 @@ paths: schema: type: array items: - allOf: - - $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationResourceData' - - type: object - required: - - id - properties: - id: - description: The rule resource migration id - $ref: '../../common.schema.yaml#/components/schemas/NonEmptyString' + $ref: '../../rule_migration.schema.yaml#/components/schemas/RuleMigrationResourceData' responses: 200: description: Indicates migration resources have been created or updated correctly. @@ -276,6 +345,7 @@ paths: summary: Gets rule migration resources for a migration operationId: GetRuleMigrationResources x-codegen-enabled: true + x-internal: true description: Retrieves resources for an existing SIEM rules migration tags: - SIEM Rule Migrations diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts index 38d7e2c4584b..82e3c5549fd8 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.gen.ts @@ -113,7 +113,7 @@ export type RuleMigrationTranslationResultEnum = typeof RuleMigrationTranslation export const RuleMigrationTranslationResultEnum = RuleMigrationTranslationResult.enum; /** - * The status of the rule migration process. + * The status of each rule migration. */ export type RuleMigrationStatus = z.infer<typeof RuleMigrationStatus>; export const RuleMigrationStatus = z.enum(['pending', 'processing', 'completed', 'failed']); @@ -186,15 +186,27 @@ export const RuleMigration = z }) .merge(RuleMigrationData); +/** + * The status of the migration task. + */ +export type RuleMigrationTaskStatus = z.infer<typeof RuleMigrationTaskStatus>; +export const RuleMigrationTaskStatus = z.enum(['ready', 'running', 'stopped', 'finished']); +export type RuleMigrationTaskStatusEnum = typeof RuleMigrationTaskStatus.enum; +export const RuleMigrationTaskStatusEnum = RuleMigrationTaskStatus.enum; + /** * The rule migration task stats object. */ export type RuleMigrationTaskStats = z.infer<typeof RuleMigrationTaskStats>; export const RuleMigrationTaskStats = z.object({ + /** + * The migration id + */ + id: NonEmptyString, /** * Indicates if the migration task status. */ - status: z.enum(['ready', 'running', 'stopped', 'finished']), + status: RuleMigrationTaskStatus, /** * The rules migration stats. */ @@ -220,24 +232,16 @@ export const RuleMigrationTaskStats = z.object({ */ failed: z.number().int(), }), + /** + * The moment the migration was created. + */ + created_at: z.string(), /** * The moment of the last update. */ - last_updated_at: z.string().optional(), + last_updated_at: z.string(), }); -export type RuleMigrationAllTaskStats = z.infer<typeof RuleMigrationAllTaskStats>; -export const RuleMigrationAllTaskStats = z.array( - RuleMigrationTaskStats.merge( - z.object({ - /** - * The migration id - */ - migration_id: NonEmptyString, - }) - ) -); - /** * The type of the rule migration resource. */ diff --git a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml index 552d192a641f..82892b4fa072 100644 --- a/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml +++ b/x-pack/plugins/security_solution/common/siem_migrations/model/rule_migration.schema.yaml @@ -145,17 +145,18 @@ components: type: object description: The rule migration task stats object. required: + - id - status - rules + - created_at + - last_updated_at properties: + id: + description: The migration id + $ref: './common.schema.yaml#/components/schemas/NonEmptyString' status: - type: string description: Indicates if the migration task status. - enum: - - ready - - running - - stopped - - finished + $ref: '#/components/schemas/RuleMigrationTaskStatus' rules: type: object description: The rules migration stats. @@ -181,23 +182,22 @@ components: failed: type: integer description: The number of rules that have failed migration. + created_at: + type: string + description: The moment the migration was created. last_updated_at: type: string description: The moment of the last update. - RuleMigrationAllTaskStats: - type: array - items: - allOf: - - $ref: '#/components/schemas/RuleMigrationTaskStats' - - type: object - required: - - migration_id - properties: - migration_id: - description: The migration id - $ref: './common.schema.yaml#/components/schemas/NonEmptyString' - + RuleMigrationTaskStatus: + type: string + description: The status of the migration task. + enum: # should match SiemMigrationTaskStatus enum at ../constants.ts + - ready + - running + - stopped + - finished + RuleMigrationTranslationResult: type: string description: The rule translation result. @@ -208,7 +208,7 @@ components: RuleMigrationStatus: type: string - description: The status of the rule migration process. + description: The status of each rule migration. enum: # should match SiemMigrationsStatus enum at ../constants.ts - pending - processing diff --git a/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts b/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts index 8435e6ec8984..91c426c24dc7 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/cells/index.ts @@ -13,6 +13,10 @@ import type { BrowserFields, TimelineNonEcsData } from '../../../search_strategy /** The following props are provided to the function called by `renderCellValue` */ export type CellValueElementProps = EuiDataGridCellValueElementProps & { + /** + * makes sure that field is not rendered as a plain text + * but according to the renderer. + */ asPlainText?: boolean; browserFields?: BrowserFields; data: TimelineNonEcsData[]; diff --git a/x-pack/plugins/security_solution/common/types/timeline/store.ts b/x-pack/plugins/security_solution/common/types/timeline/store.ts index c65705e0c9a7..834949d2ed59 100644 --- a/x-pack/plugins/security_solution/common/types/timeline/store.ts +++ b/x-pack/plugins/security_solution/common/types/timeline/store.ts @@ -73,7 +73,7 @@ export type OnColumnRemoved = (columnId: ColumnId) => void; export type OnColumnResized = ({ columnId, delta }: { columnId: ColumnId; delta: number }) => void; /** Invoked when a user clicks to load more item */ -export type OnChangePage = (nextPage: number) => void; +export type OnFetchMoreRecords = (nextPage: number) => void; /** Invoked when a user checks/un-checks a row */ export type OnRowSelected = ({ diff --git a/x-pack/plugins/security_solution/common/utils/field_formatters.test.ts b/x-pack/plugins/security_solution/common/utils/field_formatters.test.ts deleted file mode 100644 index 33d0c226fc44..000000000000 --- a/x-pack/plugins/security_solution/common/utils/field_formatters.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { EventHit } from '../search_strategy'; -import { getDataFromFieldsHits, getDataSafety } from './field_formatters'; -import { eventDetailsFormattedFields, eventHit } from '@kbn/securitysolution-t-grid'; - -describe('Events Details Helpers', () => { - const fields: EventHit['fields'] = eventHit.fields; - const resultFields = eventDetailsFormattedFields; - describe('#getDataFromFieldsHits', () => { - it('happy path', () => { - const result = getDataFromFieldsHits(fields); - expect(result).toEqual(resultFields); - }); - it('lets get weird', () => { - const whackFields = { - 'crazy.pants': [ - { - 'matched.field': ['matched_field'], - first_seen: ['2021-02-22T17:29:25.195Z'], - provider: ['yourself'], - type: ['custom'], - 'matched.atomic': ['matched_atomic'], - lazer: [ - { - 'great.field': ['grrrrr'], - lazer: [ - { - lazer: [ - { - cool: true, - lazer: [ - { - lazer: [ - { - lazer: [ - { - lazer: [ - { - whoa: false, - }, - ], - }, - ], - }, - ], - }, - ], - }, - ], - }, - { - lazer: [ - { - cool: false, - }, - ], - }, - ], - }, - { - 'great.field': ['grrrrr_2'], - }, - ], - }, - ], - }; - const whackResultFields = [ - { - category: 'crazy', - field: 'crazy.pants', - values: [ - '{"matched.field":["matched_field"],"first_seen":["2021-02-22T17:29:25.195Z"],"provider":["yourself"],"type":["custom"],"matched.atomic":["matched_atomic"],"lazer":[{"great.field":["grrrrr"],"lazer":[{"lazer":[{"cool":true,"lazer":[{"lazer":[{"lazer":[{"lazer":[{"whoa":false}]}]}]}]}]},{"lazer":[{"cool":false}]}]},{"great.field":["grrrrr_2"]}]}', - ], - originalValue: [ - '{"matched.field":["matched_field"],"first_seen":["2021-02-22T17:29:25.195Z"],"provider":["yourself"],"type":["custom"],"matched.atomic":["matched_atomic"],"lazer":[{"great.field":["grrrrr"],"lazer":[{"lazer":[{"cool":true,"lazer":[{"lazer":[{"lazer":[{"lazer":[{"whoa":false}]}]}]}]}]},{"lazer":[{"cool":false}]}]},{"great.field":["grrrrr_2"]}]}', - ], - isObjectArray: true, - }, - ]; - const result = getDataFromFieldsHits(whackFields); - expect(result).toEqual(whackResultFields); - }); - }); - it('#getDataSafety', async () => { - const result = await getDataSafety(getDataFromFieldsHits, fields); - expect(result).toEqual(resultFields); - }); -}); diff --git a/x-pack/plugins/security_solution/common/utils/field_formatters.ts b/x-pack/plugins/security_solution/common/utils/field_formatters.ts deleted file mode 100644 index 1d8c05ec9ccf..000000000000 --- a/x-pack/plugins/security_solution/common/utils/field_formatters.ts +++ /dev/null @@ -1,148 +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 { ecsFieldMap } from '@kbn/rule-registry-plugin/common/assets/field_maps/ecs_field_map'; -import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; -import { technicalRuleFieldMap } from '@kbn/rule-registry-plugin/common/assets/field_maps/technical_rule_field_map'; -import { isEmpty } from 'lodash/fp'; -import { ENRICHMENT_DESTINATION_PATH } from '../constants'; - -import type { Fields, TimelineEventsDetailsItem } from '../search_strategy'; -import { toObjectArrayOfStrings, toStringArray } from './to_array'; - -export const baseCategoryFields = ['@timestamp', 'labels', 'message', 'tags']; - -export const getFieldCategory = (field: string): string => { - const fieldCategory = field.split('.')[0]; - if (!isEmpty(fieldCategory) && baseCategoryFields.includes(fieldCategory)) { - return 'base'; - } - return fieldCategory; -}; - -export const formatGeoLocation = (item: unknown[]) => { - const itemGeo = item.length > 0 ? (item[0] as { coordinates: number[] }) : null; - if (itemGeo != null && !isEmpty(itemGeo.coordinates)) { - try { - return toStringArray({ - lon: itemGeo.coordinates[0], - lat: itemGeo.coordinates[1], - }); - } catch { - return toStringArray(item); - } - } - return toStringArray(item); -}; - -export const isGeoField = (field: string) => - field.includes('geo.location') || field.includes('geoip.location'); - -export const isThreatEnrichmentFieldOrSubfield = (field: string, prependField?: string) => - prependField?.includes(ENRICHMENT_DESTINATION_PATH) || field === ENRICHMENT_DESTINATION_PATH; - -export const getDataFromFieldsHits = ( - fields: Fields, - prependField?: string, - prependFieldCategory?: string -): TimelineEventsDetailsItem[] => - Object.keys(fields).reduce<TimelineEventsDetailsItem[]>((accumulator, field) => { - const item: unknown[] = fields[field]; - - const fieldCategory = - prependFieldCategory != null ? prependFieldCategory : getFieldCategory(field); - if (isGeoField(field)) { - return [ - ...accumulator, - { - category: fieldCategory, - field, - values: formatGeoLocation(item), - originalValue: formatGeoLocation(item), - isObjectArray: true, // important for UI - }, - ]; - } - - const objArrStr = toObjectArrayOfStrings(item); - const strArr = objArrStr.map(({ str }) => str); - const isObjectArray = objArrStr.some((o) => o.isObjectArray); - const dotField = prependField ? `${prependField}.${field}` : field; - - // return simple field value (non-esc object, non-array) - if ( - !isObjectArray || - Object.keys({ ...ecsFieldMap, ...technicalRuleFieldMap, ...legacyExperimentalFieldMap }).find( - (ecsField) => ecsField === field - ) === undefined - ) { - return [ - ...accumulator, - { - category: fieldCategory, - field: dotField, - values: strArr, - originalValue: strArr, - isObjectArray, - }, - ]; - } - - const threatEnrichmentObject = isThreatEnrichmentFieldOrSubfield(field, prependField) - ? [ - { - category: fieldCategory, - field: dotField, - values: strArr, - originalValue: strArr, - isObjectArray, - }, - ] - : []; - - // format nested fields - const nestedFields = Array.isArray(item) - ? item - .reduce<TimelineEventsDetailsItem[][]>((acc, curr) => { - acc.push(getDataFromFieldsHits(curr as Fields, dotField, fieldCategory)); - return acc; - }, []) - .flat() - : getDataFromFieldsHits(item, prependField, fieldCategory); - - // combine duplicate fields - const flat: Record<string, TimelineEventsDetailsItem> = [ - ...accumulator, - ...nestedFields, - ...threatEnrichmentObject, - ].reduce( - (acc, f) => ({ - ...acc, - // acc/flat is hashmap to determine if we already have the field or not without an array iteration - // its converted back to array in return with Object.values - ...(acc[f.field] != null - ? { - [f.field]: { - ...f, - originalValue: acc[f.field].originalValue.includes(f.originalValue[0]) - ? acc[f.field].originalValue - : [...acc[f.field].originalValue, ...f.originalValue], - values: acc[f.field].values?.includes(f.values?.[0] || '') - ? acc[f.field].values - : [...(acc[f.field].values || []), ...(f.values || [])], - }, - } - : { [f.field]: f }), - }), - {} as Record<string, TimelineEventsDetailsItem> - ); - - return Object.values(flat); - }, []); - -export const getDataSafety = <A, T>(fn: (args: A) => T, args: A): Promise<T> => - new Promise((resolve) => setTimeout(() => resolve(fn(args)))); diff --git a/x-pack/plugins/security_solution/common/utils/to_array.ts b/x-pack/plugins/security_solution/common/utils/to_array.ts deleted file mode 100644 index b6945708ff0d..000000000000 --- a/x-pack/plugins/security_solution/common/utils/to_array.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const toArray = <T = string>(value: T | T[] | null | undefined): T[] => - Array.isArray(value) ? value : value == null ? [] : [value]; - -export const toStringArray = <T = string>(value: T | T[] | null): string[] => { - if (Array.isArray(value)) { - return value.reduce<string[]>((acc, v) => { - if (v != null) { - switch (typeof v) { - case 'number': - case 'boolean': - return [...acc, v.toString()]; - case 'object': - try { - return [...acc, JSON.stringify(v)]; - } catch { - return [...acc, 'Invalid Object']; - } - case 'string': - return [...acc, v]; - default: - return [...acc, `${v}`]; - } - } - return acc; - }, []); - } else if (value == null) { - return []; - } else if (!Array.isArray(value) && typeof value === 'object') { - try { - return [JSON.stringify(value)]; - } catch { - return ['Invalid Object']; - } - } else { - return [`${value}`]; - } -}; - -export const toObjectArrayOfStrings = <T = string>( - value: T | T[] | null -): Array<{ - str: string; - isObjectArray?: boolean; -}> => { - if (Array.isArray(value)) { - return value.reduce< - Array<{ - str: string; - isObjectArray?: boolean; - }> - >((acc, v) => { - if (v != null) { - switch (typeof v) { - case 'number': - case 'boolean': - return [...acc, { str: v.toString() }]; - case 'object': - try { - return [...acc, { str: JSON.stringify(v), isObjectArray: true }]; // need to track when string is not a simple value - } catch { - return [...acc, { str: 'Invalid Object' }]; - } - case 'string': - return [...acc, { str: v }]; - default: - return [...acc, { str: `${v}` }]; - } - } - return acc; - }, []); - } else if (value == null) { - return []; - } else if (!Array.isArray(value) && typeof value === 'object') { - try { - return [{ str: JSON.stringify(value), isObjectArray: true }]; - } catch { - return [{ str: 'Invalid Object' }]; - } - } else { - return [{ str: `${value}` }]; - } -}; diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index fa79b170f351..b1b85b822278 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -430,41 +430,6 @@ paths: summary: Start an Entity Engine tags: - Security Entity Analytics API - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/EntityType' - responses: - '200': - content: - application/json: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -615,6 +580,14 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: >- + If true returns a detailed status of the engine including all it's + components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -624,10 +597,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/EngineDescriptor' + allOf: + - $ref: '#/components/schemas/EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -824,6 +807,47 @@ components: $ref: '#/components/schemas/AssetCriticalityLevel' required: - criticality_level + EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/EngineComponentResource' + required: + - id + - installed + - resource EngineDataviewUpdateResult: type: object properties: diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml index 9c2b3d62b165..4a3b3495467e 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_entity_analytics_api_2023_10_31.bundled.schema.yaml @@ -430,41 +430,6 @@ paths: summary: Start an Entity Engine tags: - Security Entity Analytics API - /api/entity_store/engines/{entityType}/stats: - post: - operationId: GetEntityEngineStats - parameters: - - description: The entity type of the engine (either 'user' or 'host'). - in: path - name: entityType - required: true - schema: - $ref: '#/components/schemas/EntityType' - responses: - '200': - content: - application/json: - schema: - type: object - properties: - indexPattern: - $ref: '#/components/schemas/IndexPattern' - indices: - items: - type: object - type: array - status: - $ref: '#/components/schemas/EngineStatus' - transforms: - items: - type: object - type: array - type: - $ref: '#/components/schemas/EntityType' - description: Successful response - summary: Get Entity Engine stats - tags: - - Security Entity Analytics API /api/entity_store/engines/{entityType}/stop: post: operationId: StopEntityEngine @@ -615,6 +580,14 @@ paths: /api/entity_store/status: get: operationId: GetEntityStoreStatus + parameters: + - description: >- + If true returns a detailed status of the engine including all it's + components + in: query + name: include_components + schema: + type: boolean responses: '200': content: @@ -624,10 +597,20 @@ paths: properties: engines: items: - $ref: '#/components/schemas/EngineDescriptor' + allOf: + - $ref: '#/components/schemas/EngineDescriptor' + - type: object + properties: + components: + items: + $ref: '#/components/schemas/EngineComponentStatus' + type: array type: array status: $ref: '#/components/schemas/StoreStatus' + required: + - status + - engines description: Successful response summary: Get the status of the Entity Store tags: @@ -824,6 +807,47 @@ components: $ref: '#/components/schemas/AssetCriticalityLevel' required: - criticality_level + EngineComponentResource: + enum: + - entity_engine + - entity_definition + - index + - component_template + - index_template + - ingest_pipeline + - enrich_policy + - task + - transform + type: string + EngineComponentStatus: + type: object + properties: + errors: + items: + type: object + properties: + message: + type: string + title: + type: string + type: array + health: + enum: + - green + - yellow + - red + - unknown + type: string + id: + type: string + installed: + type: boolean + resource: + $ref: '#/components/schemas/EngineComponentResource' + required: + - id + - installed + - resource EngineDataviewUpdateResult: type: object properties: diff --git a/x-pack/plugins/security_solution/docs/siem_migration/README.md b/x-pack/plugins/security_solution/docs/siem_migration/README.md new file mode 100644 index 000000000000..84a2d17277ec --- /dev/null +++ b/x-pack/plugins/security_solution/docs/siem_migration/README.md @@ -0,0 +1,17 @@ +# SIEM Migration Library + +## Migration Process + +The SIEM migration library defines a set of UI components and services that are used to migrate third party SIEM resources like detection rules and translate them into resources that can be used in the Elastic Security app. + +## Graphs: + +The below images are generated by running the following command from the security_solution directory: + +```bash +yarn siem-migrations:graph:draw +``` + +Main agent graph: + +![Agent Graph](./img/agent_graph.png) \ No newline at end of file diff --git a/x-pack/plugins/security_solution/docs/siem_migration/img/agent_graph.png b/x-pack/plugins/security_solution/docs/siem_migration/img/agent_graph.png new file mode 100644 index 000000000000..ecccb602e201 Binary files /dev/null and b/x-pack/plugins/security_solution/docs/siem_migration/img/agent_graph.png differ diff --git a/x-pack/plugins/security_solution/kibana.jsonc b/x-pack/plugins/security_solution/kibana.jsonc index 0e713bc09588..f672378c88df 100644 --- a/x-pack/plugins/security_solution/kibana.jsonc +++ b/x-pack/plugins/security_solution/kibana.jsonc @@ -25,7 +25,6 @@ "dashboard", "data", "dataViews", - "discover", "ecsDataQualityDashboard", "elasticAssistant", "embeddable", @@ -59,7 +58,8 @@ "unifiedDocViewer", "charts", "entityManager", - "inference" + "inference", + "discoverShared" ], "optionalPlugins": [ "encryptedSavedObjects", diff --git a/x-pack/plugins/security_solution/package.json b/x-pack/plugins/security_solution/package.json index 62a406960cee..fd1be833c5d6 100644 --- a/x-pack/plugins/security_solution/package.json +++ b/x-pack/plugins/security_solution/package.json @@ -27,6 +27,7 @@ "test:generate:serverless-dev": "NODE_TLS_REJECT_UNAUTHORIZED=0 node --no-warnings scripts/endpoint/resolver_generator --node https://elastic_serverless:changeme@127.0.0.1:9200 --kibana http://elastic_serverless:changeme@127.0.0.1:5601", "mappings:generate": "node scripts/mappings/mappings_generator", "mappings:load": "node scripts/mappings/mappings_loader", + "siem-migrations:graph:draw": "node scripts/siem_migration/draw_graphs", "junit:transform": "node scripts/junit_transformer --pathPattern '../../../target/kibana-security-solution/cypress/results/*.xml' --rootDirectory ../../../ --reportName 'Security Solution Cypress' --writeInPlace", "openapi:generate": "node scripts/openapi/generate", "openapi:generate:debug": "node --inspect-brk scripts/openapi/generate", @@ -35,4 +36,4 @@ "openapi:bundle:entity-analytics": "node scripts/openapi/bundle_entity_analytics", "openapi:bundle:endpoint-management": "node scripts/openapi/bundle_endpoint_management" } -} +} \ No newline at end of file diff --git a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts index 429d1e1f9db2..27b309b2acee 100644 --- a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts +++ b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/discover/add_to_timeline.ts @@ -6,8 +6,8 @@ */ import type { CellAction, CellActionFactory } from '@kbn/cell-actions'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { SecurityAppStore } from '../../../../common/store'; -import { isInSecurityApp } from '../../utils'; import type { StartServices } from '../../../../types'; import { createAddToTimelineCellActionFactory } from '../cell_action/add_to_timeline'; diff --git a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts index b1a272de4d37..ef920458f51d 100644 --- a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts +++ b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.test.ts @@ -4,10 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { Subject } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; import type { CellValueContext, EmbeddableInput, IEmbeddable } from '@kbn/embeddable-plugin/public'; import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; -import { LENS_EMBEDDABLE_TYPE } from '@kbn/lens-plugin/public'; import type { SecurityAppStore } from '../../../../common/store/types'; import { createAddToTimelineLensAction, getInvestigatedValue } from './add_to_timeline'; import { KibanaServices } from '../../../../common/lib/kibana'; @@ -16,6 +15,9 @@ import type { DataProvider } from '../../../../../common/types'; import { TimelineId, EXISTS_OPERATOR } from '../../../../../common/types'; import { addProvider } from '../../../../timelines/store/actions'; import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; +import type { Query, Filter, AggregateQuery, TimeRange } from '@kbn/es-query'; +import type { LensApi } from '@kbn/lens-plugin/public'; +import { getLensApiMock } from '@kbn/lens-plugin/public/react_embeddable/mocks'; jest.mock('../../../../common/lib/kibana'); const currentAppId$ = new Subject<string | undefined>(); @@ -29,16 +31,32 @@ const store = { dispatch: mockDispatch, } as unknown as SecurityAppStore; -class MockEmbeddable { - public type; - constructor(type: string) { - this.type = type; - } - getFilters() {} - getQuery() {} -} +const getMockLensApi = ( + { from, to = 'now' }: { from: string; to: string } = { from: 'now-24h', to: 'now' } +): LensApi => + getLensApiMock({ + timeRange$: new BehaviorSubject<TimeRange | undefined>({ from, to }), + getViewUnderlyingDataArgs: jest.fn(() => ({ + dataViewSpec: { id: 'index-pattern-id' }, + timeRange: { from: 'now-7d', to: 'now' }, + filters: [], + query: undefined, + columns: [], + })), + saveToLibrary: jest.fn(async () => 'saved-id'), + }); + +const getMockEmbeddable = (type: string): IEmbeddable => + ({ + type, + filters$: new BehaviorSubject<Filter[] | undefined>([]), + query$: new BehaviorSubject<Query | AggregateQuery | undefined>({ + query: 'test', + language: 'kuery', + }), + } as unknown as IEmbeddable); -const lensEmbeddable = new MockEmbeddable(LENS_EMBEDDABLE_TYPE) as unknown as IEmbeddable; +const lensEmbeddable = getMockLensApi(); const columnMeta = { field: 'user.name', @@ -85,7 +103,7 @@ describe('createAddToTimelineLensAction', () => { expect( await addToTimelineAction.isCompatible({ ...context, - embeddable: new MockEmbeddable('not_lens') as unknown as IEmbeddable, + embeddable: getMockEmbeddable('not_lens') as unknown as IEmbeddable, }) ).toEqual(false); }); diff --git a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts index 84c95fd659fb..8792d2a6004f 100644 --- a/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts +++ b/x-pack/plugins/security_solution/public/app/actions/add_to_timeline/lens/add_to_timeline.ts @@ -6,14 +6,17 @@ */ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { isErrorEmbeddable, isFilterableEmbeddable } from '@kbn/embeddable-plugin/public'; +import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; +import { apiPublishesUnifiedSearch } from '@kbn/presentation-publishing'; +import { isLensApi } from '@kbn/lens-plugin/public'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { KibanaServices } from '../../../../common/lib/kibana'; import type { SecurityAppStore } from '../../../../common/store/types'; import { addProvider } from '../../../../timelines/store/actions'; import type { DataProvider } from '../../../../../common/types'; import { EXISTS_OPERATOR, TimelineId } from '../../../../../common/types'; -import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions } from '../../utils'; import { ADD_TO_TIMELINE, ADD_TO_TIMELINE_FAILED_TEXT, @@ -83,8 +86,8 @@ export const createAddToTimelineLensAction = ({ getDisplayName: () => ADD_TO_TIMELINE, isCompatible: async ({ embeddable, data }) => !isErrorEmbeddable(embeddable as IEmbeddable) && - isLensEmbeddable(embeddable as IEmbeddable) && - isFilterableEmbeddable(embeddable as IEmbeddable) && + isLensApi(embeddable) && + apiPublishesUnifiedSearch(embeddable) && isDataColumnsFilterable(data) && isInSecurityApp(currentAppId), execute: async ({ data }) => { diff --git a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts index 7a2c39717b34..ba92d46e6eb8 100644 --- a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts +++ b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/discover/copy_to_clipboard.ts @@ -6,7 +6,7 @@ */ import type { CellAction, CellActionFactory } from '@kbn/cell-actions'; -import { isInSecurityApp } from '../../utils'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { StartServices } from '../../../../types'; import { createCopyToClipboardCellActionFactory } from '../cell_action/copy_to_clipboard'; diff --git a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts index bb036e3f12e0..0ec4e0084834 100644 --- a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts +++ b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.test.ts @@ -7,12 +7,14 @@ import type { CellValueContext, EmbeddableInput, IEmbeddable } from '@kbn/embeddable-plugin/public'; import { ErrorEmbeddable } from '@kbn/embeddable-plugin/public'; -import { LENS_EMBEDDABLE_TYPE } from '@kbn/lens-plugin/public'; +import type { LensApi } from '@kbn/lens-plugin/public'; import { createCopyToClipboardLensAction } from './copy_to_clipboard'; import { KibanaServices } from '../../../../common/lib/kibana'; import { APP_UI_ID } from '../../../../../common/constants'; -import { Subject } from 'rxjs'; +import { BehaviorSubject, Subject } from 'rxjs'; import type { ActionExecutionContext } from '@kbn/ui-actions-plugin/public'; +import type { TimeRange } from '@kbn/es-query'; +import { getLensApiMock } from '@kbn/lens-plugin/public/react_embeddable/mocks'; jest.mock('../../../../common/lib/kibana'); const currentAppId$ = new Subject<string | undefined>(); @@ -23,14 +25,29 @@ KibanaServices.get().notifications.toasts.addSuccess = mockSuccessToast; const mockCopy = jest.fn((text: string) => true); jest.mock('copy-to-clipboard', () => (text: string) => mockCopy(text)); -class MockEmbeddable { - public type; - constructor(type: string) { - this.type = type; - } - getFilters() {} - getQuery() {} -} +const getMockLensApi = ( + { from, to = 'now' }: { from: string; to: string } = { from: 'now-24h', to: 'now' } +): LensApi => + getLensApiMock({ + timeRange$: new BehaviorSubject<TimeRange | undefined>({ from, to }), + getViewUnderlyingDataArgs: jest.fn(() => ({ + dataViewSpec: { id: 'index-pattern-id' }, + timeRange: { from: 'now-7d', to: 'now' }, + filters: [], + query: undefined, + columns: [], + })), + saveToLibrary: jest.fn(async () => 'saved-id'), + }); + +const getMockEmbeddable = (type: string): IEmbeddable => + ({ + type, + getFilters: jest.fn(), + getQuery: jest.fn(), + } as unknown as IEmbeddable); + +const lensEmbeddable = getMockLensApi(); const columnMeta = { field: 'user.name', @@ -39,7 +56,6 @@ const columnMeta = { sourceParams: { indexPatternId: 'some-pattern-id' }, }; const data: CellValueContext['data'] = [{ columnMeta, value: 'the value' }]; -const lensEmbeddable = new MockEmbeddable(LENS_EMBEDDABLE_TYPE) as unknown as IEmbeddable; const context = { data, @@ -76,7 +92,7 @@ describe('createCopyToClipboardLensAction', () => { expect( await copyToClipboardAction.isCompatible({ ...context, - embeddable: new MockEmbeddable('not_lens') as unknown as IEmbeddable, + embeddable: getMockEmbeddable('not_lens') as unknown as IEmbeddable, }) ).toEqual(false); }); diff --git a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts index 8546f0c3260c..f4c61c1e7bf7 100644 --- a/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts +++ b/x-pack/plugins/security_solution/public/app/actions/copy_to_clipboard/lens/copy_to_clipboard.ts @@ -9,8 +9,9 @@ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/publi import { isErrorEmbeddable } from '@kbn/embeddable-plugin/public'; import { createAction } from '@kbn/ui-actions-plugin/public'; import copy from 'copy-to-clipboard'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { KibanaServices } from '../../../../common/lib/kibana'; -import { fieldHasCellActions, isCountField, isInSecurityApp, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions, isCountField, isLensEmbeddable } from '../../utils'; import { COPY_TO_CLIPBOARD, COPY_TO_CLIPBOARD_ICON, COPY_TO_CLIPBOARD_SUCCESS } from '../constants'; export const ACTION_ID = 'embeddable_copyToClipboard'; diff --git a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts index d0cdaed61f8a..19ae6cf1f174 100644 --- a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts +++ b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_in.ts @@ -6,8 +6,8 @@ */ import type { CellAction, CellActionFactory } from '@kbn/cell-actions'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { SecurityAppStore } from '../../../../common/store'; -import { isInSecurityApp } from '../../utils'; import type { StartServices } from '../../../../types'; import { createFilterInCellActionFactory } from '../cell_action/filter_in'; diff --git a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts index 757b2f41d99b..77e463c5268d 100644 --- a/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts +++ b/x-pack/plugins/security_solution/public/app/actions/filter/discover/filter_out.ts @@ -6,7 +6,7 @@ */ import type { CellActionFactory, CellAction } from '@kbn/cell-actions'; -import { isInSecurityApp } from '../../utils'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import type { SecurityAppStore } from '../../../../common/store'; import type { StartServices } from '../../../../types'; import { createFilterOutCellActionFactory } from '../cell_action/filter_out'; diff --git a/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts b/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts index 966efe9590ec..e26446676728 100644 --- a/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts +++ b/x-pack/plugins/security_solution/public/app/actions/filter/lens/create_action.ts @@ -16,8 +16,9 @@ import type { CellValueContext, IEmbeddable } from '@kbn/embeddable-plugin/publi import { createAction } from '@kbn/ui-actions-plugin/public'; import { ACTION_INCOMPATIBLE_VALUE_WARNING } from '@kbn/cell-actions/src/actions/translations'; import { i18n } from '@kbn/i18n'; +import { isInSecurityApp } from '../../../../common/hooks/is_in_security_app'; import { timelineSelectors } from '../../../../timelines/store'; -import { fieldHasCellActions, isInSecurityApp, isLensEmbeddable } from '../../utils'; +import { fieldHasCellActions, isLensEmbeddable } from '../../utils'; import { TimelineId } from '../../../../../common/types'; import { DefaultCellActionTypes } from '../../constants'; import type { SecurityAppStore } from '../../../../common/store'; diff --git a/x-pack/plugins/security_solution/public/app/actions/utils.ts b/x-pack/plugins/security_solution/public/app/actions/utils.ts index 12c5400dbcf3..3da597db60c0 100644 --- a/x-pack/plugins/security_solution/public/app/actions/utils.ts +++ b/x-pack/plugins/security_solution/public/app/actions/utils.ts @@ -5,9 +5,8 @@ * 2.0. */ import type { IEmbeddable } from '@kbn/embeddable-plugin/public'; -import { LENS_EMBEDDABLE_TYPE, type Embeddable as LensEmbeddable } from '@kbn/lens-plugin/public'; +import { isLensApi } from '@kbn/lens-plugin/public'; import type { Serializable } from '@kbn/utility-types'; -import { APP_UI_ID } from '../../../common/constants'; // All cell actions are disabled for these fields in Security const FIELDS_WITHOUT_CELL_ACTIONS = [ @@ -17,12 +16,10 @@ const FIELDS_WITHOUT_CELL_ACTIONS = [ 'kibana.alert.reason', ]; -export const isInSecurityApp = (currentAppId?: string): boolean => { - return !!currentAppId && currentAppId === APP_UI_ID; -}; - -export const isLensEmbeddable = (embeddable: IEmbeddable): embeddable is LensEmbeddable => { - return embeddable.type === LENS_EMBEDDABLE_TYPE; +// @TODO: this is a temporary fix. It needs a better refactor on the consumer side here to +// adapt to the new Embeddable architecture +export const isLensEmbeddable = (embeddable: IEmbeddable): embeddable is IEmbeddable => { + return isLensApi(embeddable); }; export const fieldHasCellActions = (field?: string): boolean => { diff --git a/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.test.tsx b/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.test.tsx index c1d3760813a1..49508dd79b1e 100644 --- a/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.test.tsx +++ b/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.test.tsx @@ -22,32 +22,11 @@ jest.mock('./timeline', () => ({ Timeline: () => <div>{'Timeline'}</div>, })); -jest.mock('../../../common/components/navigation/use_security_solution_navigation', () => { - return { - useSecuritySolutionNavigation: () => ({ - icon: 'logoSecurity', - items: [ - { - id: 'investigate', - name: 'Investigate', - items: [ - { - 'data-href': 'some-data-href', - 'data-test-subj': 'navigation-cases', - disabled: false, - href: 'some-href', - id: 'cases', - isSelected: true, - name: 'Cases', - }, - ], - tabIndex: undefined, - }, - ], - name: 'Security', - }), - }; -}); +const navProps = { icon: 'logoSecurity', items: [], name: 'Security' }; +const mockUseSecuritySolutionNavigation = jest.fn(); +jest.mock('../../../common/components/navigation/use_security_solution_navigation', () => ({ + useSecuritySolutionNavigation: () => mockUseSecuritySolutionNavigation(), +})); const mockUseRouteSpy = jest.fn((): [{ pageName: string }] => [ { pageName: SecurityPageName.alerts }, @@ -69,6 +48,39 @@ const renderComponent = ({ describe('SecuritySolutionTemplateWrapper', () => { beforeEach(() => { jest.clearAllMocks(); + mockUseSecuritySolutionNavigation.mockReturnValue(navProps); + }); + + describe('when navigation props are defined (classic nav)', () => { + beforeEach(() => { + mockUseSecuritySolutionNavigation.mockReturnValue(navProps); + }); + it('should render the children', async () => { + const { queryByText } = renderComponent(); + expect(queryByText('child of wrapper')).toBeInTheDocument(); + }); + }); + + describe('when navigation props are null (project nav)', () => { + beforeEach(() => { + mockUseSecuritySolutionNavigation.mockReturnValue(null); + }); + + it('should render the children', async () => { + const { queryByText } = renderComponent(); + expect(queryByText('child of wrapper')).toBeInTheDocument(); + }); + }); + + describe('when navigation props are undefined (loading)', () => { + beforeEach(() => { + mockUseSecuritySolutionNavigation.mockReturnValue(undefined); + }); + + it('should not render the children', async () => { + const { queryByText } = renderComponent(); + expect(queryByText('child of wrapper')).not.toBeInTheDocument(); + }); }); it('Should render with bottom bar when user allowed', async () => { diff --git a/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx b/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx index 19e8d55aa2dd..f547d128ab54 100644 --- a/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx +++ b/x-pack/plugins/security_solution/public/app/home/template_wrapper/index.tsx @@ -69,8 +69,8 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionTemplateW const { euiTheme, colorMode: globalColorMode } = useEuiTheme(); // There is some logic in the StyledKibanaPageTemplate that checks for children presence, and we dont even need to render the children - // here if isEmptyState is set - const isNotEmpty = !rest.isEmptyState; + // solutionNavProps is momentarily initialized to undefined, this check prevents the children from being re-rendered in the initial load + const renderChildren = !rest.isEmptyState && solutionNavProps !== undefined; /* * StyledKibanaPageTemplate is a styled EuiPageTemplate. Security solution currently passes the header @@ -83,11 +83,11 @@ export const SecuritySolutionTemplateWrapper: React.FC<SecuritySolutionTemplateW theme={euiTheme} $isShowingTimelineOverlay={isShowingTimelineOverlay} paddingSize="none" - solutionNav={solutionNavProps} + solutionNav={solutionNavProps ?? undefined} restrictWidth={false} {...rest} > - {isNotEmpty && ( + {renderChildren && ( <> <GlobalKQLHeader /> <KibanaPageTemplate.Section diff --git a/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/ml_links.ts b/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/ml_links.ts index 7a7e7334fefb..f9ef049c73d3 100644 --- a/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/ml_links.ts +++ b/x-pack/plugins/security_solution/public/app/solution_navigation/links/sections/ml_links.ts @@ -39,7 +39,7 @@ export const mlAppLink: LinkItem = { id: SecurityPageName.mlLanding, title: i18n.ML_TITLE, path: MACHINE_LEARNING_PATH, - capabilities: [`${SERVER_APP_ID}.show`], + capabilities: [[`${SERVER_APP_ID}.show`, `ml.canGetJobs`]], globalSearchKeywords: [i18n.ML_KEYWORD], hideTimeline: true, skipUrlState: true, diff --git a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx index adb952d66121..1bf997eb4de2 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx @@ -12,7 +12,6 @@ import { import { APP_UI_ID } from '../../../../common'; import * as i18n from './translations'; import { - KNOWLEDGE_BASE_CATEGORY, PROMPT_CONTEXT_ALERT_CATEGORY, PROMPT_CONTEXT_DETECTION_RULES_CATEGORY, PROMPT_CONTEXT_EVENT_CATEGORY, @@ -34,16 +33,6 @@ export const BASE_SECURITY_QUICK_PROMPTS: PromptResponse[] = [ promptType: PromptTypeEnum.quick, consumer: APP_UI_ID, }, - { - name: i18n.ESQL_QUERY_GENERATION_TITLE, - content: i18n.ESQL_QUERY_GENERATION_PROMPT, - color: '#9170B8', - categories: [KNOWLEDGE_BASE_CATEGORY], - isDefault: true, - id: i18n.ESQL_QUERY_GENERATION_TITLE, - promptType: PromptTypeEnum.quick, - consumer: APP_UI_ID, - }, { name: i18n.RULE_CREATION_TITLE, content: i18n.RULE_CREATION_PROMPT, diff --git a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts index 41b9e7ddb197..1d122b0169be 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts @@ -22,21 +22,6 @@ export const ALERT_SUMMARIZATION_PROMPT = i18n.translate( } ); -export const ESQL_QUERY_GENERATION_TITLE = i18n.translate( - 'xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationTitle', - { - defaultMessage: 'ES|QL Query Generation', - } -); - -export const ESQL_QUERY_GENERATION_PROMPT = i18n.translate( - 'xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationPrompt', - { - defaultMessage: - "As an expert user of Elastic Security, please generate an accurate and valid ESQL query to detect the use case below. Your response should be formatted to be able to use immediately in an Elastic Security timeline or detection rule. Take your time with the answer, check your knowledge really well on all the functions I am asking for. For ES|QL answers specifically, you should only ever answer with what's available in your private knowledge. I cannot afford for queries to be inaccurate. Assume I am using the Elastic Common Schema and Elastic Agent.\n\nEnsure the answers are formatted in a way which is easily copyable as a separate code block in markdown.", - } -); - export const RULE_CREATION_TITLE = i18n.translate( 'xpack.securitySolution.assistant.quickPrompts.ruleCreationTitle', { diff --git a/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx b/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx index 97bec48eaaae..1976d97c9c8d 100644 --- a/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx +++ b/x-pack/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/alerts_tab/index.tsx @@ -6,9 +6,11 @@ */ import type { AttackDiscovery, Replacements } from '@kbn/elastic-assistant-common'; -import { AlertConsumers } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; +import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; import React, { useMemo } from 'react'; +import { AlertConsumers } from '@kbn/rule-data-utils'; import { ALERTS_TABLE_REGISTRY_CONFIG_IDS } from '../../../../../../../common/constants'; import { useKibana } from '../../../../../../common/lib/kibana'; @@ -39,12 +41,13 @@ const AlertsTabComponent: React.FC<Props> = ({ attackDiscovery, replacements }) const configId = ALERTS_TABLE_REGISTRY_CONFIG_IDS.CASE; // show the same row-actions as in the case view - const alertStateProps = useMemo( + const alertStateProps: AlertsTableStateProps = useMemo( () => ({ alertsTableConfigurationRegistry: triggersActionsUi.alertsTableConfigurationRegistry, configurationId: configId, id: `attack-discovery-alerts-${attackDiscovery.id}`, - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: SECURITY_SOLUTION_RULE_TYPE_IDS, + consumers: [AlertConsumers.SIEM], query: alertIdsQuery, showAlertStatusWithFlapping: false, }), diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx index 6567fb41a93f..2b1a2002667c 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/alerts_findings_details_table.tsx @@ -19,6 +19,8 @@ import { METRIC_TYPE } from '@kbn/analytics'; import { buildEntityAlertsQuery } from '@kbn/cloud-security-posture-common/utils/helpers'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { TableId } from '@kbn/securitysolution-data-table'; +import type { AlertsByStatus } from '../../../overview/components/detection_response/alerts_by_status/types'; +import { DETECTION_RESPONSE_ALERTS_BY_STATUS_ID } from '../../../overview/components/detection_response/alerts_by_status/types'; import { OPEN_IN_ALERTS_TITLE_HOSTNAME, OPEN_IN_ALERTS_TITLE_STATUS, @@ -34,6 +36,7 @@ import { getSeverityColor } from '../../../detections/components/alerts_kpis/sev import { SeverityBadge } from '../../../common/components/severity_badge'; import { ALERT_PREVIEW_BANNER } from '../../../flyout/document_details/preview/constants'; import { FILTER_OPEN, FILTER_ACKNOWLEDGED } from '../../../../common/types'; +import { useNonClosedAlerts } from '../../hooks/use_non_closed_alerts'; type AlertSeverity = 'low' | 'medium' | 'high' | 'critical'; @@ -68,6 +71,8 @@ export const AlertsDetailsTable = memo( ); }, []); + const [currentFilter, setCurrentFilter] = useState<string>(''); + const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -89,12 +94,46 @@ export const AlertsDetailsTable = memo( const { to, from } = useGlobalTime(); const { signalIndexName } = useSignalIndex(); - const { data } = useQueryAlerts({ - query: buildEntityAlertsQuery(field, to, from, value, 500), + const { data, setQuery } = useQueryAlerts({ + query: buildEntityAlertsQuery(field, to, from, value, 500, ''), queryName: ALERTS_QUERY_NAMES.BY_RULE_BY_STATUS, indexName: signalIndexName, }); + const { filteredAlertsData: alertsData } = useNonClosedAlerts({ + field, + value, + to, + from, + queryId: `${DETECTION_RESPONSE_ALERTS_BY_STATUS_ID}`, + }); + + const severityMap = new Map<string, number>(); + (Object.keys(alertsData || {}) as AlertsByStatus[]).forEach((status) => { + if (alertsData?.[status]?.severities) { + alertsData?.[status]?.severities.forEach((severity) => { + const currentSeverity = severityMap.get(severity.key) || 0; + severityMap.set(severity.key, currentSeverity + severity.value); + }); + } + }); + + const alertStats = Array.from(severityMap, ([key, count]) => ({ + key: capitalize(key), + count, + color: getSeverityColor(key), + filter: () => { + setCurrentFilter(key); + setQuery(buildEntityAlertsQuery(field, to, from, value, 500, key)); + }, + isCurrentFilter: currentFilter === key, + reset: (event: React.MouseEvent<SVGElement, MouseEvent>) => { + setCurrentFilter(''); + setQuery(buildEntityAlertsQuery(field, to, from, value, 500, '')); + event?.stopPropagation(); + }, + })); + const alertDataResults = (data?.hits?.hits as AlertsDetailsFields[])?.map( (item: AlertsDetailsFields) => { return { @@ -108,19 +147,6 @@ export const AlertsDetailsTable = memo( } ); - const severitiesMap = alertDataResults?.map((item) => item.severity) || []; - - const alertStats = Object.entries( - severitiesMap.reduce((acc: Record<string, number>, item) => { - acc[item] = (acc[item] || 0) + 1; - return acc; - }, {}) - ).map(([key, count]) => ({ - key: capitalize(key), - count, - color: getSeverityColor(key), - })); - const { pageOfItems, totalItemCount } = alertsPagination(alertDataResults || []); const pagination = { diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx index 00430c2b8726..61c89e196a18 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/misconfiguration_findings_details_table.tsx @@ -10,8 +10,12 @@ import type { Criteria, EuiBasicTableColumn } from '@elastic/eui'; import { EuiSpacer, EuiPanel, EuiText, EuiBasicTable, EuiIcon } from '@elastic/eui'; import { useMisconfigurationFindings } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_findings'; import { i18n } from '@kbn/i18n'; -import type { CspFinding, CspFindingResult } from '@kbn/cloud-security-posture-common'; -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { + MISCONFIGURATION_STATUS, + type CspFinding, + type CspFindingResult, + buildMisconfigurationEntityFlyoutPreviewQuery, +} from '@kbn/cloud-security-posture-common'; import { euiThemeVars } from '@kbn/ui-theme'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; import type { CspBenchmarkRuleMetadata } from '@kbn/cloud-security-posture-common/schema/rules/latest'; @@ -25,11 +29,17 @@ import { import { METRIC_TYPE } from '@kbn/analytics'; import { useGetNavigationUrlParams } from '@kbn/cloud-security-posture/src/hooks/use_get_navigation_url_params'; import { SecurityPageName } from '@kbn/deeplinks-security'; +import { useHasMisconfigurations } from '@kbn/cloud-security-posture/src/hooks/use_has_misconfigurations'; import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; type MisconfigurationFindingDetailFields = Pick<CspFinding, 'result' | 'rule' | 'resource'>; -const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: number) => { +const getFindingsStats = ( + passedFindingsStats: number, + failedFindingsStats: number, + filterFunction: (filter: string) => void, + currentFilter: string +) => { if (passedFindingsStats === 0 && failedFindingsStats === 0) return []; return [ { @@ -41,6 +51,14 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb ), count: passedFindingsStats, color: euiThemeVars.euiColorSuccess, + filter: () => { + filterFunction(MISCONFIGURATION_STATUS.PASSED); + }, + isCurrentFilter: currentFilter === MISCONFIGURATION_STATUS.PASSED, + reset: (event: React.MouseEvent<SVGElement, MouseEvent>) => { + filterFunction(''); + event?.stopPropagation(); + }, }, { key: i18n.translate( @@ -51,6 +69,14 @@ const getFindingsStats = (passedFindingsStats: number, failedFindingsStats: numb ), count: failedFindingsStats, color: euiThemeVars.euiColorVis9, + filter: () => { + filterFunction(MISCONFIGURATION_STATUS.FAILED); + }, + isCurrentFilter: currentFilter === MISCONFIGURATION_STATUS.FAILED, + reset: (event: React.MouseEvent<SVGElement, MouseEvent>) => { + filterFunction(''); + event?.stopPropagation(); + }, }, ]; }; @@ -67,15 +93,16 @@ export const MisconfigurationFindingsDetailsTable = memo( ); }, []); + const [currentFilter, setCurrentFilter] = useState<string>(''); + const { data } = useMisconfigurationFindings({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildMisconfigurationEntityFlyoutPreviewQuery(field, value, currentFilter), sort: [], enabled: true, pageSize: 1, }); - const passedFindings = data?.count.passed || 0; - const failedFindings = data?.count.failed || 0; + const { passedFindings, failedFindings } = useHasMisconfigurations(field, value); const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -129,6 +156,13 @@ export const MisconfigurationFindingsDetailsTable = memo( const linkWidth = 40; const resultWidth = 74; + const misconfgurationStats = getFindingsStats( + passedFindings, + failedFindings, + setCurrentFilter, + currentFilter + ); + const columns: Array<EuiBasicTableColumn<MisconfigurationFindingDetailFields>> = [ { field: 'rule', @@ -202,7 +236,7 @@ export const MisconfigurationFindingsDetailsTable = memo( <EuiIcon type={'popout'} /> </SecuritySolutionLinkAnchor> <EuiSpacer size="xl" /> - <DistributionBar stats={getFindingsStats(passedFindings, failedFindings)} /> + <DistributionBar stats={misconfgurationStats} /> <EuiSpacer size="l" /> <EuiBasicTable items={pageOfItems || []} diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx index 155946a791f7..84f85af509b8 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/csp_details/vulnerabilities_findings_details_table.tsx @@ -9,8 +9,10 @@ import React, { memo, useEffect, useState } from 'react'; import type { Criteria, EuiBasicTableColumn } from '@elastic/eui'; import { EuiSpacer, EuiPanel, EuiText, EuiBasicTable, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import type { VulnSeverity } from '@kbn/cloud-security-posture-common'; -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { + buildVulnerabilityEntityFlyoutPreviewQuery, + type VulnSeverity, +} from '@kbn/cloud-security-posture-common'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; import { useVulnerabilitiesFindings } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_findings'; import type { @@ -30,6 +32,7 @@ import { import { METRIC_TYPE } from '@kbn/analytics'; import { SecurityPageName } from '@kbn/deeplinks-security'; import { useGetNavigationUrlParams } from '@kbn/cloud-security-posture/src/hooks/use_get_navigation_url_params'; +import { useHasVulnerabilities } from '@kbn/cloud-security-posture/src/hooks/use_has_vulnerabilities'; import { SecuritySolutionLinkAnchor } from '../../../common/components/links'; type VulnerabilitiesFindingDetailFields = Pick< @@ -52,14 +55,18 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ value }: { value: str ); }, []); + const [currentFilter, setCurrentFilter] = useState<string>(''); + const { data } = useVulnerabilitiesFindings({ - query: buildEntityFlyoutPreviewQuery('host.name', value), + query: buildVulnerabilityEntityFlyoutPreviewQuery('host.name', value, currentFilter), sort: [], enabled: true, pageSize: 1, }); - const { CRITICAL = 0, HIGH = 0, MEDIUM = 0, LOW = 0, NONE = 0 } = data?.count || {}; + const { counts } = useHasVulnerabilities('host.name', value); + + const { critical = 0, high = 0, medium = 0, low = 0, none = 0 } = counts || {}; const [pageIndex, setPageIndex] = useState(0); const [pageSize, setPageSize] = useState(10); @@ -120,6 +127,18 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ value }: { value: str ); }; + const vulnerabilityStats = getVulnerabilityStats( + { + critical, + high, + medium, + low, + none, + }, + setCurrentFilter, + currentFilter + ); + const columns: Array<EuiBasicTableColumn<VulnerabilitiesFindingDetailFields>> = [ { field: 'vulnerability', @@ -220,15 +239,7 @@ export const VulnerabilitiesFindingsDetailsTable = memo(({ value }: { value: str <EuiIcon type={'popout'} /> </SecuritySolutionLinkAnchor> <EuiSpacer size="xl" /> - <DistributionBar - stats={getVulnerabilityStats({ - critical: CRITICAL, - high: HIGH, - medium: MEDIUM, - low: LOW, - none: NONE, - })} - /> + <DistributionBar stats={vulnerabilityStats} /> <EuiSpacer size="l" /> <EuiBasicTable items={pageOfItems || []} diff --git a/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx b/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx index 5a5b638abafa..bbdf05b00163 100644 --- a/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx +++ b/x-pack/plugins/security_solution/public/cloud_security_posture/components/vulnerabilities/vulnerabilities_preview.tsx @@ -13,7 +13,7 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { DistributionBar } from '@kbn/security-solution-distribution-bar'; import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; import { - buildEntityFlyoutPreviewQuery, + buildGenericEntityFlyoutPreviewQuery, getAbbreviatedNumber, } from '@kbn/cloud-security-posture-common'; import { getVulnerabilityStats, hasVulnerabilitiesData } from '@kbn/cloud-security-posture'; @@ -73,7 +73,7 @@ export const VulnerabilitiesPreview = ({ }, []); const { data } = useVulnerabilitiesPreview({ - query: buildEntityFlyoutPreviewQuery(field, value), + query: buildGenericEntityFlyoutPreviewQuery(field, value), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx b/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx index 4cf9bcbb4d77..9c22ae244073 100644 --- a/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/empty_prompt.tsx @@ -14,6 +14,7 @@ import { EuiPageHeader, useEuiTheme, type EuiThemeComputed, + EuiButtonEmpty, } from '@elastic/eui'; import { css } from '@emotion/react'; import { OnboardingCardId } from '../../../onboarding/constants'; @@ -67,7 +68,7 @@ const footerStyles = css` margin: 20px auto 0; `; -export const EmptyPromptComponent = memo(() => { +export const EmptyPromptComponent = memo(({ onSkip }: { onSkip?: () => void }) => { const { euiTheme } = useEuiTheme(); const { navigateTo } = useNavigateTo(); @@ -164,9 +165,20 @@ export const EmptyPromptComponent = memo(() => { textAlign="center" title={i18n.UNIFY_TITLE} footer={ - <EuiButton data-test-subj="add-integrations-footer" onClick={onClick}> - {i18n.SIEM_CTA} - </EuiButton> + <EuiFlexGroup gutterSize="s" justifyContent="center"> + <EuiFlexItem grow={false}> + <EuiButton data-test-subj="add-integrations-footer" onClick={onClick}> + {i18n.SIEM_CTA} + </EuiButton> + </EuiFlexItem> + {onSkip && ( + <EuiFlexItem grow={false}> + <EuiButtonEmpty data-test-subj="skip-integrations-footer" onClick={onSkip}> + {i18n.SIEM_CONTINUE} + </EuiButtonEmpty> + </EuiFlexItem> + )} + </EuiFlexGroup> } css={footerStyles} /> diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/index.tsx b/x-pack/plugins/security_solution/public/common/components/empty_prompt/index.tsx index 20c05e5f5170..e7699aff7f6c 100644 --- a/x-pack/plugins/security_solution/public/common/components/empty_prompt/index.tsx +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/index.tsx @@ -11,8 +11,8 @@ const EmptyPromptLazy = lazy(() => import('./empty_prompt')); const centerLogoStyle = { display: 'flex', margin: 'auto' }; -export const EmptyPrompt = () => ( +export const EmptyPrompt = ({ onSkip }: { onSkip?: () => void }) => ( <Suspense fallback={<EuiLoadingLogo logo="logoSecurity" size="xl" style={centerLogoStyle} />}> - <EmptyPromptLazy /> + <EmptyPromptLazy onSkip={onSkip} /> </Suspense> ); diff --git a/x-pack/plugins/security_solution/public/common/components/empty_prompt/translations.tsx b/x-pack/plugins/security_solution/public/common/components/empty_prompt/translations.tsx index e23b166a8574..afb89bd6135d 100644 --- a/x-pack/plugins/security_solution/public/common/components/empty_prompt/translations.tsx +++ b/x-pack/plugins/security_solution/public/common/components/empty_prompt/translations.tsx @@ -34,6 +34,13 @@ export const SIEM_CTA = i18n.translate( } ); +export const SIEM_CONTINUE = i18n.translate( + 'xpack.securitySolution.getStarted.landingCards.box.siem.continue', + { + defaultMessage: 'Continue without adding integrations', + } +); + export const ENDPOINT_TITLE = i18n.translate( 'xpack.securitySolution.getStarted.landingCards.box.endpoint.title', { diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx index c5bc4a01f514..bb7f50b066ed 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/host_isolation/from_alerts/use_host_isolation_action.test.tsx @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - +import type React from 'react'; +import { act } from '@testing-library/react'; import type { UseHostIsolationActionProps } from './use_host_isolation_action'; import { useHostIsolationAction } from './use_host_isolation_action'; import type { AppContextTestRender, UserPrivilegesMockSetter } from '../../../../mock/endpoint'; @@ -15,7 +16,6 @@ import type { AlertTableContextMenuItem } from '../../../../../detections/compon import type { ResponseActionsApiCommandNames } from '../../../../../../common/endpoint/service/response_actions/constants'; import { agentStatusMocks } from '../../../../../../common/endpoint/service/response_actions/mocks/agent_status.mocks'; import { ISOLATE_HOST, UNISOLATE_HOST } from './translations'; -import type React from 'react'; import { HOST_ENDPOINT_UNENROLLED_TOOLTIP, LOADING_ENDPOINT_DATA_TOOLTIP, @@ -87,20 +87,22 @@ describe('useHostIsolationAction', () => { }); } - const { result, waitForValueToChange } = render(); - await waitForValueToChange(() => result.current); + const { result } = render(); - expect(result.current).toEqual([ - buildExpectedMenuItemResult({ - ...(command === 'unisolate' ? { name: UNISOLATE_HOST } : {}), - }), - ]); + await appContextMock.waitFor(() => + expect(result.current).toEqual([ + buildExpectedMenuItemResult({ + ...(command === 'unisolate' ? { name: UNISOLATE_HOST } : {}), + }), + ]) + ); } ); it('should call `closePopover` callback when menu item `onClick` is called', async () => { - const { result, waitForValueToChange } = render(); - await waitForValueToChange(() => result.current); + const { result } = render(); + await appContextMock.waitFor(() => expect(result.current[0].onClick).toBeDefined()); + result.current[0].onClick!({} as unknown as React.MouseEvent); expect(hookProps.closePopover).toHaveBeenCalled(); @@ -135,12 +137,14 @@ describe('useHostIsolationAction', () => { it('should return disabled menu item while loading agent status', async () => { const { result } = render(); - expect(result.current).toEqual([ - buildExpectedMenuItemResult({ - disabled: true, - toolTipContent: LOADING_ENDPOINT_DATA_TOOLTIP, - }), - ]); + await appContextMock.waitFor(() => + expect(result.current).toEqual([ + buildExpectedMenuItemResult({ + disabled: true, + toolTipContent: LOADING_ENDPOINT_DATA_TOOLTIP, + }), + ]) + ); }); it.each(['endpoint', 'non-endpoint'])( @@ -156,37 +160,51 @@ describe('useHostIsolationAction', () => { if (type === 'non-endpoint') { hookProps.detailsData = endpointAlertDataMock.generateSentinelOneAlertDetailsItemData(); } - const { result, waitForValueToChange } = render(); - await waitForValueToChange(() => result.current); - - expect(result.current).toEqual([ - buildExpectedMenuItemResult({ - disabled: true, - toolTipContent: - type === 'endpoint' ? HOST_ENDPOINT_UNENROLLED_TOOLTIP : NOT_FROM_ENDPOINT_HOST_TOOLTIP, - }), - ]); + const { result } = render(); + await appContextMock.waitFor(() => + expect(result.current).toEqual([ + buildExpectedMenuItemResult({ + disabled: true, + toolTipContent: + type === 'endpoint' + ? HOST_ENDPOINT_UNENROLLED_TOOLTIP + : NOT_FROM_ENDPOINT_HOST_TOOLTIP, + }), + ]) + ); } ); it('should call isolate API when agent is currently NOT isolated', async () => { - const { result, waitForValueToChange } = render(); - await waitForValueToChange(() => result.current); + const { result } = render(); + await appContextMock.waitFor(() => expect(result.current[0].onClick).toBeDefined()); result.current[0].onClick!({} as unknown as React.MouseEvent); expect(hookProps.onAddIsolationStatusClick).toHaveBeenCalledWith('isolateHost'); }); it('should call un-isolate API when agent is currently isolated', async () => { - apiMock.responseProvider.getAgentStatus.mockReturnValue( - agentStatusMocks.generateAgentStatusApiResponse({ - data: { 'abfe4a35-d5b4-42a0-a539-bd054c791769': { isolated: true } }, - }) - ); - const { result, waitForValueToChange } = render(); - await waitForValueToChange(() => result.current); - result.current[0].onClick!({} as unknown as React.MouseEvent); + apiMock.responseProvider.getAgentStatus.mockImplementation(({ query }) => { + const agentId = (query!.agentIds as string[])[0]; + + return agentStatusMocks.generateAgentStatusApiResponse({ + data: { [agentId]: { isolated: true } }, + }); + }); + + const { result } = render(); + + await appContextMock.waitFor(() => { + expect(apiMock.responseProvider.getAgentStatus).toHaveBeenCalled(); + expect(result.current[0].onClick).toBeDefined(); + }); + + act(() => { + result.current[0].onClick!({} as unknown as React.MouseEvent); + }); - expect(hookProps.onAddIsolationStatusClick).toHaveBeenCalledWith('unisolateHost'); + await appContextMock.waitFor(() => + expect(hookProps.onAddIsolationStatusClick).toHaveBeenCalledWith('unisolateHost') + ); }); }); diff --git a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts index 3b68c0efdf9e..6cbd0ced1238 100644 --- a/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/endpoint/responder/from_alerts/use_responder_action_data.test.ts @@ -25,7 +25,8 @@ import type { AppContextTestRender } from '../../../../mock/endpoint'; import { createAppRootMockRenderer, endpointAlertDataMock } from '../../../../mock/endpoint'; import { HOST_METADATA_LIST_ROUTE } from '../../../../../../common/endpoint/constants'; import { endpointMetadataHttpMocks } from '../../../../../management/pages/endpoint_hosts/mocks'; -import type { RenderHookResult } from '@testing-library/react-hooks/src/types'; +import type { RenderHookResult } from '@testing-library/react'; +import { waitFor, act } from '@testing-library/react'; import { createHttpFetchError } from '@kbn/core-http-browser-mocks'; import { HostStatus } from '../../../../../../common/endpoint/types'; import { @@ -61,17 +62,14 @@ describe('use responder action data hooks', () => { describe('useWithResponderActionDataFromAlert() hook', () => { let renderHook: () => RenderHookResult< - UseWithResponderActionDataFromAlertProps, - ResponderActionData + ResponderActionData, + UseWithResponderActionDataFromAlertProps >; let alertDetailItemData: TimelineEventsDetailsItem[]; beforeEach(() => { renderHook = () => { - return appContextMock.renderHook< - UseWithResponderActionDataFromAlertProps, - ResponderActionData - >(() => + return appContextMock.renderHook(() => useWithResponderActionDataFromAlert({ eventData: alertDetailItemData, onClick: onClickMock, @@ -95,7 +93,9 @@ describe('use responder action data hooks', () => { it('should call `onClick()` function prop when is pass to the hook', () => { alertDetailItemData = endpointAlertDataMock.generateSentinelOneAlertDetailsItemData(); const { result } = renderHook(); - result.current.handleResponseActionsClick(); + act(() => { + result.current.handleResponseActionsClick(); + }); expect(onClickMock).toHaveBeenCalled(); }); @@ -103,7 +103,9 @@ describe('use responder action data hooks', () => { it('should NOT call `onClick` if the action is disabled', () => { alertDetailItemData = endpointAlertDataMock.generateAlertDetailsItemDataForAgentType('foo'); const { result } = renderHook(); - result.current.handleResponseActionsClick(); + act(() => { + result.current.handleResponseActionsClick(); + }); expect(onClickMock).not.toHaveBeenCalled(); }); @@ -169,8 +171,8 @@ describe('use responder action data hooks', () => { }); it('should show action enabled if host metadata was retrieved and host is enrolled', async () => { - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current.isDisabled); + const { result } = renderHook(); + await waitFor(() => expect(result.current.isDisabled).toBe(false)); expect(result.current).toEqual(getExpectedResponderActionData()); }); @@ -181,8 +183,10 @@ describe('use responder action data hooks', () => { statusCode: 404, }); }); - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current.tooltip); + + const { result } = renderHook(); + + await waitFor(() => expect(result.current.tooltip).not.toEqual('Loading')); expect(result.current).toEqual( getExpectedResponderActionData({ @@ -199,8 +203,8 @@ describe('use responder action data hooks', () => { }; metadataApiMocks.responseProvider.metadataDetails.mockReturnValue(hostMetadata); - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current.tooltip); + const { result } = renderHook(); + await waitFor(() => expect(result.current.tooltip).not.toEqual('Loading')); expect(result.current).toEqual( getExpectedResponderActionData({ @@ -216,8 +220,8 @@ describe('use responder action data hooks', () => { statusCode: 500, }); }); - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current.tooltip); + const { result } = renderHook(); + await waitFor(() => expect(result.current.tooltip).not.toEqual('Loading')); expect(result.current).toEqual( getExpectedResponderActionData({ @@ -231,7 +235,7 @@ describe('use responder action data hooks', () => { describe('useResponderActionData() hook', () => { let hookProps: UseResponderActionDataProps; - let renderHook: () => RenderHookResult<UseResponderActionDataProps, ResponderActionData>; + let renderHook: () => RenderHookResult<ResponderActionData, UseResponderActionDataProps>; beforeEach(() => { endpointMetadataHttpMocks(appContextMock.coreStart.http); @@ -241,15 +245,13 @@ describe('use responder action data hooks', () => { onClick: onClickMock, }; renderHook = () => { - return appContextMock.renderHook<UseResponderActionDataProps, ResponderActionData>(() => - useResponderActionData(hookProps) - ); + return appContextMock.renderHook(() => useResponderActionData(hookProps)); }; }); it('should show action enabled when agentType is Endpoint and host is enabled', async () => { - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current.isDisabled); + const { result } = renderHook(); + await waitFor(() => expect(result.current.isDisabled).toBe(false)); expect(result.current).toEqual(getExpectedResponderActionData()); }); @@ -266,9 +268,13 @@ describe('use responder action data hooks', () => { }); it('should call `onClick` prop when action is enabled', async () => { - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current.isDisabled); - result.current.handleResponseActionsClick(); + const { result } = renderHook(); + + await waitFor(() => expect(result.current.isDisabled).toBe(false)); + + act(() => { + result.current.handleResponseActionsClick(); + }); expect(onClickMock).toHaveBeenCalled(); }); @@ -276,7 +282,10 @@ describe('use responder action data hooks', () => { it('should not call `onCLick` prop when action is disabled', () => { hookProps.agentType = 'sentinel_one'; const { result } = renderHook(); - result.current.handleResponseActionsClick(); + + act(() => { + result.current.handleResponseActionsClick(); + }); expect(onClickMock).not.toHaveBeenCalled(); }); diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx index 5d1d2ab2eaba..16f9640807b5 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_enable_data_feed.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useEnableDataFeed } from './use_enable_data_feed'; import { TestProviders } from '../../../mock'; @@ -78,21 +78,18 @@ describe('useSecurityJobsHelpers', () => { resolvePromiseCb = resolve; }) ); - const { result, waitForNextUpdate } = renderHook(() => useEnableDataFeed(), { + const { result } = renderHook(() => useEnableDataFeed(), { wrapper, }); expect(result.current.isLoading).toBe(false); await act(async () => { const enableDataFeedPromise = result.current.enableDatafeed(JOB, TIMESTAMP); - - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(true); - resolvePromiseCb({}); await enableDataFeedPromise; - expect(result.current.isLoading).toBe(false); }); + + await waitFor(() => expect(result.current.isLoading).toBe(false)); }); it('does not call setupMlJob if job is already installed', async () => { diff --git a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts index 1451054fb882..af3120a4e7b9 100644 --- a/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts +++ b/x-pack/plugins/security_solution/public/common/components/ml_popover/hooks/use_security_jobs.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { hasMlAdminPermissions } from '../../../../../common/machine_learning/has_ml_admin_permissions'; import { hasMlLicense } from '../../../../../common/machine_learning/has_ml_license'; import { useAppToasts } from '../../../hooks/use_app_toasts'; @@ -71,33 +71,31 @@ describe('useSecurityJobs', () => { bucketSpanSeconds: 900, }; - const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(), { + const { result } = renderHook(() => useSecurityJobs(), { wrapper: TestProviders, }); - await waitForNextUpdate(); - - expect(result.current.jobs).toHaveLength(6); + await waitFor(() => expect(result.current.jobs).toHaveLength(6)); expect(result.current.jobs).toEqual(expect.arrayContaining([expectedSecurityJob])); }); it('returns those permissions', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSecurityJobs(), { + const { result } = renderHook(() => useSecurityJobs(), { wrapper: TestProviders, }); - await waitForNextUpdate(); - - expect(result.current.isMlAdmin).toEqual(true); - expect(result.current.isLicensed).toEqual(true); + await waitFor(() => { + expect(result.current.isMlAdmin).toEqual(true); + expect(result.current.isLicensed).toEqual(true); + }); }); it('renders a toast error if an ML call fails', async () => { (getModules as jest.Mock).mockRejectedValue('whoops'); - const { waitFor } = renderHook(() => useSecurityJobs(), { + renderHook(() => useSecurityJobs(), { wrapper: TestProviders, }); // addError might be called after an arbitrary number of renders, so we - // need to use waitFor here instead of waitForNextUpdate + // need to use waitFor here instead of waitFor await waitFor(() => { expect(appToastsMock.addError).toHaveBeenCalledWith('whoops', { title: 'Security job fetch failure', diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.test.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.test.tsx index 0f59bbbccb8a..0aed8dc19663 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.test.tsx @@ -34,6 +34,20 @@ describe('Security Solution Navigation', () => { beforeEach(() => { jest.clearAllMocks(); }); + describe('while chrome style is undefined', () => { + beforeAll(() => { + mockGetChromeStyle$.mockReturnValue(of()); + }); + + it('should return proper navigation props', async () => { + const { result } = renderHook(useSecuritySolutionNavigation); + expect(result.current).toEqual(undefined); + + // check rendering of SecuritySideNav children + expect(mockSecuritySideNav).not.toHaveBeenCalled(); + }); + }); + describe('when classic navigation is enabled', () => { beforeAll(() => { mockGetChromeStyle$.mockReturnValue(of('classic')); @@ -77,9 +91,9 @@ describe('Security Solution Navigation', () => { mockGetChromeStyle$.mockReturnValue(of('project')); }); - it('should return undefined props when disabled', () => { + it('should return null props when disabled', () => { const { result } = renderHook(useSecuritySolutionNavigation); - expect(result.current).toEqual(undefined); + expect(result.current).toEqual(null); }); it('should initialize breadcrumbs', () => { diff --git a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.tsx b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.tsx index a2f54c04ca46..9abebcbb359c 100644 --- a/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.tsx +++ b/x-pack/plugins/security_solution/public/common/components/navigation/use_security_solution_navigation/use_security_solution_navigation.tsx @@ -23,16 +23,20 @@ const translatedNavTitle = i18n.translate('xpack.securitySolution.navigation.mai defaultMessage: 'Security', }); -export const useSecuritySolutionNavigation = (): KibanaPageTemplateProps['solutionNav'] => { +export const useSecuritySolutionNavigation = (): KibanaPageTemplateProps['solutionNav'] | null => { const { chrome } = useKibana().services; const chromeStyle$ = useMemo(() => chrome.getChromeStyle$(), [chrome]); - const chromeStyle = useObservable(chromeStyle$, 'classic'); + const chromeStyle = useObservable(chromeStyle$, undefined); useBreadcrumbsNav(); + if (chromeStyle === undefined) { + return undefined; // wait for chromeStyle to be initialized + } + if (chromeStyle === 'project') { - // new shared-ux 'project' navigation enabled, return undefined to disable the 'classic' navigation - return undefined; + // new shared-ux 'project' navigation enabled, return null to disable the 'classic' navigation + return null; } return { diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx index 6b264a4dc759..871750d5ad00 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/lens_embeddable.tsx @@ -19,7 +19,6 @@ import type { TypedLensByValueInput, XYState, } from '@kbn/lens-plugin/public'; -import type { LensBaseEmbeddableInput } from '@kbn/lens-plugin/public/embeddable'; import { setAbsoluteRangeDatePicker } from '../../store/inputs/actions'; import { useKibana } from '../../lib/kibana'; import { useLensAttributes } from './use_lens_attributes'; @@ -159,7 +158,7 @@ const LensEmbeddableComponent: React.FC<LensEmbeddableComponentProps> = ({ [dispatch, inputsModelId] ); - const onFilterCallback = useCallback<Required<LensBaseEmbeddableInput>['onFilter']>( + const onFilterCallback = useCallback<Required<TypedLensByValueInput>['onFilter']>( (event) => { if (disableOnClickFilter) { event.preventDefault(); diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_embeddable_inspect.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_embeddable_inspect.tsx index ee577d4a310d..152930fc7649 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_embeddable_inspect.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_embeddable_inspect.tsx @@ -5,14 +5,14 @@ * 2.0. */ -import type { LensBaseEmbeddableInput } from '@kbn/lens-plugin/public/embeddable'; +import type { LensEmbeddableInput } from '@kbn/lens-plugin/public'; import { useCallback } from 'react'; import type { OnEmbeddableLoaded, Request } from './types'; import { getRequestsAndResponses } from './utils'; export const useEmbeddableInspect = (onEmbeddableLoad?: OnEmbeddableLoaded) => { - const setInspectData = useCallback<NonNullable<LensBaseEmbeddableInput['onLoad']>>( + const setInspectData = useCallback<NonNullable<LensEmbeddableInput['onLoad']>>( (isLoading, adapters) => { if (!adapters) { return; diff --git a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx index 8ed7d40519ac..3d6bb712e9d9 100644 --- a/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx +++ b/x-pack/plugins/security_solution/public/common/components/visualization_actions/use_lens_attributes.test.tsx @@ -22,6 +22,7 @@ import { useSourcererDataView } from '../../../sourcerer/containers'; import { kpiHostMetricLensAttributes } from './lens_attributes/hosts/kpi_host_metric'; import { useRouteSpy } from '../../utils/route/use_route_spy'; import { SecurityPageName } from '../../../app/types'; +import type { Query } from '@kbn/es-query'; import { getEventsHistogramLensAttributes } from './lens_attributes/common/events'; jest.mock('../../../sourcerer/containers'); @@ -147,7 +148,7 @@ describe('useLensAttributes', () => { { wrapper } ); - expect(result?.current?.state.query.query).toEqual(''); + expect((result?.current?.state.query as Query).query).toEqual(''); expect(result?.current?.state.filters).toEqual([ ...getExternalAlertLensAttributes().state.filters, diff --git a/x-pack/plugins/security_solution/public/common/hooks/is_in_security_app.ts b/x-pack/plugins/security_solution/public/common/hooks/is_in_security_app.ts new file mode 100644 index 000000000000..8714c2129bc6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/common/hooks/is_in_security_app.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 useObservable from 'react-use/lib/useObservable'; +import { useMemo } from 'react'; +import { APP_UI_ID } from '../../../common'; +import { useKibana } from '../lib/kibana'; + +export const isInSecurityApp = (currentAppId?: string): boolean => { + return !!currentAppId && currentAppId === APP_UI_ID; +}; + +export const useIsInSecurityApp = () => { + const { + services: { application }, + } = useKibana(); + + const currentAppId = useObservable(application.currentAppId$); + + return useMemo(() => isInSecurityApp(currentAppId), [currentAppId]); +}; diff --git a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx index 23abdab4d14f..178785698914 100644 --- a/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/endpoint/app_context_render.tsx @@ -9,18 +9,21 @@ import type { ReactPortal } from 'react'; import React from 'react'; import type { MemoryHistory } from 'history'; import { createMemoryHistory } from 'history'; -import type { RenderOptions, RenderResult } from '@testing-library/react'; -import { render as reactRender } from '@testing-library/react'; +import type { + RenderOptions, + RenderResult, + RenderHookResult, + RenderHookOptions, +} from '@testing-library/react'; +import { + render as reactRender, + waitFor, + renderHook as reactRenderHook, +} from '@testing-library/react'; import type { Action, Reducer, Store } from 'redux'; import { QueryClient } from '@tanstack/react-query'; import { coreMock } from '@kbn/core/public/mocks'; import { PLUGIN_ID } from '@kbn/fleet-plugin/common'; -import type { RenderHookOptions, RenderHookResult } from '@testing-library/react-hooks'; -import { renderHook as reactRenderHook } from '@testing-library/react-hooks'; -import type { - ReactHooksRenderer, - WrapperComponent, -} from '@testing-library/react-hooks/src/types/react'; import type { UseBaseQueryResult } from '@tanstack/react-query'; import ReactDOM from 'react-dom'; import type { DeepReadonly } from 'utility-types'; @@ -101,17 +104,16 @@ export type WaitForReactHookState = > | false; -type HookRendererFunction<TProps, TResult> = (props: TProps) => TResult; +type HookRendererFunction<TResult, TProps> = (props: TProps) => TResult; /** * A utility renderer for hooks that return React Query results */ export type ReactQueryHookRenderer< - // eslint-disable-next-line @typescript-eslint/no-explicit-any - TProps = any, + TProps = unknown, TResult extends UseBaseQueryResult = UseBaseQueryResult > = ( - hookFn: HookRendererFunction<TProps, TResult>, + hookFn: HookRendererFunction<TResult, TProps>, /** * If defined (default is `isSuccess`), the renderer will wait for the given react * query response state value to be true @@ -150,7 +152,15 @@ export interface AppContextTestRender { /** * Renders a hook within a mocked security solution app context */ - renderHook: ReactHooksRenderer['renderHook']; + renderHook: <TResult, TProps>( + hookFn: HookRendererFunction<TResult, TProps>, + options?: RenderHookOptions<TProps> + ) => RenderHookResult<TResult, TProps>; + + /** + * Waits the return value of the callback provided to is truthy + */ + waitFor: typeof waitFor; /** * A helper utility for rendering specifically hooks that wrap ReactQuery @@ -305,12 +315,12 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { }); }; - const renderHook: ReactHooksRenderer['renderHook'] = <TProps, TResult>( - hookFn: HookRendererFunction<TProps, TResult>, + const renderHook = <TResult, TProps>( + hookFn: HookRendererFunction<TResult, TProps>, options: RenderHookOptions<TProps> = {} - ): RenderHookResult<TProps, TResult> => { - return reactRenderHook<TProps, TResult>(hookFn, { - wrapper: AppWrapper as WrapperComponent<TProps>, + ) => { + return reactRenderHook<TResult, TProps>(hookFn, { + wrapper: AppWrapper as React.FC<React.PropsWithChildren>, ...options, }); }; @@ -319,16 +329,17 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { TProps, TResult extends UseBaseQueryResult = UseBaseQueryResult >( - hookFn: HookRendererFunction<TProps, TResult>, + hookFn: HookRendererFunction<TResult, TProps>, + /** + * If defined (default is `isSuccess`), the renderer will wait for the given react query to be truthy + */ waitForHook: WaitForReactHookState = 'isSuccess', options: RenderHookOptions<TProps> = {} ) => { - const { result: hookResult, waitFor } = renderHook<TProps, TResult>(hookFn, options); + const { result: hookResult } = renderHook<TResult, TProps>(hookFn, options); if (waitForHook) { - await waitFor(() => { - return hookResult.current[waitForHook]; - }); + await waitFor(() => expect(hookResult.current[waitForHook]).toBe(true)); } return hookResult.current; @@ -400,6 +411,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => { setExperimentalFlag, getUserPrivilegesMockSetter, queryClient, + waitFor, }; }; diff --git a/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx b/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx index a987e99a67d0..69cd24e4ff45 100644 --- a/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx +++ b/x-pack/plugins/security_solution/public/common/mock/expandable_flyout.tsx @@ -5,8 +5,6 @@ * 2.0. */ -import React from 'react'; - export const createExpandableFlyoutApiMock = () => ({ closeFlyout: jest.fn(), closeLeftPanel: jest.fn(), @@ -18,17 +16,3 @@ export const createExpandableFlyoutApiMock = () => ({ openPreviewPanel: jest.fn(), openRightPanel: jest.fn(), }); - -export const createExpandableFlyoutMock = () => { - return { - useExpandableFlyoutApi: jest.fn().mockReturnValue(createExpandableFlyoutApiMock()), - useExpandableFlyoutState: jest.fn(), - ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}</>, - withExpandableFlyoutProvider: <T extends object>(Component: React.ComponentType<T>) => { - return (props: T) => { - return <Component {...props} />; - }; - }, - ExpandableFlyout: jest.fn(), - }; -}; diff --git a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts b/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts deleted file mode 100644 index 5879e2a256cc..000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { act, renderHook } from '@testing-library/react-hooks'; -import { useSetFieldValueWithCallback } from './use_set_field_value_cb'; - -const initialValue = 'initial value'; -const newValue = 'new value'; -const callback = jest.fn(); -const initialProps = { field: 'theField', setFieldValue: () => {}, value: initialValue }; - -describe('set field value callback', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - it('invokes the callback after value is set', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(newValue, callback); - }); - rerender({ ...initialProps, value: newValue }); - expect(callback).toHaveBeenCalled(); - }); - it('invokes the callback after value is set to equal value', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(initialValue, callback); - }); - rerender(); - expect(callback).toHaveBeenCalled(); - }); - it('does not invoke the callback if value does not update', () => { - const { result, rerender } = renderHook((props) => useSetFieldValueWithCallback(props), { - initialProps, - }); - act(() => { - result.current(newValue, callback); - }); - rerender(); - expect(callback).not.toHaveBeenCalled(); - }); -}); diff --git a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts b/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts deleted file mode 100644 index c067e1747b4f..000000000000 --- a/x-pack/plugins/security_solution/public/common/utils/use_set_field_value_cb.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { FormHook } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib'; -import { useCallback, useEffect, useRef, useState } from 'react'; - -export const useSetFieldValueWithCallback = ({ - field, - setFieldValue, - value, -}: { - field: string; - value: unknown; - setFieldValue: FormHook['setFieldValue']; -}) => { - const isWaitingRef = useRef(false); - const valueRef = useRef<unknown>(); - const [callback, setCallback] = useState<() => void>(() => null); - - useEffect(() => { - if (isWaitingRef.current && value === valueRef.current) { - isWaitingRef.current = false; - valueRef.current = undefined; - callback(); - } - }, [value, callback]); - - return useCallback( - (v: unknown, cb: () => void) => { - setFieldValue(field, v); - - setCallback(() => cb); - valueRef.current = v; - isWaitingRef.current = true; - }, - [field, setFieldValue] - ); -}; diff --git a/x-pack/plugins/security_solution/public/contract_components.ts b/x-pack/plugins/security_solution/public/contract_components.ts index 8f5072f43f03..f7c255bcd34b 100644 --- a/x-pack/plugins/security_solution/public/contract_components.ts +++ b/x-pack/plugins/security_solution/public/contract_components.ts @@ -11,6 +11,7 @@ import type { Observable } from 'rxjs'; export type ContractComponents = Partial<{ GetStarted: React.ComponentType<{ indicesExist?: boolean }>; DashboardsLandingCallout: React.ComponentType<{}>; + EnablementModalCallout: React.ComponentType<{}>; }>; export type SetComponents = (components: ContractComponents) => void; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/alert_suppression_edit/components/alert_suppression_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/alert_suppression_edit/components/alert_suppression_edit.tsx index 5c6099529e92..d7cea2a00ba6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/alert_suppression_edit/components/alert_suppression_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/alert_suppression_edit/components/alert_suppression_edit.tsx @@ -54,11 +54,9 @@ export const AlertSuppressionEdit = memo(function AlertSuppressionEdit({ </> ); - return disabled && disabledText ? ( - <EuiToolTip position="right" content={disabledText}> + return ( + <EuiToolTip position="right" content={disabled && disabledText}> {content} </EuiToolTip> - ) : ( - content ); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx index 079735aab3c4..c7ef28f5ed90 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_bar.tsx @@ -18,8 +18,8 @@ import type { FieldHook } from '../../../../shared_imports'; import { FilterBar } from '../../../../common/components/filter_bar'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import type { EqlOptions } from '../../../../../common/search_strategy'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import { useKibana } from '../../../../common/lib/kibana'; -import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar'; import type { EqlQueryBarFooterProps } from './footer'; import { EqlQueryBarFooter } from './footer'; import { getValidationResults } from './validators'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx index 5b519cb43c84..75d3412705fd 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_edit.tsx @@ -11,11 +11,11 @@ import { debounceAsync } from '@kbn/securitysolution-utils'; import type { FormData, FieldConfig, ValidationFuncArg } from '../../../../shared_imports'; import { UseMultiFields } from '../../../../shared_imports'; import type { EqlFieldsComboBoxOptions, EqlOptions } from '../../../../../common/search_strategy'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import { queryRequiredValidatorFactory } from '../../../rule_creation_ui/validators/query_required_validator_factory'; import { eqlQueryValidatorFactory } from './eql_query_validator_factory'; import { EqlQueryBar } from './eql_query_bar'; import * as i18n from './translations'; -import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar'; interface EqlQueryEditProps { path: string; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts index 54a0b3e3b6a6..284d0670dfbc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/eql_query_edit/eql_query_validator_factory.ts @@ -8,8 +8,8 @@ import { isEmpty } from 'lodash'; import type { FormData, ValidationError, ValidationFunc } from '../../../../shared_imports'; import { KibanaServices } from '../../../../common/lib/kibana'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; import type { EqlOptions } from '../../../../../common/search_strategy'; -import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar'; import type { EqlResponseError } from '../../../../common/hooks/eql/api'; import { EQL_ERROR_CODES, validateEql } from '../../../../common/hooks/eql/api'; import { EQL_VALIDATION_REQUEST_ERROR } from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_info_icon.tsx similarity index 71% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_info_icon.tsx index d0b4cee6752a..933a45004fc7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_info_icon.tsx @@ -5,21 +5,19 @@ * 2.0. */ -import React from 'react'; +import React, { memo } from 'react'; import { EuiPopover, EuiText, EuiButtonIcon, EuiLink } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import * as i18n from './translations'; - -import { useBoolState } from '../../../../common/hooks/use_bool_state'; +import { useBoolean } from '@kbn/react-hooks'; import { useKibana } from '../../../../common/lib/kibana'; +import * as i18n from './translations'; /** * Icon and popover that gives hint to users how to get started with ES|QL rules */ -const EsqlInfoIconComponent = () => { +export const EsqlInfoIcon = memo(function EsqlInfoIcon(): JSX.Element { const { docLinks } = useKibana().services; - - const [isPopoverOpen, , closePopover, togglePopover] = useBoolState(); + const [isPopoverOpen, { off: closePopover, on: togglePopover }] = useBoolean(false); const button = ( <EuiButtonIcon iconType="iInCircle" onClick={togglePopover} aria-label={i18n.ARIA_LABEL} /> @@ -29,13 +27,13 @@ const EsqlInfoIconComponent = () => { <EuiPopover button={button} isOpen={isPopoverOpen} closePopover={closePopover}> <EuiText size="s"> <FormattedMessage - id="xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipContent" + id="xpack.securitySolution.ruleManagement.esqlQuery.esqlInfoTooltipContent" defaultMessage="Check out our {createEsqlRuleTypeLink} to get started using ES|QL rules." values={{ createEsqlRuleTypeLink: ( <EuiLink href={docLinks.links.securitySolution.createEsqlRuleType} target="_blank"> <FormattedMessage - id="xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipLink" + id="xpack.securitySolution.ruleManagement.esqlQuery.esqlInfoTooltipLink" defaultMessage="documentation" /> </EuiLink> @@ -45,8 +43,4 @@ const EsqlInfoIconComponent = () => { </EuiText> </EuiPopover> ); -}; - -export const EsqlInfoIcon = React.memo(EsqlInfoIconComponent); - -EsqlInfoIcon.displayName = 'EsqlInfoIcon'; +}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx new file mode 100644 index 000000000000..695a3d121c9a --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/esql_query_edit.tsx @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { memo, useMemo } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; +import type { DataViewBase } from '@kbn/es-query'; +import { debounceAsync } from '@kbn/securitysolution-utils'; +import type { FieldConfig } from '../../../../shared_imports'; +import { UseField } from '../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../rule_creation_ui/components/query_bar_field'; +import { QueryBarField } from '../../../rule_creation_ui/components/query_bar_field'; +import { esqlQueryRequiredValidator } from './validators/esql_query_required_validator'; +import { esqlQueryValidatorFactory } from './validators/esql_query_validator_factory'; +import { EsqlInfoIcon } from './esql_info_icon'; +import * as i18n from './translations'; + +interface EsqlQueryEditProps { + path: string; + fieldsToValidateOnChange?: string | string[]; + dataView: DataViewBase; + required?: boolean; + loading?: boolean; + disabled?: boolean; + skipIdColumnCheck?: boolean; + onValidityChange?: (arg: boolean) => void; +} + +export const EsqlQueryEdit = memo(function EsqlQueryEdit({ + path, + fieldsToValidateOnChange, + dataView, + required = false, + loading = false, + disabled = false, + skipIdColumnCheck, + onValidityChange, +}: EsqlQueryEditProps): JSX.Element { + const queryClient = useQueryClient(); + const componentProps = useMemo( + () => ({ + isDisabled: disabled, + isLoading: loading, + indexPattern: dataView, + idAria: 'ruleEsqlQueryBar', + dataTestSubj: 'ruleEsqlQueryBar', + onValidityChange, + }), + [dataView, loading, disabled, onValidityChange] + ); + const fieldConfig: FieldConfig<FieldValueQueryBar> = useMemo( + () => ({ + label: i18n.ESQL_QUERY, + labelAppend: <EsqlInfoIcon />, + fieldsToValidateOnChange: fieldsToValidateOnChange + ? [path, fieldsToValidateOnChange].flat() + : undefined, + validations: [ + ...(required + ? [ + { + validator: esqlQueryRequiredValidator, + }, + ] + : []), + { + validator: debounceAsync( + esqlQueryValidatorFactory({ queryClient, skipIdColumnCheck }), + 300 + ), + }, + ], + }), + [required, path, fieldsToValidateOnChange, queryClient, skipIdColumnCheck] + ); + + return ( + <UseField + path={path} + component={QueryBarField} + componentProps={componentProps} + config={fieldConfig} + /> + ); +}); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/index.ts similarity index 76% rename from x-pack/plugins/enterprise_search/public/applications/shared/error_state/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/index.ts index b8e1783dbe90..43eef8c21183 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/error_state/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/index.ts @@ -5,4 +5,5 @@ * 2.0. */ -export { ErrorStatePrompt, ErrorStateCallout } from './error_state_prompt'; +export * from './esql_query_edit'; +export * from './validators/error_codes'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/translations.ts similarity index 62% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/translations.ts index 8729f7b0dd3b..9e48318c1c8b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_info_icon/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/translations.ts @@ -7,8 +7,15 @@ import { i18n } from '@kbn/i18n'; +export const ESQL_QUERY = i18n.translate( + 'xpack.securitySolution.ruleManagement.fields.esqlQuery.label', + { + defaultMessage: 'ES|QL query', + } +); + export const ARIA_LABEL = i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoAriaLabel', + 'xpack.securitySolution.ruleManagement.fields.esqlQuery.ariaLabel', { defaultMessage: `Open help popover`, } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/error_codes.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/error_codes.ts new file mode 100644 index 000000000000..5455dd1db5f0 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/error_codes.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 enum ESQL_ERROR_CODES { + INVALID_ESQL = 'ERR_INVALID_ESQL', + INVALID_SYNTAX = 'ERR_INVALID_SYNTAX', + ERR_MISSING_ID_FIELD_FROM_RESULT = 'ERR_MISSING_ID_FIELD_FROM_RESULT', +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_required_validator.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_required_validator.ts new file mode 100644 index 000000000000..d3f71eaaf5a8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_required_validator.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { fieldValidators, type FormData, type ValidationFunc } from '../../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; +import * as i18n from './translations'; + +export const esqlQueryRequiredValidator: ValidationFunc<FormData, string, FieldValueQueryBar> = ( + data +) => { + const { value } = data; + const esqlQuery = value.query.query as string; + + return fieldValidators.emptyField(i18n.ESQL_QUERY_VALIDATION_REQUIRED)({ + ...data, + value: esqlQuery, + }); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.test.ts new file mode 100644 index 000000000000..2799a606d3d9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.test.ts @@ -0,0 +1,182 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { QueryClient } from '@tanstack/react-query'; +import { getESQLQueryColumns } from '@kbn/esql-utils'; +import type { FormData, ValidationFunc, ValidationFuncArg } from '../../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; +import { esqlQueryValidatorFactory } from './esql_query_validator_factory'; +import { ESQL_ERROR_CODES } from './error_codes'; + +jest.mock('@kbn/esql-utils', () => ({ + getESQLQueryColumns: jest.fn().mockResolvedValue([{ id: '_id' }]), +})); +jest.mock('../../../../../common/lib/kibana'); + +describe('esqlQueryValidator', () => { + describe('ES|QL query syntax', () => { + it.each([['incorrect syntax'], ['from test* metadata']])( + 'reports incorrect syntax in "%s"', + (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.INVALID_SYNTAX, + }) + ); + + it.each([ + ['from test* metadata _id'], + [ + 'FROM kibana_sample_data_logs | STATS total_bytes = SUM(bytes) BY host | WHERE total_bytes > 200000 | SORT total_bytes DESC | LIMIT 10', + ], + [ + `from packetbeat* metadata + _id + | limit 100`, + ], + [ + `FROM kibana_sample_data_logs | + STATS total_bytes = SUM(bytes) BY host | + WHERE total_bytes > 200000 | + SORT total_bytes DESC | + LIMIT 10`, + ], + ])('succeeds validation for correct syntax in "%s"', (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined() + ); + }); + + describe('METADATA operator validation', () => { + it.each([ + ['from test*'], + ['from metadata*'], + ['from test* | keep metadata'], + ['from test* | eval x="metadata _id"'], + ])('reports when METADATA operator is missing in a NON aggregating query "%s"', (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + }) + ); + + it.each([ + ['from test* metadata _id'], + ['from test* metadata _id, _index'], + ['from test* metadata _index, _id'], + ['from test* metadata _id '], + ['from test* metadata _id '], + ['from test* metadata _id | limit 10'], + [ + `from packetbeat* metadata + + _id + | limit 100`, + ], + ])( + 'succeeds validation when METADATA operator EXISTS in a NON aggregating query "%s"', + (esqlQuery) => + expect( + createValidator()({ + value: createEsqlQueryFieldValue(esqlQuery), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined() + ); + + it('succeeds validation when METADATA operator is missing in an aggregating query "from test* | stats c = count(*) by fieldA"', () => + expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test* | stats c = count(*) by fieldA'), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined()); + }); + + describe('METADATA _id field validation for NON aggregating queries', () => { + it('reports when METADATA "_id" field is missing', () => { + getESQLQueryColumnsMock.mockResolvedValue([{ id: 'column1' }, { id: 'column2' }]); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test*'), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + }); + }); + + it('succeeds validation when METADATA "_id" field EXISTS', async () => { + getESQLQueryColumnsMock.mockResolvedValue([{ id: '_id' }, { id: 'column1' }]); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test* metadata _id'), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined(); + }); + }); + + describe('METADATA _id field validation for aggregating queries', () => { + it('succeeds validation when METADATA operator with "_id" field is missing', () => { + getESQLQueryColumnsMock.mockResolvedValue([{ id: 'column1' }, { id: 'column2' }]); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue( + 'from test* metadata someField | stats c = count(*) by fieldA' + ), + } as EsqlQueryValidatorArgs) + ).resolves.toBeUndefined(); + }); + }); + + describe('when getESQLQueryColumns fails', () => { + it('returns a validation error', () => { + // suppress the expected error messages + jest.spyOn(console, 'error').mockReturnValue(); + + getESQLQueryColumnsMock.mockRejectedValue(new Error('some error')); + + return expect( + createValidator()({ + value: createEsqlQueryFieldValue('from test* metadata _id'), + } as EsqlQueryValidatorArgs) + ).resolves.toMatchObject({ + code: ESQL_ERROR_CODES.INVALID_ESQL, + message: 'Error validating ES|QL: "some error"', + }); + }); + }); +}); + +type EsqlQueryValidatorArgs = ValidationFuncArg<FormData, FieldValueQueryBar>; + +const getESQLQueryColumnsMock = getESQLQueryColumns as jest.Mock; + +function createValidator(): ValidationFunc<FormData, string, FieldValueQueryBar> { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 60 * 1000, + }, + }, + }); + + return esqlQueryValidatorFactory({ queryClient }); +} + +function createEsqlQueryFieldValue(esqlQuery: string): Readonly<FieldValueQueryBar> { + return { query: { query: esqlQuery, language: 'esql' }, filters: [], saved_id: null }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.ts new file mode 100644 index 000000000000..90cdaff14cc9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/esql_query_validator_factory.ts @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { QueryClient } from '@tanstack/react-query'; +import type { DatatableColumn } from '@kbn/expressions-plugin/common'; +import type { ESQLAstQueryExpression, ESQLCommandOption } from '@kbn/esql-ast'; +import { parse } from '@kbn/esql-ast'; +import { isAggregatingQuery } from '@kbn/securitysolution-utils'; +import { isColumnItem, isOptionItem } from '@kbn/esql-validation-autocomplete'; +import type { FormData, ValidationError, ValidationFunc } from '../../../../../shared_imports'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; +import { fetchEsqlQueryColumns } from '../../../logic/esql_query_columns'; +import { ESQL_ERROR_CODES } from './error_codes'; +import * as i18n from './translations'; + +interface EsqlQueryValidatorFactoryParams { + queryClient: QueryClient; + /** + * This is a temporal fix to unlock prebuilt rule customization workflow + */ + skipIdColumnCheck?: boolean; +} + +export function esqlQueryValidatorFactory({ + queryClient, + skipIdColumnCheck, +}: EsqlQueryValidatorFactoryParams): ValidationFunc<FormData, string, FieldValueQueryBar> { + return async (...args) => { + const [{ value }] = args; + const esqlQuery = value.query.query as string; + + if (esqlQuery.trim() === '') { + return; + } + + try { + const { isEsqlQueryAggregating, hasMetadataOperator, errors } = parseEsqlQuery(esqlQuery); + + // Check if there are any syntax errors + if (errors.length) { + return constructSyntaxError(new Error(errors[0].message)); + } + + // non-aggregating query which does not have metadata, is not a valid one + if (!isEsqlQueryAggregating && !hasMetadataOperator) { + return { + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + message: i18n.ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR, + }; + } + + if (skipIdColumnCheck) { + return; + } + + const columns = await fetchEsqlQueryColumns({ + esqlQuery, + queryClient, + }); + + // for non-aggregating query, we want to disable queries w/o _id property returned in response + if (!isEsqlQueryAggregating && !hasIdColumn(columns)) { + return { + code: ESQL_ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, + message: i18n.ESQL_VALIDATION_MISSING_ID_FIELD_IN_QUERY_ERROR, + }; + } + } catch (error) { + return constructValidationError(error); + } + }; +} + +function hasIdColumn(columns: DatatableColumn[]): boolean { + return columns.some(({ id }) => '_id' === id); +} + +/** + * check if esql query valid for Security rule: + * - if it's non aggregation query it must have metadata operator + */ +function parseEsqlQuery(query: string) { + const { root, errors } = parse(query); + const isEsqlQueryAggregating = isAggregatingQuery(root); + + return { + errors, + isEsqlQueryAggregating, + hasMetadataOperator: computeHasMetadataOperator(root), + }; +} + +/** + * checks whether query has metadata _id operator + */ +function computeHasMetadataOperator(astExpression: ESQLAstQueryExpression): boolean { + // Check whether the `from` command has `metadata` operator + const metadataOption = getMetadataOption(astExpression); + if (!metadataOption) { + return false; + } + + // Check whether the `metadata` operator has `_id` argument + const idColumnItem = metadataOption.args.find( + (fromArg) => isColumnItem(fromArg) && fromArg.name === '_id' + ); + if (!idColumnItem) { + return false; + } + + return true; +} + +function getMetadataOption(astExpression: ESQLAstQueryExpression): ESQLCommandOption | undefined { + const fromCommand = astExpression.commands.find((x) => x.name === 'from'); + + if (!fromCommand?.args) { + return undefined; + } + + // Check whether the `from` command has `metadata` operator + for (const fromArg of fromCommand.args) { + if (isOptionItem(fromArg) && fromArg.name === 'metadata') { + return fromArg; + } + } + + return undefined; +} + +function constructSyntaxError(error: Error): ValidationError { + return { + code: ESQL_ERROR_CODES.INVALID_SYNTAX, + message: error?.message + ? i18n.esqlValidationErrorMessage(error.message) + : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, + error, + }; +} + +function constructValidationError(error: Error): ValidationError { + return { + code: ESQL_ERROR_CODES.INVALID_ESQL, + message: error?.message + ? i18n.esqlValidationErrorMessage(error.message) + : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, + error, + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/translations.ts similarity index 72% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/translations.ts index 4d6dde31fd5b..21948a8863ec 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/components/esql_query_edit/validators/translations.ts @@ -7,28 +7,35 @@ import { i18n } from '@kbn/i18n'; +export const ESQL_QUERY_VALIDATION_REQUIRED = i18n.translate( + 'xpack.securitySolution.ruleManagement.esqlValidation.requiredError', + { + defaultMessage: 'An ES|QL query is required.', + } +); + export const ESQL_VALIDATION_UNKNOWN_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.esqlValidation.unknownError', + 'xpack.securitySolution.ruleManagement.esqlValidation.unknownError', { defaultMessage: 'Unknown error while validating ES|QL', } ); export const esqlValidationErrorMessage = (message: string) => - i18n.translate('xpack.securitySolution.detectionEngine.esqlValidation.errorMessage', { + i18n.translate('xpack.securitySolution.ruleManagement.esqlValidation.errorMessage', { values: { message }, defaultMessage: 'Error validating ES|QL: "{message}"', }); export const ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.esqlValidation.missingMetadataOperatorInQueryError', + 'xpack.securitySolution.ruleManagement.esqlValidation.missingMetadataOperatorInQueryError', { defaultMessage: `Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* metadata _id, _version, _index.`, } ); export const ESQL_VALIDATION_MISSING_ID_FIELD_IN_QUERY_ERROR = i18n.translate( - 'xpack.securitySolution.detectionEngine.esqlValidation.missingIdFieldInQueryError', + 'xpack.securitySolution.ruleManagement.esqlValidation.missingIdFieldInQueryError', { defaultMessage: `Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* metadata _id, _version, _index. In addition, the metadata properties (_id, _version, and _index) must be returned in the query response.`, } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_query_columns.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_query_columns.ts new file mode 100644 index 000000000000..be4c53a31cef --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_query_columns.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + FetchQueryOptions, + QueryClient, + QueryFunction, + QueryKey, +} from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import type { DatatableColumn } from '@kbn/expressions-plugin/common'; +import { getESQLQueryColumns } from '@kbn/esql-utils'; +import { KibanaServices } from '../../../common/lib/kibana'; + +const DEFAULT_STALE_TIME = 60 * 1000; + +interface FetchEsqlQueryColumnsParams { + esqlQuery: string; + queryClient: QueryClient; +} + +export async function fetchEsqlQueryColumns({ + esqlQuery, + queryClient, +}: FetchEsqlQueryColumnsParams): Promise<DatatableColumn[]> { + const data = await queryClient.fetchQuery(createSharedTanstackQueryOptions(esqlQuery)); + + if (data instanceof Error) { + throw data; + } + + return data; +} + +interface UseEsqlQueryColumnsResult { + columns: DatatableColumn[]; + isLoading: boolean; +} + +export function useEsqlQueryColumns(esqlQuery: string): UseEsqlQueryColumnsResult { + const { data, isLoading } = useQuery({ + ...createSharedTanstackQueryOptions(esqlQuery), + retryOnMount: false, + refetchOnMount: false, + refetchOnWindowFocus: false, + }); + + return { columns: !data || data instanceof Error ? [] : data, isLoading }; +} + +function createSharedTanstackQueryOptions( + esqlQuery: string +): FetchQueryOptions<DatatableColumn[] | Error> { + return { + queryKey: [esqlQuery.trim()], + queryFn: queryEsqlColumnsFactory(esqlQuery), + staleTime: DEFAULT_STALE_TIME, + retry: false, + }; +} + +function queryEsqlColumnsFactory( + esqlQuery: string +): QueryFunction<DatatableColumn[] | Error, QueryKey> { + return async ({ signal }) => { + if (esqlQuery.trim() === '') { + return []; + } + + try { + return await getESQLQueryColumns({ + esqlQuery, + search: KibanaServices.get().data.search.search, + signal, + }); + } catch (e) { + return e; + } + }; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.ts deleted file mode 100644 index 808597ff3649..000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.test.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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { parseEsqlQuery, computeHasMetadataOperator } from './esql_validator'; - -import { isAggregatingQuery } from '@kbn/securitysolution-utils'; - -jest.mock('@kbn/securitysolution-utils', () => ({ isAggregatingQuery: jest.fn() })); - -const isAggregatingQueryMock = isAggregatingQuery as jest.Mock; - -const getQeryAst = (query: string) => { - const { ast } = getAstAndSyntaxErrors(query); - return ast; -}; - -describe('computeHasMetadataOperator', () => { - it('should be false if query does not have operator', () => { - expect(computeHasMetadataOperator(getQeryAst('from test*'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata id'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from metadata*'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* | keep metadata'))).toBe(false); - expect(computeHasMetadataOperator(getQeryAst('from test* | eval x="metadata _id"'))).toBe( - false - ); - }); - it('should be true if query has operator', () => { - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id, _index'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _index, _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id | limit 10'))).toBe( - true - ); - expect( - computeHasMetadataOperator( - getQeryAst(`from packetbeat* metadata - - _id - | limit 100`) - ) - ).toBe(true); - - // still validates deprecated square bracket syntax - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id, _index'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _index, _id'))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id '))).toBe(true); - expect(computeHasMetadataOperator(getQeryAst('from test* metadata _id | limit 10'))).toBe( - true - ); - expect( - computeHasMetadataOperator( - getQeryAst(`from packetbeat* metadata - - _id - | limit 100`) - ) - ).toBe(true); - }); -}); - -describe('parseEsqlQuery', () => { - it('returns isMissingMetadataOperator true when query is not aggregating and does not have metadata operator', () => { - isAggregatingQueryMock.mockReturnValueOnce(false); - - expect(parseEsqlQuery('from test*')).toEqual({ - errors: [], - isEsqlQueryAggregating: false, - isMissingMetadataOperator: true, - }); - }); - - it('returns isMissingMetadataOperator false when query is not aggregating and has metadata operator', () => { - isAggregatingQueryMock.mockReturnValueOnce(false); - - expect(parseEsqlQuery('from test* metadata _id')).toEqual({ - errors: [], - isEsqlQueryAggregating: false, - isMissingMetadataOperator: false, - }); - }); - - it('returns isMissingMetadataOperator false when query is aggregating', () => { - isAggregatingQueryMock.mockReturnValue(true); - - expect(parseEsqlQuery('from test*')).toEqual({ - errors: [], - isEsqlQueryAggregating: true, - isMissingMetadataOperator: false, - }); - - expect(parseEsqlQuery('from test* metadata _id')).toEqual({ - errors: [], - isEsqlQueryAggregating: true, - isMissingMetadataOperator: false, - }); - }); - - it('returns error when query is syntactically invalid', () => { - isAggregatingQueryMock.mockReturnValueOnce(false); - - expect(parseEsqlQuery('aaa bbbb ssdasd')).toEqual({ - errors: expect.arrayContaining([ - expect.objectContaining({ - message: - "SyntaxError: mismatched input 'aaa' expecting {'explain', 'from', 'row', 'show'}", - }), - ]), - isEsqlQueryAggregating: false, - isMissingMetadataOperator: true, - }); - }); -}); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts deleted file mode 100644 index c508676cae92..000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/esql_validator.ts +++ /dev/null @@ -1,160 +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 { isEmpty } from 'lodash'; -import type { QueryClient } from '@tanstack/react-query'; -import { isAggregatingQuery } from '@kbn/securitysolution-utils'; - -import type { ESQLAst } from '@kbn/esql-ast'; -import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { isColumnItem, isOptionItem } from '@kbn/esql-validation-autocomplete'; -import { KibanaServices } from '../../../common/lib/kibana'; - -import type { ValidationError, ValidationFunc } from '../../../shared_imports'; -import { isEsqlRule } from '../../../../common/detection_engine/utils'; -import type { DefineStepRule } from '../../../detections/pages/detection_engine/rules/types'; -import type { FieldValueQueryBar } from '../../rule_creation_ui/components/query_bar'; -import * as i18n from './translations'; -import { getEsqlQueryConfig } from './get_esql_query_config'; -export type FieldType = 'string'; - -export enum ERROR_CODES { - INVALID_ESQL = 'ERR_INVALID_ESQL', - INVALID_SYNTAX = 'ERR_INVALID_SYNTAX', - ERR_MISSING_ID_FIELD_FROM_RESULT = 'ERR_MISSING_ID_FIELD_FROM_RESULT', -} - -const constructValidationError = (error: Error) => { - return { - code: ERROR_CODES.INVALID_ESQL, - message: error?.message - ? i18n.esqlValidationErrorMessage(error.message) - : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, - error, - }; -}; - -const constructSyntaxError = (error: Error) => { - return { - code: ERROR_CODES.INVALID_SYNTAX, - message: error?.message - ? i18n.esqlValidationErrorMessage(error.message) - : i18n.ESQL_VALIDATION_UNKNOWN_ERROR, - error, - }; -}; - -const getMetadataOption = (ast: ESQLAst) => { - const fromCommand = ast.find((astItem) => astItem.type === 'command' && astItem.name === 'from'); - - if (!fromCommand?.args) { - return undefined; - } - - // Check whether the `from` command has `metadata` operator - for (const fromArg of fromCommand.args) { - if (isOptionItem(fromArg) && fromArg.name === 'metadata') { - return fromArg; - } - } - - return undefined; -}; - -/** - * checks whether query has metadata _id operator - */ -export const computeHasMetadataOperator = (ast: ESQLAst) => { - // Check whether the `from` command has `metadata` operator - const metadataOption = getMetadataOption(ast); - if (!metadataOption) { - return false; - } - - // Check whether the `metadata` operator has `_id` argument - const idColumnItem = metadataOption.args.find( - (fromArg) => isColumnItem(fromArg) && fromArg.name === '_id' - ); - if (!idColumnItem) { - return false; - } - - return true; -}; - -/** - * form validator for ES|QL queryBar - */ -export const esqlValidator = async ( - ...args: Parameters<ValidationFunc> -): Promise<ValidationError<ERROR_CODES> | void | undefined> => { - const [{ value, formData, customData }] = args; - const { query: queryValue } = value as FieldValueQueryBar; - const query = queryValue.query as string; - const { ruleType } = formData as DefineStepRule; - - const needsValidation = isEsqlRule(ruleType) && !isEmpty(query); - if (!needsValidation) { - return; - } - - try { - const queryClient = (customData.value as { queryClient: QueryClient | undefined })?.queryClient; - - const services = KibanaServices.get(); - const { isEsqlQueryAggregating, isMissingMetadataOperator, errors } = parseEsqlQuery(query); - - // Check if there are any syntax errors - if (errors.length) { - return constructSyntaxError(new Error(errors[0].message)); - } - - if (isMissingMetadataOperator) { - return { - code: ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, - message: i18n.ESQL_VALIDATION_MISSING_METADATA_OPERATOR_IN_QUERY_ERROR, - }; - } - - const columns = await queryClient?.fetchQuery( - getEsqlQueryConfig({ esqlQuery: query, search: services.data.search.search }) - ); - - if (columns && 'error' in columns) { - return constructValidationError(columns.error); - } - - // check whether _id field is present in response - const isIdFieldPresent = (columns ?? []).find(({ id }) => '_id' === id); - // for non-aggregating query, we want to disable queries w/o _id property returned in response - if (!isEsqlQueryAggregating && !isIdFieldPresent) { - return { - code: ERROR_CODES.ERR_MISSING_ID_FIELD_FROM_RESULT, - message: i18n.ESQL_VALIDATION_MISSING_ID_FIELD_IN_QUERY_ERROR, - }; - } - } catch (error) { - return constructValidationError(error); - } -}; - -/** - * check if esql query valid for Security rule: - * - if it's non aggregation query it must have metadata operator - */ -export const parseEsqlQuery = (query: string) => { - const { ast, errors } = getAstAndSyntaxErrors(query); - - const isEsqlQueryAggregating = isAggregatingQuery(ast); - - return { - errors, - isEsqlQueryAggregating, - // non-aggregating query which does not have metadata, is not a valid one - isMissingMetadataOperator: !isEsqlQueryAggregating && !computeHasMetadataOperator(ast), - }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/get_esql_query_config.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/get_esql_query_config.ts deleted file mode 100644 index c7d4f9184f18..000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation/logic/get_esql_query_config.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { getESQLQueryColumns } from '@kbn/esql-utils'; -import type { ISearchGeneric } from '@kbn/search-types'; - -/** - * react-query configuration to be used to fetch ES|QL fields - * it sets limit in query to 0, so we don't fetch unnecessary results, only fields - */ -export const getEsqlQueryConfig = ({ - esqlQuery, - search, -}: { - esqlQuery: string | undefined; - search: ISearchGeneric; -}) => { - return { - queryKey: [(esqlQuery ?? '').trim()], - queryFn: async () => { - if (!esqlQuery) { - return null; - } - try { - const res = await getESQLQueryColumns({ - esqlQuery, - search, - }); - return res; - } catch (e) { - return { error: e }; - } - }, - staleTime: 60 * 1000, - }; -}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/helpers.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/helpers.tsx index 57292d91953d..476302ab06f5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/helpers.tsx @@ -27,7 +27,6 @@ import { FilterBadgeGroup } from '@kbn/unified-search-plugin/public'; import { IntervalAbbrScreenReader } from '../../../../common/components/accessibility'; import type { RequiredFieldArray, - Threshold, AlertSuppressionMissingFieldsStrategy, } from '../../../../../common/api/detection_engine/model/rule_schema'; import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../common/api/detection_engine/model/rule_schema'; @@ -50,6 +49,7 @@ import { defaultToEmptyTag } from '../../../../common/components/empty_value'; import { RequiredFieldIcon } from '../../../rule_management/components/rule_details/required_field_icon'; import { ThreatEuiFlexGroup } from './threat_description'; import { AlertSuppressionLabel } from './alert_suppression_label'; +import type { FieldValueThreshold } from '../threshold_input'; const NoteDescriptionContainer = styled(EuiFlexItem)` height: 105px; @@ -490,20 +490,29 @@ export const buildRuleTypeDescription = (label: string, ruleType: Type): ListIte } }; -export const buildThresholdDescription = (label: string, threshold: Threshold): ListItems[] => [ - { - title: label, - description: ( - <> - {isEmpty(threshold.field[0]) - ? `${i18n.THRESHOLD_RESULTS_ALL} >= ${threshold.value}` - : `${i18n.THRESHOLD_RESULTS_AGGREGATED_BY} ${ - Array.isArray(threshold.field) ? threshold.field.join(',') : threshold.field - } >= ${threshold.value}`} - </> - ), - }, -]; +export const buildThresholdDescription = ( + label: string, + threshold: FieldValueThreshold +): ListItems[] => { + let thresholdDescription = isEmpty(threshold.field[0]) + ? `${i18n.THRESHOLD_RESULTS_ALL} >= ${threshold.value}` + : `${i18n.THRESHOLD_RESULTS_AGGREGATED_BY} ${threshold.field.join(',')} >= ${threshold.value}`; + + if (threshold.cardinality?.value && threshold.cardinality?.field.length > 0) { + thresholdDescription = i18n.THRESHOLD_CARDINALITY( + thresholdDescription, + threshold.cardinality.field[0], + threshold.cardinality.value + ); + } + + return [ + { + title: label, + description: <>{thresholdDescription}</>, + }, + ]; +}; export const buildThreatMappingDescription = ( title: string, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.test.tsx index de46d09065f4..b45f1a50414a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.test.tsx @@ -451,10 +451,62 @@ describe('description_step', () => { expect(result[0].title).toEqual('Threshold label'); expect(React.isValidElement(result[0].description)).toBeTruthy(); - expect(mount(result[0].description as React.ReactElement).html()).toContain( + expect(mount(result[0].description as React.ReactElement).html()).toEqual( + 'Results aggregated by user.name >= 100' + ); + }); + + test('returns threshold description when threshold exist, field is set, and cardinality is not set', () => { + const mockThreshold = { + threshold: { + field: ['user.name'], + value: 100, + cardinality: { + field: [], + value: 0, + }, + }, + }; + const result: ListItems[] = getDescriptionItem( + 'threshold', + 'Threshold label', + mockThreshold, + mockFilterManager, + mockLicenseService + ); + + expect(result[0].title).toEqual('Threshold label'); + expect(React.isValidElement(result[0].description)).toBeTruthy(); + expect(mount(result[0].description as React.ReactElement).html()).toEqual( 'Results aggregated by user.name >= 100' ); }); + + test('returns threshold description when threshold exist, field is set and cardinality is set', () => { + const mockThreshold = { + threshold: { + field: ['user.name'], + value: 100, + cardinality: { + field: ['host.test_value'], + value: 10, + }, + }, + }; + const result: ListItems[] = getDescriptionItem( + 'threshold', + 'Threshold label', + mockThreshold, + mockFilterManager, + mockLicenseService + ); + + expect(result[0].title).toEqual('Threshold label'); + expect(React.isValidElement(result[0].description)).toBeTruthy(); + expect(mount(result[0].description as React.ReactElement).html()).toContain( + 'Results aggregated by user.name >= 100 when unique values count of host.test_value >= 10' + ); + }); }); describe('references', () => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx index 24ad5f4135a1..26c81f325ea1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/index.tsx @@ -72,6 +72,7 @@ import { ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME, } from '../../../rule_creation/components/alert_suppression_edit'; import { THRESHOLD_ALERT_SUPPRESSION_ENABLED } from '../../../rule_creation/components/threshold_alert_suppression_edit'; +import type { FieldValueQueryBar } from '../query_bar_field'; const DescriptionListContainer = styled(EuiDescriptionList)` max-width: 600px; @@ -206,11 +207,12 @@ export const getDescriptionItem = ( indexPatterns?: DataViewBase ): ListItems[] => { if (field === 'queryBar') { - const filters = addFilterStateIfNotThere(get('queryBar.filters', data) ?? []); - const query = get('queryBar.query.query', data); - const savedId = get('queryBar.saved_id', data); - const savedQueryName = get('queryBar.title', data); - const ruleType: Type = get('ruleType', data); + const queryBar = get('queryBar', data) as FieldValueQueryBar; + const filters = addFilterStateIfNotThere(queryBar.filters ?? []); + const query = queryBar.query.query as string; + const savedId = queryBar.saved_id ?? ''; + const savedQueryName = queryBar.title; + const ruleType: Type = get('ruleType', data) as Type; const queryLabel = getQueryLabel(ruleType); return buildQueryBarDescription({ field, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/translations.ts index 5c43b9181adc..74a9faa4efd4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/description_step/translations.ts @@ -126,6 +126,24 @@ export const THRESHOLD_RESULTS_AGGREGATED_BY = i18n.translate( } ); +export const THRESHOLD_CARDINALITY = ( + thresholdFieldsGroupedBy: string, + cardinalityField: string, + cardinalityValue: string | number +) => + i18n.translate( + 'xpack.securitySolution.detectionEngine.ruleDescription.thresholdResultsCardinalityDescription', + { + defaultMessage: + '{thresholdFieldsGroupedBy} when unique values count of {cardinalityField} >= {cardinalityValue}', + values: { + thresholdFieldsGroupedBy, + cardinalityField, + cardinalityValue, + }, + } + ); + export const EQL_EVENT_CATEGORY_FIELD_LABEL = i18n.translate( 'xpack.securitySolution.detectionEngine.ruleDescription.eqlEventCategoryFieldLabel', { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts index e6a6b3d4a3d7..fa00914bced1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.test.ts @@ -8,15 +8,6 @@ import { esqlToOptions } from './use_esql_fields_options'; describe('esqlToOptions', () => { - it('should return empty array if data is undefined', () => { - expect(esqlToOptions(undefined)).toEqual([]); - }); - it('should return empty array if data is null', () => { - expect(esqlToOptions(null)).toEqual([]); - }); - it('should return empty array if data has error', () => { - expect(esqlToOptions({ error: Error })).toEqual([]); - }); it('should transform all columns if fieldTYpe is not passed', () => { expect( esqlToOptions([ diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts index b29d44c0b855..f3a3128c8842 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/esql_autocomplete/use_esql_fields_options.ts @@ -7,24 +7,12 @@ import { useMemo } from 'react'; import type { EuiComboBoxOptionOption } from '@elastic/eui'; import type { DatatableColumn } from '@kbn/expressions-plugin/public'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import { useEsqlQueryColumns } from '../../../rule_creation/logic/esql_query_columns'; -import { useQuery } from '@tanstack/react-query'; +type FieldType = 'string'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; - -import { getEsqlQueryConfig } from '../../../rule_creation/logic/get_esql_query_config'; -import type { FieldType } from '../../../rule_creation/logic/esql_validator'; - -export const esqlToOptions = ( - columns: { error: unknown } | DatatableColumn[] | undefined | null, - fieldType?: FieldType -) => { - if (columns && 'error' in columns) { - return []; - } - - const options = (columns ?? []).reduce<Array<{ label: string }>>((acc, { id, meta }) => { +export const esqlToOptions = (columns: DatatableColumn[], fieldType?: FieldType) => { + const options = columns.reduce<Array<{ label: string }>>((acc, { id, meta }) => { // if fieldType absent, we do not filter columns by type if (!fieldType || fieldType === meta.type) { acc.push({ label: id }); @@ -47,16 +35,11 @@ type UseEsqlFieldOptions = ( * fetches ES|QL fields and convert them to Combobox options */ export const useEsqlFieldOptions: UseEsqlFieldOptions = (esqlQuery, fieldType) => { - const kibana = useKibana<{ data: DataPublicPluginStart }>(); - - const { data: dataService } = kibana.services; - - const queryConfig = getEsqlQueryConfig({ esqlQuery, search: dataService.search.search }); - const { data, isLoading } = useQuery(queryConfig); + const { columns, isLoading } = useEsqlQueryColumns(esqlQuery ?? ''); const options = useMemo(() => { - return esqlToOptions(data, fieldType); - }, [data, fieldType]); + return esqlToOptions(columns, fieldType); + }, [columns, fieldType]); return { options, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/multi_select_fields/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/multi_select_fields/index.tsx index 8a27d2f66809..4b5a764d1e60 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/multi_select_fields/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/multi_select_fields/index.tsx @@ -5,8 +5,9 @@ * 2.0. */ -import React, { useMemo } from 'react'; +import React, { useEffect, useMemo, useRef } from 'react'; import type { DataViewFieldBase } from '@kbn/es-query'; +import type { EuiComboBox } from '@elastic/eui'; import { ComboBoxField } from '@kbn/es-ui-shared-plugin/static/forms/components'; import type { FieldHook } from '../../../../shared_imports'; import { FIELD_PLACEHOLDER } from './translations'; @@ -30,6 +31,7 @@ export const MultiSelectAutocompleteComponent: React.FC<MultiSelectAutocompleteP fullWidth = false, dataTestSubj, }: MultiSelectAutocompleteProps) => { + const comboBoxRef = useRef<EuiComboBox<unknown>>(); const fieldEuiFieldProps = useMemo( () => ({ fullWidth: true, @@ -39,10 +41,24 @@ export const MultiSelectAutocompleteComponent: React.FC<MultiSelectAutocompleteP onCreateOption: undefined, ...(fullWidth ? {} : { style: { width: `${FIELD_COMBO_BOX_WIDTH}px` } }), isDisabled, + ref: comboBoxRef, }), - [browserFields, isDisabled, fullWidth] + [browserFields, isDisabled, fullWidth, comboBoxRef] ); + /** + * ComboBox's options list might stay open after disabling the control. + * + * It happens for example when disabled state condition depends on the number of selected items. + * When removing the last item the control switches to disabled state but doesn't close the + * options lits. + */ + useEffect(() => { + if (isDisabled) { + comboBoxRef.current?.closeList(); + } + }, [isDisabled]); + return ( <ComboBoxField field={field} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/default_queries.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/default_queries.ts new file mode 100644 index 000000000000..c1f3150a3aa7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/default_queries.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FieldValueQueryBar } from './types'; + +export const DEFAULT_KQL_QUERY_FIELD_VALUE: Readonly<FieldValueQueryBar> = { + query: { query: '', language: 'kuery' }, + filters: [], + saved_id: null, +}; + +export const DEFAULT_THREAT_MATCH_KQL_QUERY_FIELD_VALUE: Readonly<FieldValueQueryBar> = { + query: { query: '*:*', language: 'kuery' }, + filters: [], + saved_id: null, +}; + +export const DEFAULT_EQL_QUERY_FIELD_VALUE: Readonly<FieldValueQueryBar> = { + query: { query: '', language: 'eql' }, + filters: [], + saved_id: null, +}; + +export const DEFAULT_ESQL_QUERY_FIELD_VALUE: Readonly<FieldValueQueryBar> = { + query: { query: '', language: 'esql' }, + filters: [], + saved_id: null, +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/index.ts new file mode 100644 index 000000000000..07f6e408c557 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './types'; +export * from './default_queries'; +export * from './query_field'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.test.tsx similarity index 97% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.test.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.test.tsx index 7b757f8fc621..190d10fe0a3b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; -import { QueryBarDefineRule } from '.'; +import { QueryBarField } from '.'; import { TestProviders, useFormFieldMock, @@ -74,7 +74,7 @@ describe('QueryBarDefineRule', () => { const { getByTestId } = render( <TestProviders> <Router history={mockHistory}> - <QueryBarDefineRule + <QueryBarField isLoading={false} indexPattern={{ fields: [], title: 'title' }} onCloseTimelineSearch={jest.fn()} @@ -96,7 +96,7 @@ describe('QueryBarDefineRule', () => { const { queryByTestId } = render( <TestProviders> <Router history={mockHistory}> - <QueryBarDefineRule + <QueryBarField isLoading={false} indexPattern={{ fields: [], title: 'title' }} onCloseTimelineSearch={jest.fn()} @@ -121,7 +121,7 @@ describe('QueryBarDefineRule', () => { const { getByTestId } = render( <TestProviders> <Router history={mockHistory}> - <QueryBarDefineRule + <QueryBarField isLoading={false} indexPattern={{ fields: [], title: 'title' }} onCloseTimelineSearch={jest.fn()} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.tsx similarity index 96% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.tsx index 43330bdd858e..44dad72b09c4 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/query_field.tsx @@ -9,7 +9,7 @@ import { EuiFormRow, EuiMutationObserver } from '@elastic/eui'; import React, { useCallback, useEffect, useState } from 'react'; import { Subscription } from 'rxjs'; import deepEqual from 'fast-deep-equal'; -import type { DataViewBase, Filter, Query } from '@kbn/es-query'; +import type { DataViewBase, Query } from '@kbn/es-query'; import type { SavedQuery } from '@kbn/data-plugin/public'; import { FilterManager } from '@kbn/data-plugin/public'; @@ -21,15 +21,10 @@ import type { TimelineModel } from '../../../../timelines/store/model'; import { useSavedQueryServices } from '../../../../common/utils/saved_query_services'; import type { FieldHook } from '../../../../shared_imports'; import { getFieldValidityAndErrorMessage } from '../../../../shared_imports'; +import type { FieldValueQueryBar } from './types'; import * as i18n from './translations'; -export interface FieldValueQueryBar { - filters: Filter[]; - query: Query; - saved_id: string | null; - title?: string; -} -export interface QueryBarDefineRuleProps { +export interface QueryBarFieldProps { dataTestSubj: string; field: FieldHook; idAria: string; @@ -70,7 +65,7 @@ const savedQueryToFieldValue = (savedQuery: SavedQuery): FieldValueQueryBar => ( title: savedQuery.attributes.title, }); -export const QueryBarDefineRule = ({ +export const QueryBarField = ({ defaultSavedQuery, dataTestSubj, field, @@ -85,7 +80,7 @@ export const QueryBarDefineRule = ({ resetToSavedQuery, onOpenTimeline, onSavedQueryError, -}: QueryBarDefineRuleProps) => { +}: QueryBarFieldProps) => { const { value: fieldValue, setValue: setFieldValue } = field as FieldHook<FieldValueQueryBar>; const [originalHeight, setOriginalHeight] = useState(-1); const [loadingTimeline, setLoadingTimeline] = useState(false); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/translations.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar/translations.tsx rename to x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/translations.tsx diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/types.ts new file mode 100644 index 000000000000..9807be907209 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/query_bar_field/types.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Filter, Query } from '@kbn/es-query'; + +export interface FieldValueQueryBar { + filters: Filter[]; + query: Query; + saved_id: string | null; + title?: string; +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts index e6f994573744..045e957c4e12 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/rule_preview/helpers.ts @@ -10,7 +10,7 @@ import type { EuiSelectOption } from '@elastic/eui'; import type { Type, ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import * as i18n from './translations'; -import type { FieldValueQueryBar } from '../query_bar'; +import type { FieldValueQueryBar } from '../query_bar_field'; import type { TimeframePreviewOptions } from '../../../../detections/pages/detection_engine/rules/types'; import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; import { MAX_NUMBER_OF_NEW_TERMS_FIELDS } from '../../../../../common/constants'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx index 364f1b770573..83aa6a114362 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.test.tsx @@ -6,6 +6,7 @@ */ import React, { useEffect } from 'react'; +import type { ChangeEvent } from 'react'; import { screen, fireEvent, render, within, act, waitFor } from '@testing-library/react'; import type { Type as RuleType } from '@kbn/securitysolution-io-ts-alerting-types'; import type { DataViewBase } from '@kbn/es-query'; @@ -42,13 +43,42 @@ import { addRelatedIntegrationRow, setVersion, } from '../../../rule_creation/components/related_integrations/test_helpers'; +import { useEsqlAvailability } from '../../../../common/hooks/esql/use_esql_availability'; +import { useMLRuleConfig } from '../../../../common/components/ml/hooks/use_ml_rule_config'; + +// Set the extended default timeout for all define rule step form test +jest.setTimeout(10 * 1000); // Mocks integrations jest.mock('../../../fleet_integrations/api'); + +const MOCKED_QUERY_BAR_TEST_ID = 'mockedQueryBar'; +const MOCKED_LANGUAGE_INPUT_TEST_ID = 'languageInput'; + +// Mocking QueryBar to avoid pulling and mocking a ton of dependencies jest.mock('../../../../common/components/query_bar', () => { return { - QueryBar: jest.fn(({ filterQuery }) => { - return <div data-test-subj="query-bar">{`${filterQuery.query} ${filterQuery.language}`}</div>; + QueryBar: jest.fn().mockImplementation(({ filterQuery, onSubmitQuery }) => { + const handleQueryChange = (event: ChangeEvent<HTMLTextAreaElement>) => { + onSubmitQuery({ query: event.target.value, language: filterQuery.language }); + }; + + const handleLanguageChange = (event: ChangeEvent<HTMLInputElement>) => { + onSubmitQuery({ query: filterQuery.query, language: event.target.value }); + }; + + return ( + <div data-test-subj={MOCKED_QUERY_BAR_TEST_ID}> + <textarea value={filterQuery.query} onChange={handleQueryChange} /> + <input + role="listbox" + type="text" + value={filterQuery.language} + onChange={handleLanguageChange} + data-test-subj={MOCKED_LANGUAGE_INPUT_TEST_ID} + /> + </div> + ); }), }; }); @@ -77,6 +107,7 @@ const mockRedirectLegacyUrl = jest.fn(); const mockGetLegacyUrlConflict = jest.fn(); jest.mock('../../../../common/lib/kibana', () => { const originalModule = jest.requireActual('../../../../common/lib/kibana'); + return { ...originalModule, useToasts: jest.fn().mockReturnValue({ @@ -85,41 +116,43 @@ jest.mock('../../../../common/lib/kibana', () => { addWarning: jest.fn(), remove: jest.fn(), }), - useKibana: () => ({ - services: { - ...originalModule.useKibana().services, - storage: { - get: jest.fn().mockReturnValue(true), - }, - application: { - getUrlForApp: (appId: string, options?: { path?: string }) => - `/app/${appId}${options?.path}`, - navigateToApp: jest.fn(), - capabilities: { - actions: { - delete: true, - save: true, - show: true, + useKibana: () => { + return { + services: { + ...originalModule.useKibana().services, + storage: { + get: jest.fn().mockReturnValue(true), + }, + application: { + getUrlForApp: (appId: string, options?: { path?: string }) => + `/app/${appId}${options?.path}`, + navigateToApp: jest.fn(), + capabilities: { + actions: { + delete: true, + save: true, + show: true, + }, }, }, - }, - data: { - search: { - search: () => ({ - subscribe: () => ({ - unsubscribe: jest.fn(), + data: { + search: { + search: () => ({ + subscribe: () => ({ + unsubscribe: jest.fn(), + }), }), - }), + }, }, - }, - spaces: { - ui: { - components: { getLegacyUrlConflict: mockGetLegacyUrlConflict }, - redirectLegacyUrl: mockRedirectLegacyUrl, + spaces: { + ui: { + components: { getLegacyUrlConflict: mockGetLegacyUrlConflict }, + redirectLegacyUrl: mockRedirectLegacyUrl, + }, }, }, - }, - }), + }; + }, }; }); jest.mock('../../../../common/hooks/use_selector', () => { @@ -172,18 +205,27 @@ jest.mock('react-redux', () => { jest.mock('../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'); +jest.mock('../../../../common/hooks/esql/use_esql_availability'); +jest.mock('../../../../common/components/ml/hooks/use_ml_rule_config'); + const mockUseRuleFromTimeline = useRuleFromTimeline as jest.Mock; const onOpenTimeline = jest.fn(); const COMBO_BOX_TOGGLE_BUTTON_TEST_ID = 'comboBoxToggleListButton'; const VERSION_INPUT_TEST_ID = 'relatedIntegrationVersionDependency'; +const DEFINE_RULE_FORM_STEP = 'defineRuleFormStepQueryEditor'; -// Failing: See https://github.com/elastic/kibana/issues/199648 -// Failing: See https://github.com/elastic/kibana/issues/199700 -describe.skip('StepDefineRule', () => { +describe('StepDefineRule', () => { beforeEach(() => { - jest.clearAllMocks(); mockUseRuleFromTimeline.mockReturnValue({ onOpenTimeline, loading: false }); + (useEsqlAvailability as jest.Mock).mockReturnValue({ isEsqlRuleTypeEnabled: true }); + (useMLRuleConfig as jest.Mock).mockReturnValue({ + allJobsStarted: true, + hasMlAdminPermissions: true, + hasMlLicense: true, + loading: false, + mlSuppressionFields: [], + }); }); it('renders correctly', () => { @@ -194,6 +236,151 @@ describe.skip('StepDefineRule', () => { expect(screen.getByTestId('stepDefineRule')).toBeDefined(); }); + describe('query', () => { + it.each([ + ['query', 'eql'], + ['query', 'esql'], + ] as RuleType[][])( + 'persists kuery when switching between "%s" and "%s" rule types', + async (ruleTypeA, ruleTypeB) => { + render(<TestForm />, { + wrapper: TestProviders, + }); + + typeQuery('someField : *'); + selectQueryLanguage('kuery'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + + await selectRuleType(ruleTypeB); + + expectQuery(DEFINE_RULE_FORM_STEP, ''); + + await selectRuleType(ruleTypeA); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + } + ); + + it.each([ + ['query', 'threshold'], + ['query', 'new_terms'], + ] as RuleType[][])( + 'persists kuery when switching between "%s" and "%s" rule types', + async (ruleTypeA, ruleTypeB) => { + render(<TestForm />, { + wrapper: TestProviders, + }); + + typeQuery('someField : *'); + selectQueryLanguage('kuery'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + + await selectRuleType(ruleTypeB); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + + await selectRuleType(ruleTypeA); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + } + ); + + it.each([['query'], ['threshold'], ['threat_match'], ['new_terms']] as RuleType[][])( + 'persists kuery when switching between "%s" and "threat_match" rule types', + async (ruleType) => { + render(<TestForm />, { + wrapper: TestProviders, + }); + await selectRuleType(ruleType); + typeQuery('someField : *'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + + await selectRuleType('threat_match'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + + await selectRuleType(ruleType); + + expectQuery(DEFINE_RULE_FORM_STEP, 'someField : *'); + } + ); + + it.each([['query'], ['esql'], ['threshold'], ['new_terms']] as RuleType[][])( + 'persists EQL query when switching between "eql" and "%s" rule types', + async (switchRuleType) => { + render(<TestForm />, { + wrapper: TestProviders, + }); + + await selectRuleType('eql'); + typeQuery('process where process.name == "regsvr32.exe"'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'process where process.name == "regsvr32.exe"'); + + await selectRuleType(switchRuleType); + + expectQuery(DEFINE_RULE_FORM_STEP, ''); + + await selectRuleType('eql'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'process where process.name == "regsvr32.exe"'); + } + ); + + it.each([['query'], ['eql'], ['threshold'], ['new_terms']] as RuleType[][])( + 'persists ES|QL query when switching between "esql" and "%s" rule types', + async (switchRuleType) => { + render(<TestForm />, { + wrapper: TestProviders, + }); + await selectRuleType('esql'); + typeQuery('from test*'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'from test*'); + + await selectRuleType(switchRuleType); + + expectQuery(DEFINE_RULE_FORM_STEP, ''); + + await selectRuleType('esql'); + + expectQuery(DEFINE_RULE_FORM_STEP, 'from test*'); + } + ); + + it('makes sure "threat_match" rule has "*:*" kuery by default', async () => { + render(<TestForm />, { + wrapper: TestProviders, + }); + await selectRuleType('threat_match'); + + expectQuery(DEFINE_RULE_FORM_STEP, '*:*'); + }); + + it.each([['query'], ['eql'], ['esql'], ['threshold'], ['new_terms']] as RuleType[][])( + 'makes sure "threat_match" rule has "*:*" kuery when switched from "%s" rule type without user input', + async (ruleType) => { + render(<TestForm />, { + wrapper: TestProviders, + }); + await selectRuleType(ruleType); + + expectQuery(DEFINE_RULE_FORM_STEP, ''); + + await selectRuleType('threat_match'); + + expectQuery(DEFINE_RULE_FORM_STEP, '*:*'); + + await selectRuleType(ruleType); + + expectQuery(DEFINE_RULE_FORM_STEP, ''); + } + ); + }); + describe('alert suppression', () => { it('persists state when switching between custom query and threshold rule types', async () => { const mockFields: FieldSpec[] = [ @@ -205,7 +392,7 @@ describe.skip('StepDefineRule', () => { }, ]; - const { rerender } = render( + render( <TestForm indexPattern={{ title: '', @@ -221,29 +408,11 @@ describe.skip('StepDefineRule', () => { setDurationType('Per time period'); setDuration(10, 'h'); - // switch to threshold rule type - rerender( - <TestForm - ruleType="threshold" - indexPattern={{ - title: '', - fields: mockFields, - }} - /> - ); + await selectRuleType('threshold'); expectDuration(10, 'h'); - // switch back to custom query rule type - rerender( - <TestForm - ruleType="query" - indexPattern={{ - title: '', - fields: mockFields, - }} - /> - ); + await selectRuleType('query'); expectSuppressionFields(['test-field']); expectDuration(10, 'h'); @@ -479,7 +648,7 @@ describe.skip('StepDefineRule', () => { describe('handleSetRuleFromTimeline', () => { it('updates KQL query correctly', () => { - const kqlQuery = { + const timelineKqlQuery = { index: ['.alerts-security.alerts-default', 'logs-*', 'packetbeat-*'], queryBar: { filters: [], @@ -493,7 +662,7 @@ describe.skip('StepDefineRule', () => { mockUseRuleFromTimeline.mockImplementation((handleSetRuleFromTimeline) => { useEffect(() => { - handleSetRuleFromTimeline(kqlQuery); + handleSetRuleFromTimeline(timelineKqlQuery); }, [handleSetRuleFromTimeline]); return { onOpenTimeline, loading: false }; @@ -503,13 +672,14 @@ describe.skip('StepDefineRule', () => { wrapper: TestProviders, }); - expect(screen.getAllByTestId('query-bar')[0].textContent).toBe( - `${kqlQuery.queryBar.query.query} ${kqlQuery.queryBar.query.language}` - ); + expectQuery(DEFINE_RULE_FORM_STEP, timelineKqlQuery.queryBar.query.query); + expectQueryLanguage(DEFINE_RULE_FORM_STEP, timelineKqlQuery.queryBar.query.language); }); it('updates EQL query correctly', async () => { - const eqlQuery = { + jest.useFakeTimers(); + + const timelineEqlQuery = { index: ['.alerts-security.alerts-default', 'logs-*', 'packetbeat-*'], queryBar: { filters: [], @@ -528,20 +698,28 @@ describe.skip('StepDefineRule', () => { }, }; + const setRuleFromTimelineFactory = + (handleSetRuleFromTimeline: (value: unknown) => void) => async () => + act(async () => handleSetRuleFromTimeline(timelineEqlQuery)); + + let setRuleFromTimeline!: () => void; + mockUseRuleFromTimeline.mockImplementation((handleSetRuleFromTimeline) => { - useEffect(() => { - handleSetRuleFromTimeline(eqlQuery); - }, [handleSetRuleFromTimeline]); + setRuleFromTimeline = setRuleFromTimelineFactory(handleSetRuleFromTimeline); return { onOpenTimeline, loading: false }; }); - render(<TestForm ruleType="eql" />, { + render(<TestForm />, { wrapper: TestProviders, }); - expect(screen.getByTestId(`eqlQueryBarTextInput`).textContent).toEqual( - eqlQuery.queryBar.query.query + await setRuleFromTimeline(); + + jest.runAllTimers(); + + expect(screen.getByTestId('eqlQueryBarTextInput')).toHaveValue( + timelineEqlQuery.queryBar.query.query ); await act(async () => { @@ -550,14 +728,14 @@ describe.skip('StepDefineRule', () => { expect( within(screen.getByTestId('eql-event-category-field')).queryByRole('combobox') - ).toHaveValue(eqlQuery.eqlOptions.eventCategoryField); + ).toHaveValue(timelineEqlQuery.eqlOptions.eventCategoryField); expect( within(screen.getByTestId('eql-tiebreaker-field')).queryByRole('combobox') - ).toHaveValue(eqlQuery.eqlOptions.tiebreakerField); + ).toHaveValue(timelineEqlQuery.eqlOptions.tiebreakerField); expect(within(screen.getByTestId('eql-timestamp-field')).queryByRole('combobox')).toHaveValue( - eqlQuery.eqlOptions.timestampField + timelineEqlQuery.eqlOptions.timestampField ); }); }); @@ -571,15 +749,9 @@ describe.skip('StepDefineRule', () => { saved_id: null, }, }; - render( - <TestForm - formProps={{ isQueryBarValid: false, ruleType: 'query' }} - initialState={initialState} - />, - { - wrapper: TestProviders, - } - ); + render(<TestForm formProps={{ isQueryBarValid: false }} initialState={initialState} />, { + wrapper: TestProviders, + }); expect(screen.getByTestId('ai-assistant')).toBeInTheDocument(); }); @@ -592,31 +764,26 @@ describe.skip('StepDefineRule', () => { saved_id: null, }, }; - render( - <TestForm - formProps={{ isQueryBarValid: false, ruleType: 'query' }} - initialState={initialState} - />, - { - wrapper: TestProviders, - } - ); + render(<TestForm formProps={{ isQueryBarValid: false }} initialState={initialState} />, { + wrapper: TestProviders, + }); expect(screen.queryByTestId('ai-assistant')).toBe(null); }); it('does not render assistant when query is valid', () => { - render(<TestForm formProps={{ isQueryBarValid: true, ruleType: 'query' }} />, { + render(<TestForm formProps={{ isQueryBarValid: true }} />, { wrapper: TestProviders, }); expect(screen.queryByTestId('ai-assistant')).toBe(null); }); - it('does not render assistant for ML rule type', () => { - render(<TestForm formProps={{ isQueryBarValid: false, ruleType: 'machine_learning' }} />, { + it('does not render assistant for ML rule type', async () => { + render(<TestForm formProps={{ isQueryBarValid: false }} />, { wrapper: TestProviders, }); + await selectRuleType('machine_learning'); expect(screen.queryByTestId('ai-assistant')).toBe(null); }); @@ -625,7 +792,6 @@ describe.skip('StepDefineRule', () => { interface TestFormProps { initialState?: Partial<DefineStepRule>; - ruleType?: RuleType; indexPattern?: DataViewBase; onSubmit?: FormSubmitHandler<DefineStepRule>; formProps?: Partial<StepDefineRuleProps>; @@ -633,7 +799,6 @@ interface TestFormProps { function TestForm({ initialState, - ruleType = stepDefineDefaultValue.ruleType, indexPattern = { fields: [], title: '' }, onSubmit, formProps, @@ -657,7 +822,6 @@ function TestForm({ isQueryBarValid={true} setIsQueryBarValid={jest.fn()} setIsThreatQueryBarValid={jest.fn()} - ruleType={ruleType} index={stepDefineDefaultValue.index} threatIndex={stepDefineDefaultValue.threatIndex} alertSuppressionFields={stepDefineDefaultValue[ALERT_SUPPRESSION_FIELDS_FIELD_NAME]} @@ -680,3 +844,53 @@ function submitForm(): Promise<void> { fireEvent.click(screen.getByText('Submit')); }); } + +function typeQuery(query: string): void { + act(() => { + fireEvent.input(within(screen.getByTestId(DEFINE_RULE_FORM_STEP)).getByRole('textbox'), { + target: { value: query }, + }); + }); +} + +function expectQuery(containerTestId: string, expectedQuery: string): void { + expect(within(screen.getByTestId(containerTestId)).getByRole('textbox')).toHaveValue( + expectedQuery + ); +} + +function selectQueryLanguage(language: 'kuery' | 'eql' | 'esql'): void { + act(() => { + fireEvent.input( + within(screen.getByTestId(DEFINE_RULE_FORM_STEP)).getByTestId(MOCKED_LANGUAGE_INPUT_TEST_ID), + { + target: { value: language }, + } + ); + }); +} + +function expectQueryLanguage(containerTestId: string, expectedLanguage: string): void { + expect( + within(screen.getByTestId(containerTestId)).getByTestId(MOCKED_LANGUAGE_INPUT_TEST_ID) + ).toHaveValue(expectedLanguage); +} + +async function selectRuleType(ruleType: RuleType): Promise<void> { + const testId = RULE_TYPE_TEST_ID_MAP[ruleType]; + + await act(async () => fireEvent.click(screen.getByTestId(testId))); + + expect(within(screen.getByTestId(testId)).getByRole('switch')).toBeChecked(); +} + +const RULE_TYPE_TEST_ID_MAP = { + query: 'customRuleType', + saved_query: 'customRuleType', + eql: 'eqlRuleType', + machine_learning: 'machineLearningRuleType', + threshold: 'thresholdRuleType', + threat_match: 'threatMatchRuleType', + new_terms: 'newTermsRuleType', + esql: 'esqlRuleType', +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx index 053544e6fdbb..dd50d83ce7f0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/index.tsx @@ -16,20 +16,16 @@ import { EuiText, } from '@elastic/eui'; import type { FC } from 'react'; -import React, { memo, useCallback, useState, useEffect, useMemo, useRef } from 'react'; +import React, { memo, useCallback, useState, useEffect, useMemo } from 'react'; import styled from 'styled-components'; import { i18n as i18nCore } from '@kbn/i18n'; import { isEqual } from 'lodash'; import type { FieldSpec } from '@kbn/data-plugin/common'; -import usePrevious from 'react-use/lib/usePrevious'; -import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; -import { useQueryClient } from '@tanstack/react-query'; import type { SavedQuery } from '@kbn/data-plugin/public'; import type { DataViewBase } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useSetFieldValueWithCallback } from '../../../../common/utils/use_set_field_value_cb'; import type { SetRuleQuery } from '../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; import { useRuleFromTimeline } from '../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; import { isMlRule } from '../../../../../common/machine_learning/helpers'; @@ -40,15 +36,14 @@ import type { } from '../../../../detections/pages/detection_engine/rules/types'; import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; import { StepRuleDescription } from '../description_step'; -import type { QueryBarDefineRuleProps } from '../query_bar'; -import { QueryBarDefineRule } from '../query_bar'; +import type { QueryBarFieldProps } from '../query_bar_field'; +import { QueryBarField } from '../query_bar_field'; import { SelectRuleType } from '../select_rule_type'; import { AnomalyThresholdSlider } from '../anomaly_threshold_slider'; import { MlJobSelect } from '../../../rule_creation/components/ml_job_select'; import { PickTimeline } from '../../../rule_creation/components/pick_timeline'; import { StepContentWrapper } from '../../../rule_creation/components/step_content_wrapper'; import { ThresholdInput } from '../threshold_input'; -import { EsqlInfoIcon } from '../../../rule_creation/components/esql_info_icon'; import { Field, Form, @@ -81,7 +76,6 @@ import { NewTermsFields } from '../new_terms_fields'; import { ScheduleItem } from '../../../rule_creation/components/schedule_item_form'; import { RequiredFields } from '../../../rule_creation/components/required_fields'; import { DocLink } from '../../../../common/components/links_to_docs/doc_link'; -import { defaultCustomQuery } from '../../../../detections/pages/detection_engine/rules/utils'; import { useLicense } from '../../../../common/hooks/use_license'; import { MINIMUM_LICENSE_FOR_SUPPRESSION } from '../../../../../common/detection_engine/constants'; import { useUpsellingMessage } from '../../../../common/hooks/use_upselling'; @@ -96,6 +90,8 @@ import { } from '../../../rule_creation/components/alert_suppression_edit'; import { ThresholdAlertSuppressionEdit } from '../../../rule_creation/components/threshold_alert_suppression_edit'; import { usePersistentAlertSuppressionState } from './use_persistent_alert_suppression_state'; +import { EsqlQueryEdit } from '../../../rule_creation/components/esql_query_edit'; +import { usePersistentQuery } from './use_persistent_query'; const CommonUseField = getUseField({ component: Field }); @@ -112,7 +108,6 @@ export interface StepDefineRuleProps extends RuleStepProps { isQueryBarValid: boolean; setIsQueryBarValid: (valid: boolean) => void; setIsThreatQueryBarValid: (valid: boolean) => void; - ruleType: Type; index: string[]; threatIndex: string[]; alertSuppressionFields?: string[]; @@ -165,7 +160,6 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ isUpdateView = false, queryBarSavedId, queryBarTitle, - ruleType, setIsQueryBarValid, setIsThreatQueryBarValid, shouldLoadQueryDynamically, @@ -173,7 +167,10 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ threatIndicesConfig, thresholdFields, }) => { - const queryClient = useQueryClient(); + const [{ ruleType, queryBar, machineLearningJobId }] = useFormData<DefineStepRule>({ + form, + watch: ['ruleType', 'queryBar', 'machineLearningJobId'], + }); const { isSuppressionEnabled: isAlertSuppressionEnabled } = useAlertSuppression(ruleType); const [openTimelineSearch, setOpenTimelineSearch] = useState(false); @@ -181,10 +178,6 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ const [threatIndexModified, setThreatIndexModified] = useState(false); const license = useLicense(); - const [{ machineLearningJobId }] = useFormData<DefineStepRule>({ - form, - watch: ['machineLearningJobId'], - }); const { allJobsStarted, hasMlAdminPermissions, @@ -196,43 +189,12 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ const isMlSuppressionIncomplete = isMlRule(ruleType) && machineLearningJobId?.length > 0 && !allJobsStarted; - const esqlQueryRef = useRef<DefineStepRule['queryBar'] | undefined>(undefined); - const isAlertSuppressionLicenseValid = license.isAtLeast(MINIMUM_LICENSE_FOR_SUPPRESSION); const isThresholdRule = getIsThresholdRule(ruleType); const alertSuppressionUpsellingMessage = useUpsellingMessage('alert_suppression_rule_form'); const { getFields, reset, setFieldValue } = form; - const setRuleTypeCallback = useSetFieldValueWithCallback({ - field: 'ruleType', - value: ruleType, - setFieldValue, - }); - - const handleSetRuleFromTimeline = useCallback<SetRuleQuery>( - ({ index: timelineIndex, queryBar: timelineQueryBar, eqlOptions }) => { - const setQuery = () => { - setFieldValue('index', timelineIndex); - setFieldValue('queryBar', timelineQueryBar); - }; - if (timelineQueryBar.query.language === 'eql') { - setRuleTypeCallback('eql', setQuery); - setFieldValue('eqlOptions', eqlOptions ?? {}); - } else { - setQuery(); - } - }, - [setFieldValue, setRuleTypeCallback] - ); - - const { onOpenTimeline, loading: timelineQueryLoading } = - useRuleFromTimeline(handleSetRuleFromTimeline); - - // if 'index' is selected, use these browser fields - // otherwise use the dataview browserfields - const previousRuleType = usePrevious(ruleType); - // Callback for when user toggles between Data Views and Index Patterns const onChangeDataSource = useCallback( (optionId: string) => { @@ -281,95 +243,42 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ setThreatIndexModified(!isEqual(threatIndex, threatIndicesConfig)); }, [threatIndex, threatIndicesConfig]); - /** - * When the user changes rule type to or from "threat_match" this will modify the - * default "Custom query" string to either: - * * from '' to '*:*' if the type is switched to "threat_match" - * * from '*:*' back to '' if the type is switched back from "threat_match" to another one - */ - useEffect(() => { - const { queryBar: currentQuery } = getFields(); - if (currentQuery == null) { - return; - } - - // NOTE: Below this code does two things that are worth commenting. - - // 1. If the user enters some text in the "Custom query" form field, we want - // to keep it even if the user switched to another rule type. So we want to - // be able to figure out if the field has been modified. - // - The forms library provides properties (isPristine, isModified, isDirty) - // for that but they can't be used in our case: their values can be reset - // if you go to step 2 and then back to step 1 or the form is reset in another way. - // - That's why we compare the actual value of the field with default ones. - // NOTE: It's important to do a deep object comparison by value. - // Don't do it by reference because the forms lib can change it internally. - - // 2. We call currentQuery.reset() in both cases to not trigger validation errors - // as the user has not entered data into those areas yet. - - // If the user switched rule type to "threat_match" from any other one, - // but hasn't changed the custom query used for normal rules (''), - // we reset the custom query to the default used for "threat_match" rules ('*:*'). - if (isThreatMatchRule(ruleType) && !isThreatMatchRule(previousRuleType)) { - if (isEqual(currentQuery.value, defaultCustomQuery.forNormalRules)) { - currentQuery.reset({ - defaultValue: defaultCustomQuery.forThreatMatchRules, - }); - return; - } - } - - // If the user switched rule type from "threat_match" to any other one, - // but hasn't changed the custom query used for "threat_match" rules ('*:*'), - // we reset the custom query to another default value (''). - if (!isThreatMatchRule(ruleType) && isThreatMatchRule(previousRuleType)) { - if (isEqual(currentQuery.value, defaultCustomQuery.forThreatMatchRules)) { - currentQuery.reset({ - defaultValue: defaultCustomQuery.forNormalRules, - }); - } - } - }, [ruleType, previousRuleType, getFields]); - - /** - * ensures when user switches between rule types, written ES|QL query is not getting lost - * additional work is required in this code area, as currently switching to EQL will result in query lose - * https://github.com/elastic/kibana/issues/166933 - */ - useEffect(() => { - const { queryBar: currentQuery } = getFields(); - if (currentQuery == null) { - return; - } - - const currentQueryValue = currentQuery.value as DefineStepRule['queryBar']; + const { setPersistentEqlQuery, setPersistentEqlOptions } = usePersistentQuery({ + form, + }); + usePersistentAlertSuppressionState({ form }); - // sets ES|QL query to a default value or earlier added one, when switching to ES|QL rule type - if (isEsqlRule(ruleType)) { - if (previousRuleType && !isEsqlRule(previousRuleType)) { - currentQuery.reset({ - defaultValue: esqlQueryRef.current ?? defaultCustomQuery.forEsqlRules, + const handleSetRuleFromTimeline = useCallback<SetRuleQuery>( + ({ index: timelineIndex, queryBar: timelineQueryBar, eqlOptions }) => { + const setQuery = () => { + setFieldValue('index', timelineIndex); + setFieldValue('queryBar', timelineQueryBar); + }; + if (timelineQueryBar.query.language === 'eql') { + setFieldValue('ruleType', 'eql'); + + // Rule type change takes as minimum two re-renders. Since we render a specific + // query editor component depending on rule type we need to first render + // the rule type specific query editor component (using UseField under the hood) to + // be able to set query's field value. + // + // setTimeout provides a simple solution to wait until the rule type specific query + // editor component is rendered. + setTimeout(() => { + setPersistentEqlQuery(timelineQueryBar); + setPersistentEqlOptions(eqlOptions ?? {}); + setQuery(); + setFieldValue('eqlOptions', eqlOptions ?? {}); }); + } else { + setQuery(); } - // otherwise reset it to default values of other rule types - } else if (isEsqlRule(previousRuleType)) { - // sets ES|QL query value to reference, so it can be used when user switch back from one rule type to another - if (currentQueryValue?.query?.language === 'esql') { - esqlQueryRef.current = currentQueryValue; - } - - const defaultValue = isThreatMatchRule(ruleType) - ? defaultCustomQuery.forThreatMatchRules - : defaultCustomQuery.forNormalRules; - - currentQuery.reset({ - defaultValue, - }); - } - }, [ruleType, previousRuleType, getFields]); + }, + [setFieldValue, setPersistentEqlQuery, setPersistentEqlOptions] + ); - usePersistentAlertSuppressionState({ form }); + const { onOpenTimeline, loading: timelineQueryLoading } = + useRuleFromTimeline(handleSetRuleFromTimeline); // if saved query failed to load: // - reset shouldLoadFormDynamically to false, as non existent query cannot be used for loading and execution @@ -437,8 +346,6 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ ] ); - const [{ queryBar }] = useFormData<DefineStepRule>({ form, watch: ['queryBar'] }); - const { fields: esqlSuppressionFields, isLoading: isEsqlSuppressionLoading } = useAllEsqlRuleFields({ esqlQuery: isEsqlRule(ruleType) ? (queryBar?.query?.query as string) : undefined, @@ -621,46 +528,6 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ handleResetIndices, ]); - const queryBarProps = useMemo( - () => - ({ - idAria: 'detectionEngineStepDefineRuleQueryBar', - indexPattern, - isDisabled: isLoading, - isLoading, - dataTestSubj: 'detectionEngineStepDefineRuleQueryBar', - onValidityChange: setIsQueryBarValid, - } as QueryBarDefineRuleProps), - [indexPattern, isLoading, setIsQueryBarValid] - ); - - const esqlQueryBarConfig = useMemo( - () => ({ - ...schema.queryBar, - label: i18n.ESQL_QUERY, - labelAppend: <EsqlInfoIcon />, - }), - [] - ); - - const EsqlQueryBarMemo = useMemo( - () => ( - <UseField - key="QueryBarDefineRule" - path="queryBar" - config={esqlQueryBarConfig} - component={QueryBarDefineRule} - validationData={{ queryClient }} - componentProps={{ - ...queryBarProps, - dataTestSubj: 'detectionEngineStepDefineRuleEsqlQueryBar', - idAria: 'detectionEngineStepDefineRuleEsqlQueryBar', - }} - /> - ), - [queryBarProps, esqlQueryBarConfig, queryClient] - ); - const QueryBarMemo = useMemo( () => ( <UseField @@ -679,7 +546,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ </MyLabelButton> ), }} - component={QueryBarDefineRule} + component={QueryBarField} componentProps={ { idAria: 'detectionEngineStepDefineRuleQueryBar', @@ -694,7 +561,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ onSavedQueryError: handleSavedQueryError, defaultSavedQuery, onOpenTimeline, - } as QueryBarDefineRuleProps + } as QueryBarFieldProps } /> ), @@ -743,30 +610,41 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({ component={SelectRuleType} componentProps={selectRuleTypeProps} /> - <RuleTypeEuiFormRow $isVisible={!isMlRule(ruleType)} fullWidth> + <RuleTypeEuiFormRow $isVisible={!isMlRule(ruleType) && !isEsqlRule(ruleType)} fullWidth> + <> + <EuiSpacer size="s" /> + {DataSource} + </> + </RuleTypeEuiFormRow> + <RuleTypeEuiFormRow + $isVisible={!isMlRule(ruleType)} + fullWidth + data-test-subj="defineRuleFormStepQueryEditor" + > <> - <StyledVisibleContainer isVisible={!isEsqlRule(ruleType)}> - <EuiSpacer size="s" /> - {DataSource} - </StyledVisibleContainer> <EuiSpacer size="s" /> {isEqlRule(ruleType) ? ( - <> - <EqlQueryEdit - key="eqlQueryBar" - path="queryBar" - eqlOptionsPath="eqlOptions" - fieldsToValidateOnChange={ALERT_SUPPRESSION_FIELDS_FIELD_NAME} - required - showFilterBar - dataView={indexPattern} - loading={isIndexPatternLoading} - disabled={isLoading} - onValidityChange={setIsQueryBarValid} - /> - </> + <EqlQueryEdit + path="queryBar" + eqlOptionsPath="eqlOptions" + fieldsToValidateOnChange={ALERT_SUPPRESSION_FIELDS_FIELD_NAME} + required + showFilterBar + dataView={indexPattern} + loading={isIndexPatternLoading} + disabled={isLoading} + onValidityChange={setIsQueryBarValid} + /> ) : isEsqlRule(ruleType) ? ( - EsqlQueryBarMemo + <EsqlQueryEdit + path="queryBar" + fieldsToValidateOnChange={ALERT_SUPPRESSION_FIELDS_FIELD_NAME} + required + dataView={indexPattern} + disabled={isLoading} + loading={isLoading} + onValidityChange={setIsQueryBarValid} + /> ) : ( QueryBarMemo )} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx index 835cab7a4cfc..f0db9f034273 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/schema.tsx @@ -9,7 +9,7 @@ import { isEmpty } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiText } from '@elastic/eui'; import React from 'react'; -import { debounceAsync } from '@kbn/securitysolution-utils'; + import { singleEntryThreat, containsInvalidItems, @@ -30,10 +30,15 @@ import type { ERROR_CODE, FormSchema, ValidationFunc } from '../../../../shared_ import { FIELD_TYPES, fieldValidators } from '../../../../shared_imports'; import type { DefineStepRule } from '../../../../detections/pages/detection_engine/rules/types'; import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; -import { esqlValidator } from '../../../rule_creation/logic/esql_validator'; import { dataViewIdValidatorFactory } from '../../validators/data_view_id_validator_factory'; import { indexPatternValidatorFactory } from '../../validators/index_pattern_validator_factory'; import { alertSuppressionFieldsValidatorFactory } from '../../validators/alert_suppression_fields_validator_factory'; +import { + ALERT_SUPPRESSION_DURATION_FIELD_NAME, + ALERT_SUPPRESSION_FIELDS_FIELD_NAME, + ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME, +} from '../../../rule_creation/components/alert_suppression_edit'; +import * as alertSuppressionEditI81n from '../../../rule_creation/components/alert_suppression_edit/components/translations'; import { INDEX_HELPER_TEXT, THREAT_MATCH_INDEX_HELPER_TEXT, @@ -41,12 +46,6 @@ import { THREAT_MATCH_EMPTIES, EQL_SEQUENCE_SUPPRESSION_GROUPBY_VALIDATION_TEXT, } from './translations'; -import { - ALERT_SUPPRESSION_DURATION_FIELD_NAME, - ALERT_SUPPRESSION_FIELDS_FIELD_NAME, - ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME, -} from '../../../rule_creation/components/alert_suppression_edit'; -import * as alertSuppressionEditI81n from '../../../rule_creation/components/alert_suppression_edit/components/translations'; import { queryRequiredValidatorFactory } from '../../validators/query_required_validator_factory'; import { kueryValidatorFactory } from '../../validators/kuery_validator_factory'; @@ -134,9 +133,6 @@ export const schema: FormSchema<DefineStepRule> = { { validator: kueryValidatorFactory(), }, - { - validator: debounceAsync(esqlValidator, 300), - }, ], }, ruleType: { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx index 7b8063b23e30..897331d20da7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/translations.tsx @@ -139,13 +139,6 @@ export const ALERT_SUPPRESSION_MISSING_FIELDS_DO_NOT_SUPPRESS_OPTION = i18n.tran } ); -export const ESQL_QUERY = i18n.translate( - 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlQueryLabel', - { - defaultMessage: 'ES|QL query', - } -); - export const ALERT_SUPPRESSION_PER_RULE_EXECUTION = i18n.translate( 'xpack.securitySolution.detectionEngine.createRule.stepDefineRule.alertSuppressionOptions.perRuleExecutionLabel', { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_alert_suppression_state.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_alert_suppression_state.ts index d3c60df68492..91bd19819f2a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_alert_suppression_state.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_alert_suppression_state.ts @@ -6,6 +6,7 @@ */ import { useEffect } from 'react'; +import usePrevious from 'react-use/lib/usePrevious'; import { isThresholdRule } from '../../../../../common/detection_engine/utils'; import type { FormHook } from '../../../../shared_imports'; import { useFormData } from '../../../../shared_imports'; @@ -51,8 +52,13 @@ export function usePersistentAlertSuppressionState({ ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME, ], }); + const previousRuleType = usePrevious(ruleType); useEffect(() => { + if (!ruleType || ruleType === previousRuleType) { + return; + } + form.updateFieldValues({ [THRESHOLD_ALERT_SUPPRESSION_ENABLED]: thresholdAlertSuppressionEnabled, [ALERT_SUPPRESSION_FIELDS_FIELD_NAME]: suppressionFields, @@ -68,6 +74,7 @@ export function usePersistentAlertSuppressionState({ }, [ form, ruleType, + previousRuleType, thresholdAlertSuppressionEnabled, suppressionFields, suppressionDurationType, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_query.ts new file mode 100644 index 000000000000..6be364e70091 --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/step_define_rule/use_persistent_query.ts @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEffect, useMemo, useRef } from 'react'; +import { isEqual } from 'lodash'; +import usePrevious from 'react-use/lib/usePrevious'; +import type { EqlOptions } from '../../../../../common/search_strategy'; +import type { FieldHook } from '../../../../shared_imports'; +import { useFormData, type FormHook } from '../../../../shared_imports'; +import type { DefineStepRule } from '../../../../detections/pages/detection_engine/rules/types'; +import { + isEqlRule, + isEsqlRule, + isThreatMatchRule, +} from '../../../../../common/detection_engine/utils'; +import { + DEFAULT_EQL_QUERY_FIELD_VALUE, + DEFAULT_ESQL_QUERY_FIELD_VALUE, + DEFAULT_KQL_QUERY_FIELD_VALUE, + DEFAULT_THREAT_MATCH_KQL_QUERY_FIELD_VALUE, + type FieldValueQueryBar, +} from '../query_bar_field'; + +const EQL_QUERY_LANGUAGE = 'eql'; +const ESQL_QUERY_LANGUAGE = 'esql'; + +interface UsePersistentQueryParams { + form: FormHook<DefineStepRule>; +} + +interface UsePersistentQueryResult { + setPersistentQuery: (value: FieldValueQueryBar) => void; + setPersistentEqlQuery: (value: FieldValueQueryBar) => void; + setPersistentEqlOptions: (value: EqlOptions) => void; + setPersistentEsqlQuery: (value: FieldValueQueryBar) => void; +} + +/** + * Persists query when switching between different rule types using different queries (kuery, EQL and ES|QL). + * + * When the user changes rule type to or from "threat_match" this will modify the + * default "Custom query" string to either: + * * from '' to '*:*' if the type is switched to "threat_match" + * * from '*:*' back to '' if the type is switched back from "threat_match" to another one + */ +export function usePersistentQuery({ form }: UsePersistentQueryParams): UsePersistentQueryResult { + /** + * The main idea of this hook is persisting of the state when user switches between + * different rule types. It's necessary since we conditionally render different query type + * fields. Kibana's Form lib doesn't persist field values when corresponding UseField hooks + * aren't rendered. + */ + const [{ ruleType, queryBar: currentQuery, eqlOptions: currentEqlOptions }] = + useFormData<DefineStepRule>({ + form, + watch: ['ruleType', 'queryBar', 'eqlOptions'], + }); + const previousRuleType = usePrevious(ruleType); + const queryRef = useRef<FieldValueQueryBar>(DEFAULT_KQL_QUERY_FIELD_VALUE); + const eqlQueryRef = useRef<FieldValueQueryBar>(DEFAULT_EQL_QUERY_FIELD_VALUE); + const eqlOptionsRef = useRef<EqlOptions>({}); + const esqlQueryRef = useRef<FieldValueQueryBar>(DEFAULT_ESQL_QUERY_FIELD_VALUE); + + /** + * This useEffect is concerned about persisting the current query in a corresponding React + * reference. There are 3 query types (kuery, EQL, ES|QL). An additional check is required to + * make sure query type matches rule type. When switching between rule types it takes a few + * re-renders to update the form data. + */ + useEffect(() => { + if (!ruleType) { + return; + } + + if (isEqlRule(ruleType)) { + eqlQueryRef.current = + currentQuery?.query?.language === EQL_QUERY_LANGUAGE ? currentQuery : eqlQueryRef.current; + eqlOptionsRef.current = + currentQuery?.query?.language === EQL_QUERY_LANGUAGE + ? currentEqlOptions + : eqlOptionsRef.current; + + return; + } + + if (isEsqlRule(ruleType)) { + esqlQueryRef.current = + currentQuery?.query?.language === ESQL_QUERY_LANGUAGE ? currentQuery : esqlQueryRef.current; + + return; + } + + if ([EQL_QUERY_LANGUAGE, ESQL_QUERY_LANGUAGE].includes(currentQuery?.query?.language)) { + return; + } + + queryRef.current = currentQuery; + }, [ruleType, currentQuery, currentEqlOptions]); + + /** + * This useEffect restores a corresponding query (kuery, EQL or ES|QL) in form data + * after switching rule types. There is an exceptional case with threat_match rules + * having a special default kuery `*:*` while the other rules using kuery have en empty + * string kuery by default. + */ + useEffect(() => { + if (ruleType === previousRuleType || !ruleType) { + return; + } + + const queryField = form.getFields().queryBar as FieldHook<FieldValueQueryBar>; + const eqlOptionsField = form.getFields().eqlOptions as FieldHook<EqlOptions>; + + if (isEqlRule(ruleType)) { + queryField.reset({ + defaultValue: eqlQueryRef.current, + }); + eqlOptionsField.reset({ + defaultValue: eqlOptionsRef.current, + }); + return; + } + + if (isEsqlRule(ruleType)) { + queryField.reset({ + defaultValue: esqlQueryRef.current, + }); + + return; + } + + if (isThreatMatchRule(ruleType) && isEqual(queryRef.current, DEFAULT_KQL_QUERY_FIELD_VALUE)) { + queryField.reset({ + defaultValue: DEFAULT_THREAT_MATCH_KQL_QUERY_FIELD_VALUE, + }); + + return; + } + + if ( + isThreatMatchRule(previousRuleType) && + isEqual(queryRef.current, DEFAULT_THREAT_MATCH_KQL_QUERY_FIELD_VALUE) + ) { + queryField.reset({ + defaultValue: DEFAULT_KQL_QUERY_FIELD_VALUE, + }); + } + + if (isEqlRule(previousRuleType) || isEsqlRule(previousRuleType)) { + queryField.reset({ + defaultValue: queryRef.current, + }); + } + }, [ruleType, previousRuleType, form]); + + return useMemo( + () => ({ + setPersistentQuery: (value: FieldValueQueryBar) => (queryRef.current = value), + setPersistentEqlQuery: (value: FieldValueQueryBar) => (eqlQueryRef.current = value), + setPersistentEqlOptions: (value: EqlOptions) => (eqlOptionsRef.current = value), + setPersistentEsqlQuery: (value: FieldValueQueryBar) => (esqlQueryRef.current = value), + }), + [] + ); +} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/threatmatch_input/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/threatmatch_input/index.tsx index c2b04b7d15da..b2c9cab59e39 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/threatmatch_input/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/components/threatmatch_input/index.tsx @@ -19,7 +19,7 @@ import { } from '../../../../shared_imports'; import type { DefineStepRule } from '../../../../detections/pages/detection_engine/rules/types'; import { schema } from '../step_define_rule/schema'; -import { QueryBarDefineRule } from '../query_bar'; +import { QueryBarField } from '../query_bar_field'; import * as i18n from '../step_define_rule/translations'; import { MyLabelButton } from '../step_define_rule'; @@ -96,7 +96,7 @@ const ThreatMatchInputComponent: React.FC<ThreatMatchInputProps> = ({ ...schema.threatQueryBar, labelAppend: null, }} - component={QueryBarDefineRule} + component={QueryBarField} componentProps={{ idAria: 'detectionEngineStepDefineThreatRuleQueryBar', indexPattern: threatIndexPatterns, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/hooks/use_all_esql_rule_fields.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/hooks/use_all_esql_rule_fields.ts index 80bfc364e5b5..e49c7ccc9f48 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/hooks/use_all_esql_rule_fields.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/hooks/use_all_esql_rule_fields.ts @@ -6,30 +6,16 @@ */ import { useMemo, useState } from 'react'; import type { DatatableColumn } from '@kbn/expressions-plugin/public'; -import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DataViewFieldBase } from '@kbn/es-query'; import useDebounce from 'react-use/lib/useDebounce'; - -import { useQuery } from '@tanstack/react-query'; - -import { useKibana } from '@kbn/kibana-react-plugin/public'; import { computeIsESQLQueryAggregating } from '@kbn/securitysolution-utils'; +import { useEsqlQueryColumns } from '../../rule_creation/logic/esql_query_columns'; -import { getEsqlQueryConfig } from '../../rule_creation/logic/get_esql_query_config'; - -const esqlToFields = ( - columns: { error: unknown } | DatatableColumn[] | undefined | null -): DataViewFieldBase[] => { - if (columns && 'error' in columns) { - return []; - } - - const fields = (columns ?? []).map(({ id, meta }) => { - return { - name: id, - type: meta.type, - }; - }); +const esqlToFields = (columns: DatatableColumn[]): DataViewFieldBase[] => { + const fields = columns.map(({ id, meta }) => ({ + name: id, + type: meta.type, + })); return fields; }; @@ -43,16 +29,11 @@ type UseEsqlFields = (esqlQuery: string | undefined) => { * fetches ES|QL fields and convert them to DataViewBase fields */ export const useEsqlFields: UseEsqlFields = (esqlQuery) => { - const kibana = useKibana<{ data: DataPublicPluginStart }>(); - - const { data: dataService } = kibana.services; - - const queryConfig = getEsqlQueryConfig({ esqlQuery, search: dataService?.search?.search }); - const { data, isLoading } = useQuery(queryConfig); + const { columns, isLoading } = useEsqlQueryColumns(esqlQuery ?? ''); const fields = useMemo(() => { - return esqlToFields(data); - }, [data]); + return esqlToFields(columns); + }, [columns]); return { fields, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.test.ts index d2bbe9edb116..3210ac84b159 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.test.ts @@ -7,7 +7,6 @@ import { renderHook } from '@testing-library/react-hooks'; import type { FormData, FormHook, ValidationError } from '../../../shared_imports'; -import { ERROR_CODES as ESQL_ERROR_CODES } from '../../rule_creation/logic/esql_validator'; import { EQL_ERROR_CODES } from '../../../common/hooks/eql/api'; import type { AboutStepRule, @@ -15,9 +14,9 @@ import type { DefineStepRule, ScheduleStepRule, } from '../../../detections/pages/detection_engine/rules/types'; - -import { useRuleFormsErrors } from './form'; import { ALERT_SUPPRESSION_FIELDS_FIELD_NAME } from '../../rule_creation/components/alert_suppression_edit'; +import { ESQL_ERROR_CODES } from '../../rule_creation/components/esql_query_edit'; +import { useRuleFormsErrors } from './form'; const getFormWithErrorsMock = <T extends FormData = FormData>(fields: { [key: string]: { errors: Array<ValidationError<EQL_ERROR_CODES | ESQL_ERROR_CODES>> }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx index 64230fd3a8a2..f88d0c144944 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/form.tsx @@ -23,10 +23,10 @@ import { schema as aboutRuleSchema, threatMatchAboutSchema, } from '../components/step_about_rule/schema'; +import { ESQL_ERROR_CODES } from '../../rule_creation/components/esql_query_edit'; import { schema as scheduleRuleSchema } from '../components/step_schedule_rule/schema'; import { getSchema as getActionsRuleSchema } from '../../rule_creation/components/step_rule_actions/get_schema'; import { useFetchIndex } from '../../../common/containers/source'; -import { ERROR_CODES as ESQL_ERROR_CODES } from '../../rule_creation/logic/esql_validator'; import { EQL_ERROR_CODES } from '../../../common/hooks/eql/api'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx index 01435a2f7c65..6019b696a089 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/index.tsx @@ -557,7 +557,6 @@ const CreateRulePageComponent: React.FC = () => { isQueryBarValid={isQueryBarValid} setIsQueryBarValid={setIsQueryBarValid} setIsThreatQueryBarValid={setIsThreatQueryBarValid} - ruleType={defineStepData.ruleType} index={memoizedIndex} threatIndex={defineStepData.threatIndex} alertSuppressionFields={defineStepData[ALERT_SUPPRESSION_FIELDS_FIELD_NAME]} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index b09ee5f4e3f4..dbc753ca33d3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -236,7 +236,6 @@ const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { isQueryBarValid={isQueryBarValid} setIsQueryBarValid={setIsQueryBarValid} setIsThreatQueryBarValid={setIsThreatQueryBarValid} - ruleType={defineStepData.ruleType} index={memoizedIndex} threatIndex={defineStepData.threatIndex} alertSuppressionFields={defineStepData[ALERT_SUPPRESSION_FIELDS_FIELD_NAME]} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/kuery_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/kuery_validator_factory.ts index f362acffd3bc..8c2618103320 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/kuery_validator_factory.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/kuery_validator_factory.ts @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; import { fromKueryExpression } from '@kbn/es-query'; import type { FormData, ValidationFunc } from '../../../shared_imports'; -import type { FieldValueQueryBar } from '../components/query_bar'; +import type { FieldValueQueryBar } from '../components/query_bar_field'; export function kueryValidatorFactory(): ValidationFunc<FormData, string, FieldValueQueryBar> { return (...args) => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/query_required_validator_factory.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/query_required_validator_factory.ts index f06aaa6b312f..f0bab68eaa69 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/query_required_validator_factory.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/validators/query_required_validator_factory.ts @@ -10,7 +10,7 @@ import { isEmpty } from 'lodash'; import type { RuleType } from '@kbn/securitysolution-rules'; import type { FormData, ValidationFunc } from '../../../shared_imports'; import { isEqlRule, isEsqlRule } from '../../../../common/detection_engine/utils'; -import type { FieldValueQueryBar } from '../components/query_bar'; +import type { FieldValueQueryBar } from '../components/query_bar_field'; export function queryRequiredValidatorFactory( ruleType: RuleType diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts index 2e005cd7ca03..eac29becca31 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts @@ -4,10 +4,11 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -/* eslint-disable no-restricted-imports */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { renderHook, cleanup } from '@testing-library/react'; +// eslint-disable-next-line no-restricted-imports import type { UseLegacyUrlRedirectParams } from './use_redirect_legacy_url'; +// eslint-disable-next-line no-restricted-imports import { useLegacyUrlRedirect } from './use_redirect_legacy_url'; import type { Rule } from '../../../rule_management/logic'; import type { SpacesApi } from '@kbn/spaces-plugin/public'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx index 1dec9aa36d21..6f616f23d1ce 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { cleanup, renderHook } from '@testing-library/react-hooks'; +import { renderHook, cleanup } from '@testing-library/react'; import type { UseRuleDetailsTabsProps } from './use_rule_details_tabs'; import { RuleDetailTabs, useRuleDetailsTabs } from './use_rule_details_tabs'; import type { Rule } from '../../../rule_management/logic'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index aea4b6672659..4bde24e9f457 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -679,10 +679,15 @@ export const performInstallSpecificRules = async ( }), }); -export const performUpgradeSpecificRules = async ( - rules: UpgradeSpecificRulesRequest['rules'], - pickVersion: PickVersionValues -): Promise<PerformRuleUpgradeResponseBody> => +export interface PerformUpgradeRequest { + rules: UpgradeSpecificRulesRequest['rules']; + pickVersion: PickVersionValues; +} + +export const performUpgradeSpecificRules = async ({ + rules, + pickVersion, +}: PerformUpgradeRequest): Promise<PerformRuleUpgradeResponseBody> => KibanaServices.get().http.fetch(PERFORM_RULE_UPGRADE_URL, { method: 'POST', version: '1', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts index 08338ab9a932..f560440e7fff 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation.ts @@ -6,16 +6,13 @@ */ import type { UseMutationOptions } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query'; -import type { - PerformRuleUpgradeResponseBody, - PickVersionValues, - UpgradeSpecificRulesRequest, -} from '../../../../../../common/api/detection_engine/prebuilt_rules'; +import type { PerformRuleUpgradeResponseBody } from '../../../../../../common/api/detection_engine/prebuilt_rules'; import { PERFORM_RULE_UPGRADE_URL } from '../../../../../../common/api/detection_engine/prebuilt_rules/urls'; import { useInvalidateFetchPrebuiltRulesStatusQuery } from './use_fetch_prebuilt_rules_status_query'; import { useInvalidateFindRulesQuery } from '../use_find_rules_query'; import { useInvalidateFetchRuleManagementFiltersQuery } from '../use_fetch_rule_management_filters_query'; import { useInvalidateFetchRulesSnoozeSettingsQuery } from '../use_fetch_rules_snooze_settings_query'; +import type { PerformUpgradeRequest } from '../../api'; import { performUpgradeSpecificRules } from '../../api'; import { useInvalidateFetchPrebuiltRulesUpgradeReviewQuery } from './use_fetch_prebuilt_rules_upgrade_review_query'; import { useInvalidateFetchCoverageOverviewQuery } from '../use_fetch_coverage_overview_query'; @@ -27,12 +24,7 @@ export const PERFORM_SPECIFIC_RULES_UPGRADE_KEY = [ ]; export const usePerformSpecificRulesUpgradeMutation = ( - pickVersion: PickVersionValues, - options?: UseMutationOptions< - PerformRuleUpgradeResponseBody, - Error, - UpgradeSpecificRulesRequest['rules'] - > + options?: UseMutationOptions<PerformRuleUpgradeResponseBody, Error, PerformUpgradeRequest> ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRulesSnoozeSettings = useInvalidateFetchRulesSnoozeSettingsQuery(); @@ -43,9 +35,9 @@ export const usePerformSpecificRulesUpgradeMutation = ( const invalidateRuleStatus = useInvalidateFetchPrebuiltRulesStatusQuery(); const invalidateFetchCoverageOverviewQuery = useInvalidateFetchCoverageOverviewQuery(); - return useMutation<PerformRuleUpgradeResponseBody, Error, UpgradeSpecificRulesRequest['rules']>( - (rulesToUpgrade: UpgradeSpecificRulesRequest['rules']) => { - return performUpgradeSpecificRules(rulesToUpgrade, pickVersion); + return useMutation<PerformRuleUpgradeResponseBody, Error, PerformUpgradeRequest>( + (args: PerformUpgradeRequest) => { + return performUpgradeSpecificRules(args); }, { ...options, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/per_field_rule_diff_tab.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/per_field_rule_diff_tab.tsx index f03cd8ed23bb..32dc508f41bb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/per_field_rule_diff_tab.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/per_field_rule_diff_tab.tsx @@ -16,9 +16,10 @@ import * as i18n from './translations'; interface PerFieldRuleDiffTabProps { ruleDiff: PartialRuleDiff; + header?: React.ReactNode; } -export const PerFieldRuleDiffTab = ({ ruleDiff }: PerFieldRuleDiffTabProps) => { +export const PerFieldRuleDiffTab = ({ ruleDiff, header }: PerFieldRuleDiffTabProps) => { const fieldsToRender = useMemo(() => { const fields: FieldsGroupDiff[] = []; // Filter out diff outcomes that we don't support displaying in the per-field diff flyout @@ -44,6 +45,7 @@ export const PerFieldRuleDiffTab = ({ ruleDiff }: PerFieldRuleDiffTabProps) => { return ( <> <RuleDiffHeaderBar /> + {header} {aboutFields.length !== 0 && ( <RuleDiffSection title={i18n.ABOUT_SECTION_LABEL} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index 295323017f06..70f267ac94ba 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -185,15 +185,23 @@ interface ThresholdProps { threshold: ThresholdType; } -export const Threshold = ({ threshold }: ThresholdProps) => ( - <div data-test-subj="thresholdPropertyValue"> - {isEmpty(threshold.field[0]) - ? `${descriptionStepI18n.THRESHOLD_RESULTS_ALL} >= ${threshold.value}` - : `${descriptionStepI18n.THRESHOLD_RESULTS_AGGREGATED_BY} ${ - Array.isArray(threshold.field) ? threshold.field.join(',') : threshold.field - } >= ${threshold.value}`} - </div> -); +export const Threshold = ({ threshold }: ThresholdProps) => { + let thresholdDescription = isEmpty(threshold.field[0]) + ? `${descriptionStepI18n.THRESHOLD_RESULTS_ALL} >= ${threshold.value}` + : `${descriptionStepI18n.THRESHOLD_RESULTS_AGGREGATED_BY} ${ + Array.isArray(threshold.field) ? threshold.field.join(',') : threshold.field + } >= ${threshold.value}`; + + if (threshold.cardinality && threshold.cardinality.length > 0) { + thresholdDescription = descriptionStepI18n.THRESHOLD_CARDINALITY( + thresholdDescription, + threshold.cardinality[0].field, + threshold.cardinality[0].value + ); + } + + return <div data-test-subj="thresholdPropertyValue">{thresholdDescription}</div>; +}; interface AnomalyThresholdProps { anomalyThreshold: number; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/esql_rule_field_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/esql_rule_field_edit.tsx index 745d25da3839..12777222736c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/esql_rule_field_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/esql_rule_field_edit.tsx @@ -7,17 +7,21 @@ import React from 'react'; import type { UpgradeableEsqlFields } from '../../../../model/prebuilt_rule_upgrade/fields'; +import { assertUnreachable } from '../../../../../../../common/utility_types'; +import { EsqlQueryEditForm } from './fields/esql_query'; import { AlertSuppressionEditForm } from './fields/alert_suppression'; -interface EqQlRuleFieldEditProps { +interface EsqlRuleFieldEditProps { fieldName: UpgradeableEsqlFields; } -export function EsqlRuleFieldEdit({ fieldName }: EqQlRuleFieldEditProps) { +export function EsqlRuleFieldEdit({ fieldName }: EsqlRuleFieldEditProps) { switch (fieldName) { + case 'esql_query': + return <EsqlQueryEditForm />; case 'alert_suppression': return <AlertSuppressionEditForm />; default: - return null; // Will be replaced with `assertUnreachable(fieldName)` once all fields are implemented + return assertUnreachable(fieldName); } } diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx index 3a8312897671..4dd953006d39 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/eql_query/eql_query_edit_form.tsx @@ -8,9 +8,9 @@ import React from 'react'; import type { Filter } from '@kbn/es-query'; import type { EqlOptions } from '@kbn/timelines-plugin/common'; +import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar_field'; import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; -import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar'; import { type DiffableRule, RuleEqlQuery, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx new file mode 100644 index 000000000000..a9375b7316bb --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_adapter.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { DataViewBase } from '@kbn/es-query'; +import { EsqlQueryEdit } from '../../../../../../../rule_creation/components/esql_query_edit'; +import type { RuleFieldEditComponentProps } from '../rule_field_edit_component_props'; +import { useDiffableRuleDataView } from '../hooks/use_diffable_rule_data_view'; + +export function EsqlQueryEditAdapter({ + finalDiffableRule, +}: RuleFieldEditComponentProps): JSX.Element { + const { dataView, isLoading } = useDiffableRuleDataView(finalDiffableRule); + + return ( + <EsqlQueryEdit + path="esqlQuery" + required + dataView={dataView ?? DEFAULT_DATA_VIEW_BASE} + loading={isLoading} + disabled={isLoading} + skipIdColumnCheck + /> + ); +} + +const DEFAULT_DATA_VIEW_BASE: DataViewBase = { + title: '', + fields: [], +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx new file mode 100644 index 000000000000..a156ef747aed --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/esql_query_edit_form.tsx @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; +import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; +import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar_field'; +import { + type DiffableRule, + QueryLanguageEnum, + RuleEsqlQuery, +} from '../../../../../../../../../common/api/detection_engine'; +import { EsqlQueryEditAdapter } from './esql_query_edit_adapter'; + +export function EsqlQueryEditForm(): JSX.Element { + return ( + <RuleFieldEditFormWrapper + component={EsqlQueryEditAdapter} + ruleFieldFormSchema={formSchema} + deserializer={deserializer} + serializer={serializer} + /> + ); +} + +const formSchema = {} as FormSchema<{ + esqlQuery: RuleEsqlQuery; +}>; + +function deserializer( + fieldValue: FormData, + finalDiffableRule: DiffableRule +): { + esqlQuery: FieldValueQueryBar; +} { + const parsedEsqlQuery = + 'esql_query' in finalDiffableRule + ? RuleEsqlQuery.parse(fieldValue.esql_query) + : { + query: '', + language: QueryLanguageEnum.esql, + filters: [], + }; + + return { + esqlQuery: { + query: { + query: parsedEsqlQuery.query, + language: parsedEsqlQuery.language, + }, + filters: [], + saved_id: null, + }, + }; +} + +function serializer(formData: FormData): { + esql_query: RuleEsqlQuery; +} { + const formValue = formData as { esqlQuery: FieldValueQueryBar }; + + return { + esql_query: { + query: formValue.esqlQuery.query.query as string, + language: QueryLanguageEnum.esql, + }, + }; +} diff --git a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/index.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/index.ts similarity index 82% rename from x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/index.ts rename to x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/index.ts index dcb2d12f6c98..309a56c96d16 100644 --- a/x-pack/plugins/search_inference_endpoints/public/components/empty_prompt/index.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/esql_query/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { AddEmptyPrompt } from './add_empty_prompt'; +export * from './esql_query_edit_form'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx index 8dbcc03e9783..27415855adfb 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit.tsx @@ -12,7 +12,7 @@ import { EuiButtonEmpty } from '@elastic/eui'; import type { DataViewBase } from '@kbn/es-query'; import { schema } from '../../../../../../../rule_creation_ui/components/step_define_rule/schema'; import { HiddenField, UseField } from '../../../../../../../../shared_imports'; -import { QueryBarDefineRule } from '../../../../../../../rule_creation_ui/components/query_bar'; +import { QueryBarField } from '../../../../../../../rule_creation_ui/components/query_bar_field'; import * as stepDefineRuleI18n from '../../../../../../../rule_creation_ui/components/step_define_rule/translations'; import type { DiffableRule } from '../../../../../../../../../common/api/detection_engine'; import type { SetRuleQuery } from '../../../../../../../../detections/containers/detection_engine/rules/use_rule_from_timeline'; @@ -58,7 +58,7 @@ export function KqlQueryEdit({ <ImportTimelineQueryButton handleOpenTimelineSearch={toggleIsTimelineSearchOpen} /> ), }} - component={QueryBarDefineRule} + component={QueryBarField} componentProps={{ indexPattern: dataView ?? DEFAULT_DATA_VIEW, isLoading, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx index b6bab6e57976..98ffc4b6bfdf 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/three_way_diff/final_edit/fields/kql_query/kql_query_edit_form.tsx @@ -10,7 +10,7 @@ import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import type { FormData, FormSchema } from '../../../../../../../../shared_imports'; import { schema } from '../../../../../../../rule_creation_ui/components/step_define_rule/schema'; import { RuleFieldEditFormWrapper } from '../rule_field_edit_form_wrapper'; -import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar'; +import type { FieldValueQueryBar } from '../../../../../../../rule_creation_ui/components/query_bar_field'; import { KqlQueryLanguage, KqlQueryType, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts index 968b40c7a602..6cd50548f5d0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_bulk_export.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useRulesTableContextOptional } from '../../../rule_management_ui/components/rules_table/rules_table/rules_table_context'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts index 6309d8b629bc..ee9b43af4355 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/bulk_actions/use_execute_bulk_action.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { BulkActionTypeEnum } from '../../../../../common/api/detection_engine/rule_management'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { METRIC_TYPE, TELEMETRY_EVENT, track } from '../../../../common/lib/telemetry'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts index f82812f7ac9d..33f36ffe14da 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/prebuilt_rules/use_perform_rule_upgrade.ts @@ -4,20 +4,15 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { PickVersionValues } from '../../../../../common/api/detection_engine'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { usePerformSpecificRulesUpgradeMutation } from '../../api/hooks/prebuilt_rules/use_perform_specific_rules_upgrade_mutation'; import * as i18n from './translations'; -export const usePerformUpgradeSpecificRules = ({ - pickVersion, -}: { - pickVersion: PickVersionValues; -}) => { +export const usePerformUpgradeSpecificRules = () => { const { addError, addSuccess } = useAppToasts(); - return usePerformSpecificRulesUpgradeMutation(pickVersion, { + return usePerformSpecificRulesUpgradeMutation({ onError: (err) => { addError(err, { title: i18n.RULE_UPGRADE_FAILED }); }, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx index 949c957bf83c..27615ef2d489 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_alert_suppression.test.tsx @@ -4,7 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; + +import { renderHook } from '@testing-library/react'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { useAlertSuppression } from './use_alert_suppression'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts index 553f8734b454..37acd41f9822 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_dissasociate_exception_list.test.ts @@ -5,16 +5,12 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { coreMock } from '@kbn/core/public/mocks'; import * as api from '../api/api'; import { getRulesSchemaMock } from '../../../../common/api/detection_engine/model/rule_schema/mocks'; -import type { - ReturnUseDisassociateExceptionList, - UseDisassociateExceptionListProps, -} from './use_disassociate_exception_list'; import { useDisassociateExceptionList } from './use_disassociate_exception_list'; const mockKibanaHttpService = coreMock.createStart().http; @@ -33,10 +29,7 @@ describe('useDisassociateExceptionList', () => { test('initializes hook', async () => { await act(async () => { - const { result, waitForNextUpdate } = renderHook< - UseDisassociateExceptionListProps, - ReturnUseDisassociateExceptionList - >(() => + const { result } = renderHook(() => useDisassociateExceptionList({ http: mockKibanaHttpService, ruleRuleId: 'rule_id', @@ -45,9 +38,7 @@ describe('useDisassociateExceptionList', () => { }) ); - await waitForNextUpdate(); - - expect(result.current).toEqual([false, null]); + await waitFor(() => expect(result.current).toEqual([false, null])); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts index cdb6e805d18c..e62428f9f17d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_indices.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useRuleIndices } from './use_rule_indices'; import { useGetInstalledJob } from '../../../common/components/ml/hooks/use_get_jobs'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts index 2802153a4567..25b2d88c6ddd 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts @@ -16,7 +16,7 @@ import { DataSourceType, AlertSuppressionDurationType, } from '../../../../../detections/pages/detection_engine/rules/types'; -import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar'; +import type { FieldValueQueryBar } from '../../../../rule_creation_ui/components/query_bar_field'; import { fillEmptySeverityMappings } from '../../../../../detections/pages/detection_engine/rules/helpers'; import { getThreatMock } from '../../../../../../common/detection_engine/schemas/types/threat.mock'; import { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_header_buttons.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_header_buttons.tsx index 6fbdd5b4f891..58a8f7b779a1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_header_buttons.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_header_buttons.tsx @@ -28,6 +28,7 @@ export const AddPrebuiltRulesHeaderButtons = () => { loadingRules, isRefetching, isUpgradingSecurityPackages, + isInstallingAllRules, hasRulesToInstall, }, actions: { installAllRules, installSelectedRules }, @@ -38,7 +39,7 @@ export const AddPrebuiltRulesHeaderButtons = () => { const numberOfSelectedRules = selectedRules.length ?? 0; const shouldDisplayInstallSelectedRulesButton = numberOfSelectedRules > 0; - const isRuleInstalling = loadingRules.length > 0; + const isRuleInstalling = loadingRules.length > 0 || isInstallingAllRules; const isRequestInProgress = isRuleInstalling || isRefetching || isUpgradingSecurityPackages; const [isOverflowPopoverOpen, setOverflowPopover] = useBoolean(false); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_install_button.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_install_button.tsx index 6ea9e9dd6a74..4d239458e6a5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_install_button.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_install_button.tsx @@ -19,7 +19,7 @@ import React, { useCallback, useMemo } from 'react'; import useBoolean from 'react-use/lib/useBoolean'; import type { Rule } from '../../../../rule_management/logic'; import type { RuleSignatureId } from '../../../../../../common/api/detection_engine'; -import type { AddPrebuiltRulesTableActions } from './add_prebuilt_rules_table_context'; +import { type AddPrebuiltRulesTableActions } from './add_prebuilt_rules_table_context'; import * as i18n from './translations'; export interface PrebuiltRulesInstallButtonProps { @@ -28,6 +28,7 @@ export interface PrebuiltRulesInstallButtonProps { installOneRule: AddPrebuiltRulesTableActions['installOneRule']; loadingRules: RuleSignatureId[]; isDisabled: boolean; + isInstallingAllRules: boolean; } export const PrebuiltRulesInstallButton = ({ @@ -36,8 +37,9 @@ export const PrebuiltRulesInstallButton = ({ installOneRule, loadingRules, isDisabled, + isInstallingAllRules, }: PrebuiltRulesInstallButtonProps) => { - const isRuleInstalling = loadingRules.includes(ruleId); + const isRuleInstalling = loadingRules.includes(ruleId) || isInstallingAllRules; const isInstallButtonDisabled = isRuleInstalling || isDisabled; const [isPopoverOpen, setPopover] = useBoolean(false); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.test.tsx index 4be2547598b5..c8ee77040b18 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table.test.tsx @@ -14,6 +14,7 @@ import { useUserData } from '../../../../../detections/components/user_info'; import { usePrebuiltRulesInstallReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_install_review'; import { useFetchPrebuiltRulesStatusQuery } from '../../../../rule_management/api/hooks/prebuilt_rules/use_fetch_prebuilt_rules_status_query'; import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; // Mock components not needed in this test suite jest.mock('../../../../rule_management/components/rule_details/rule_details_flyout', () => ({ @@ -109,10 +110,12 @@ describe('AddPrebuiltRulesTable', () => { ]); render( - <AddPrebuiltRulesTableContextProvider> - <AddPrebuiltRulesHeaderButtons /> - <AddPrebuiltRulesTable /> - </AddPrebuiltRulesTableContextProvider> + <QueryClientProvider client={new QueryClient()}> + <AddPrebuiltRulesTableContextProvider> + <AddPrebuiltRulesHeaderButtons /> + <AddPrebuiltRulesTable /> + </AddPrebuiltRulesTableContextProvider> + </QueryClientProvider> ); const installAllButton = screen.getByTestId('installAllRulesButton'); @@ -132,10 +135,12 @@ describe('AddPrebuiltRulesTable', () => { (useIsUpgradingSecurityPackages as jest.Mock).mockReturnValueOnce(true); render( - <AddPrebuiltRulesTableContextProvider> - <AddPrebuiltRulesHeaderButtons /> - <AddPrebuiltRulesTable /> - </AddPrebuiltRulesTableContextProvider> + <QueryClientProvider client={new QueryClient()}> + <AddPrebuiltRulesTableContextProvider> + <AddPrebuiltRulesHeaderButtons /> + <AddPrebuiltRulesTable /> + </AddPrebuiltRulesTableContextProvider> + </QueryClientProvider> ); const installAllButton = screen.getByTestId('installAllRulesButton'); @@ -153,10 +158,12 @@ describe('AddPrebuiltRulesTable', () => { ]); render( - <AddPrebuiltRulesTableContextProvider> - <AddPrebuiltRulesHeaderButtons /> - <AddPrebuiltRulesTable /> - </AddPrebuiltRulesTableContextProvider> + <QueryClientProvider client={new QueryClient()}> + <AddPrebuiltRulesTableContextProvider> + <AddPrebuiltRulesHeaderButtons /> + <AddPrebuiltRulesTable /> + </AddPrebuiltRulesTableContextProvider> + </QueryClientProvider> ); const installAllButton = screen.getByTestId('installAllRulesButton'); @@ -198,9 +205,11 @@ describe('AddPrebuiltRulesTable', () => { }); const { findByText } = render( - <AddPrebuiltRulesTableContextProvider> - <AddPrebuiltRulesTable /> - </AddPrebuiltRulesTableContextProvider> + <QueryClientProvider client={new QueryClient()}> + <AddPrebuiltRulesTableContextProvider> + <AddPrebuiltRulesTable /> + </AddPrebuiltRulesTableContextProvider> + </QueryClientProvider> ); expect(await findByText('All Elastic rules have been installed')).toBeInTheDocument(); @@ -245,9 +254,11 @@ describe('AddPrebuiltRulesTable', () => { }); render( - <AddPrebuiltRulesTableContextProvider> - <AddPrebuiltRulesTable /> - </AddPrebuiltRulesTableContextProvider> + <QueryClientProvider client={new QueryClient()}> + <AddPrebuiltRulesTableContextProvider> + <AddPrebuiltRulesTable /> + </AddPrebuiltRulesTableContextProvider> + </QueryClientProvider> ); const installRuleButton = screen.queryByTestId(`installSinglePrebuiltRuleButton-${id}`); @@ -293,9 +304,11 @@ describe('AddPrebuiltRulesTable', () => { }); render( - <AddPrebuiltRulesTableContextProvider> - <AddPrebuiltRulesTable /> - </AddPrebuiltRulesTableContextProvider> + <QueryClientProvider client={new QueryClient()}> + <AddPrebuiltRulesTableContextProvider> + <AddPrebuiltRulesTable /> + </AddPrebuiltRulesTableContextProvider> + </QueryClientProvider> ); const installRuleButton = screen.queryByTestId(`installSinglePrebuiltRuleButton-${id}`); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx index 14e539ec40ae..dca480900197 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx @@ -5,25 +5,27 @@ * 2.0. */ +import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { useIsMutating } from '@tanstack/react-query'; import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; -import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { useUserData } from '../../../../../detections/components/user_info'; -import { useFetchPrebuiltRulesStatusQuery } from '../../../../rule_management/api/hooks/prebuilt_rules/use_fetch_prebuilt_rules_status_query'; -import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; import type { RuleSignatureId } from '../../../../../../common/api/detection_engine'; +import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { invariant } from '../../../../../../common/utils/invariant'; +import { useUserData } from '../../../../../detections/components/user_info'; +import { useFetchPrebuiltRulesStatusQuery } from '../../../../rule_management/api/hooks/prebuilt_rules/use_fetch_prebuilt_rules_status_query'; +import { PERFORM_ALL_RULES_INSTALLATION_KEY } from '../../../../rule_management/api/hooks/prebuilt_rules/use_perform_all_rules_install_mutation'; import { usePerformInstallAllRules, usePerformInstallSpecificRules, } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_install'; import { usePrebuiltRulesInstallReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_install_review'; -import type { AddPrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_install'; -import { useFilterPrebuiltRulesToInstall } from './use_filter_prebuilt_rules_to_install'; +import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; import { useRulePreviewFlyout } from '../use_rule_preview_flyout'; -import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema'; -import * as i18n from './translations'; import { isUpgradeReviewRequestEnabled } from './add_prebuilt_rules_utils'; +import * as i18n from './translations'; +import type { AddPrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_install'; +import { useFilterPrebuiltRulesToInstall } from './use_filter_prebuilt_rules_to_install'; export interface AddPrebuiltRulesTableState { /** @@ -59,6 +61,11 @@ export interface AddPrebuiltRulesTableState { * package in background */ isUpgradingSecurityPackages: boolean; + + /** + * Is true when performing Install All Rules mutation + */ + isInstallingAllRules: boolean; /** * List of rule IDs that are currently being upgraded */ @@ -112,6 +119,10 @@ export const AddPrebuiltRulesTableContextProvider = ({ const { data: prebuiltRulesStatus } = useFetchPrebuiltRulesStatusQuery(); const isUpgradingSecurityPackages = useIsUpgradingSecurityPackages(); + const isInstallingAllRules = + useIsMutating({ + mutationKey: PERFORM_ALL_RULES_INSTALLATION_KEY, + }) > 0; const { data: { rules, stats: { tags } } = { @@ -269,6 +280,7 @@ export const AddPrebuiltRulesTableContextProvider = ({ loadingRules, isRefetching, isUpgradingSecurityPackages, + isInstallingAllRules, selectedRules, lastUpdated: dataUpdatedAt, }, @@ -284,6 +296,7 @@ export const AddPrebuiltRulesTableContextProvider = ({ loadingRules, isRefetching, isUpgradingSecurityPackages, + isInstallingAllRules, selectedRules, dataUpdatedAt, actions, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx index eaf3af79ee36..a0a317e72b4c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/use_add_prebuilt_rules_table_columns.tsx @@ -110,7 +110,8 @@ const INTEGRATIONS_COLUMN: TableColumn = { const createInstallButtonColumn = ( installOneRule: AddPrebuiltRulesTableActions['installOneRule'], loadingRules: RuleSignatureId[], - isDisabled: boolean + isDisabled: boolean, + isInstallingAllRules: boolean ): TableColumn => ({ field: 'rule_id', name: <RulesTableEmptyColumnName name={i18n.INSTALL_RULE_BUTTON} />, @@ -121,6 +122,7 @@ const createInstallButtonColumn = ( installOneRule={installOneRule} loadingRules={loadingRules} isDisabled={isDisabled} + isInstallingAllRules={isInstallingAllRules} /> ), width: '10%', @@ -132,11 +134,11 @@ export const useAddPrebuiltRulesTableColumns = (): TableColumn[] => { const hasCRUDPermissions = hasUserCRUDPermission(canUserCRUD); const [showRelatedIntegrations] = useUiSetting$<boolean>(SHOW_RELATED_INTEGRATIONS_SETTING); const { - state: { loadingRules, isRefetching, isUpgradingSecurityPackages }, + state: { loadingRules, isRefetching, isUpgradingSecurityPackages, isInstallingAllRules }, actions: { installOneRule }, } = useAddPrebuiltRulesTableContext(); - const isDisabled = isRefetching || isUpgradingSecurityPackages; + const isDisabled = isRefetching || isUpgradingSecurityPackages || isInstallingAllRules; return useMemo( () => [ @@ -164,9 +166,23 @@ export const useAddPrebuiltRulesTableColumns = (): TableColumn[] => { width: '12%', }, ...(hasCRUDPermissions - ? [createInstallButtonColumn(installOneRule, loadingRules, isDisabled)] + ? [ + createInstallButtonColumn( + installOneRule, + loadingRules, + isDisabled, + isInstallingAllRules + ), + ] : []), ], - [hasCRUDPermissions, installOneRule, loadingRules, isDisabled, showRelatedIntegrations] + [ + hasCRUDPermissions, + installOneRule, + loadingRules, + isDisabled, + showRelatedIntegrations, + isInstallingAllRules, + ] ); }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx index f6fb298feb3d..f948931f1c39 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/rules_table_context.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import type { PropsWithChildren } from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useUiSetting$ } from '../../../../../common/lib/kibana'; import type { Rule, RulesSnoozeSettingsMap } from '../../../../rule_management/logic'; import { useFindRules } from '../../../../rule_management/logic/use_find_rules'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts index 6330c1ad207c..1ed7f4e76c74 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_rules_table_saved_state.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { RULES_TABLE_MAX_PAGE_SIZE } from '../../../../../../common/constants'; import type { RulesTableStorageSavedState, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx index a8e570fd2271..d4593b64d60e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/rules_table/use_sync_rules_table_saved_state.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useReplaceUrlParams } from '../../../../../common/utils/global_query_string/helpers'; import { useKibana } from '../../../../../common/lib/kibana'; import { URL_PARAM_KEY } from '../../../../../common/hooks/use_url_state'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx new file mode 100644 index 000000000000..f66fd92a685f --- /dev/null +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/rule_type_change_callout.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiCallOut } from '@elastic/eui'; +import React from 'react'; +import { + RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION, + RULE_TYPE_CHANGE_CALLOUT_TITLE, +} from './translations'; + +export const RuleTypeChangeCallout = () => { + return ( + <EuiCallOut title={RULE_TYPE_CHANGE_CALLOUT_TITLE} color="danger" iconType="warning"> + <p>{RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION}</p> + </EuiCallOut> + ); +}; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts index 5db5d0eee748..9a07c1bb6908 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/translations.ts @@ -78,3 +78,18 @@ export const UPDATE_FLYOUT_JSON_VIEW_TOOLTIP_DESCRIPTION = i18n.translate( defaultMessage: 'View the latest rule changes in JSON format.', } ); + +export const RULE_TYPE_CHANGE_CALLOUT_TITLE = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeRules.ruleTypeChangeCalloutTitle', + { + defaultMessage: 'Rule type change', + } +); + +export const RULE_TYPE_CHANGE_CALLOUT_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.detectionEngine.upgradeRules.ruleTypeChangeCalloutDescription', + { + defaultMessage: + 'Your customization will be lost at update. Please take note of your customization or clone this rule before updating.', + } +); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx index 4217fa111786..6aad29f8b579 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/upgrade_prebuilt_rules_table_context.tsx @@ -5,43 +5,44 @@ * 2.0. */ +import { EuiButton, EuiToolTip } from '@elastic/eui'; import type { Dispatch, SetStateAction } from 'react'; import React, { createContext, useCallback, useContext, useMemo, useState } from 'react'; -import { EuiButton, EuiToolTip } from '@elastic/eui'; -import { isNonUpgradeableFieldName } from '../../../../rule_management/model/prebuilt_rule_upgrade/fields'; import type { RuleFieldsToUpgrade, - RuleUpgradeSpecifier, RuleUpgradeInfoForReview, + RuleUpgradeSpecifier, } from '../../../../../../common/api/detection_engine'; -import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; -import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; -import type { - RuleUpgradeState, - RulesUpgradeState, -} from '../../../../rule_management/model/prebuilt_rule_upgrade'; -import { RuleUpgradeConflictsResolverTab } from '../../../../rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab'; -import { PerFieldRuleDiffTab } from '../../../../rule_management/components/rule_details/per_field_rule_diff_tab'; -import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; import type { RuleResponse, RuleSignatureId, } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { invariant } from '../../../../../../common/utils/invariant'; -import { usePerformUpgradeSpecificRules } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_upgrade'; -import { usePrebuiltRulesUpgradeReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_upgrade_review'; -import type { UpgradePrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_upgrade'; -import { useFilterPrebuiltRulesToUpgrade } from './use_filter_prebuilt_rules_to_upgrade'; +import { useAppToasts } from '../../../../../common/hooks/use_app_toasts'; +import { PerFieldRuleDiffTab } from '../../../../rule_management/components/rule_details/per_field_rule_diff_tab'; import { TabContentPadding } from '../../../../rule_management/components/rule_details/rule_details_flyout'; import { RuleDiffTab } from '../../../../rule_management/components/rule_details/rule_diff_tab'; +import { RuleUpgradeConflictsResolverTab } from '../../../../rule_management/components/rule_details/three_way_diff/rule_upgrade_conflicts_resolver_tab'; +import * as ruleDetailsI18n from '../../../../rule_management/components/rule_details/translations'; +import { useIsPrebuiltRulesCustomizationEnabled } from '../../../../rule_management/hooks/use_is_prebuilt_rules_customization_enabled'; +import { usePerformUpgradeSpecificRules } from '../../../../rule_management/logic/prebuilt_rules/use_perform_rule_upgrade'; +import { usePrebuiltRulesUpgradeReview } from '../../../../rule_management/logic/prebuilt_rules/use_prebuilt_rules_upgrade_review'; +import { useIsUpgradingSecurityPackages } from '../../../../rule_management/logic/use_upgrade_security_packages'; +import type { + RuleUpgradeState, + RulesUpgradeState, +} from '../../../../rule_management/model/prebuilt_rule_upgrade'; import { FieldUpgradeState } from '../../../../rule_management/model/prebuilt_rule_upgrade/field_upgrade_state'; +import { isNonUpgradeableFieldName } from '../../../../rule_management/model/prebuilt_rule_upgrade/fields'; import { useRulePreviewFlyout } from '../use_rule_preview_flyout'; import { MlJobUpgradeModal } from './modals/ml_job_upgrade_modal'; import { UpgradeConflictsModal } from './modals/upgrade_conflicts_modal'; +import * as i18n from './translations'; +import type { UpgradePrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_upgrade'; +import { useFilterPrebuiltRulesToUpgrade } from './use_filter_prebuilt_rules_to_upgrade'; import { usePrebuiltRulesUpgradeState } from './use_prebuilt_rules_upgrade_state'; import { useMlJobUpgradeModal, useUpgradeConflictsModal } from './use_upgrade_modals'; -import * as ruleDetailsI18n from '../../../../rule_management/components/rule_details/translations'; -import * as i18n from './translations'; +import { RuleTypeChangeCallout } from './rule_type_change_callout'; export interface UpgradePrebuiltRulesTableState { /** @@ -168,57 +169,45 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ handleCancel: handleConflictsCancel, } = useUpgradeConflictsModal(); - const shouldConfirmMLJobs = legacyJobsInstalled.length > 0; + const { mutateAsync: upgradeSpecificRulesRequest } = usePerformUpgradeSpecificRules(); - const { mutateAsync: upgradeSpecificRulesRequest } = usePerformUpgradeSpecificRules({ - pickVersion: isPrebuiltRulesCustomizationEnabled ? 'MERGED' : 'TARGET', - }); - - const upgradeRules = useCallback( + const upgradeRulesToResolved = useCallback( async (ruleIds: RuleSignatureId[]) => { const conflictRuleIdsSet = new Set( - isPrebuiltRulesCustomizationEnabled - ? ruleIds.filter( - (ruleId) => - rulesUpgradeState[ruleId].diff.num_fields_with_conflicts > 0 && - rulesUpgradeState[ruleId].hasUnresolvedConflicts - ) - : [] + ruleIds.filter( + (ruleId) => + rulesUpgradeState[ruleId].diff.num_fields_with_conflicts > 0 && + rulesUpgradeState[ruleId].hasUnresolvedConflicts + ) ); - const ruleUpgradeSpecifiers: RuleUpgradeSpecifier[] = ruleIds - .filter((ruleId) => !conflictRuleIdsSet.has(ruleId)) - .map((ruleId) => ({ - rule_id: ruleId, - version: - rulesUpgradeState[ruleId].diff.fields.version?.target_version ?? - rulesUpgradeState[ruleId].current_rule.version, - revision: rulesUpgradeState[ruleId].revision, - fields: isPrebuiltRulesCustomizationEnabled - ? constructRuleFieldsToUpgrade(rulesUpgradeState[ruleId]) - : undefined, - })); - - setLoadingRules((prev) => [...prev, ...ruleUpgradeSpecifiers.map((x) => x.rule_id)]); + const upgradingRuleIds = ruleIds.filter((ruleId) => !conflictRuleIdsSet.has(ruleId)); + const ruleUpgradeSpecifiers: RuleUpgradeSpecifier[] = upgradingRuleIds.map((ruleId) => ({ + rule_id: ruleId, + version: rulesUpgradeState[ruleId].target_rule.version, + revision: rulesUpgradeState[ruleId].revision, + fields: constructRuleFieldsToUpgrade(rulesUpgradeState[ruleId]), + })); + + setLoadingRules((prev) => [...prev, ...upgradingRuleIds]); try { // Handle MLJobs modal - if (shouldConfirmMLJobs && !(await confirmLegacyMLJobs())) { + if (!(await confirmLegacyMLJobs())) { return; } - if ( - isPrebuiltRulesCustomizationEnabled && - conflictRuleIdsSet.size > 0 && - !(await confirmConflictsUpgrade()) - ) { + if (conflictRuleIdsSet.size > 0 && !(await confirmConflictsUpgrade())) { return; } - await upgradeSpecificRulesRequest(ruleUpgradeSpecifiers); + await upgradeSpecificRulesRequest({ + pickVersion: 'MERGED', + rules: ruleUpgradeSpecifiers, + }); } catch (err) { addError(err, { title: i18n.UPDATE_ERROR }); } finally { - const upgradedRuleIdsSet = new Set(ruleUpgradeSpecifiers.map((x) => x.rule_id)); + const upgradedRuleIdsSet = new Set(upgradingRuleIds); setLoadingRules((prev) => prev.filter((id) => !upgradedRuleIdsSet.has(id))); } @@ -226,34 +215,94 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ [ confirmLegacyMLJobs, confirmConflictsUpgrade, - shouldConfirmMLJobs, rulesUpgradeState, upgradeSpecificRulesRequest, - isPrebuiltRulesCustomizationEnabled, addError, ] ); - const ruleActionsFactory = useCallback( - (rule: RuleResponse, closeRulePreview: () => void) => ( - <EuiButton - disabled={ - loadingRules.includes(rule.rule_id) || - isRefetching || - isUpgradingSecurityPackages || - rulesUpgradeState[rule.rule_id]?.hasUnresolvedConflicts + const upgradeRulesToTarget = useCallback( + async (ruleIds: RuleSignatureId[]) => { + const ruleUpgradeSpecifiers: RuleUpgradeSpecifier[] = ruleIds.map((ruleId) => ({ + rule_id: ruleId, + version: rulesUpgradeState[ruleId].target_rule.version, + revision: rulesUpgradeState[ruleId].revision, + })); + + setLoadingRules((prev) => [...prev, ...ruleIds]); + + try { + // Handle MLJobs modal + if (!(await confirmLegacyMLJobs())) { + return; } - onClick={() => { - upgradeRules([rule.rule_id]); - closeRulePreview(); - }} - fill - data-test-subj="updatePrebuiltRuleFromFlyoutButton" - > - {i18n.UPDATE_BUTTON_LABEL} - </EuiButton> - ), - [rulesUpgradeState, loadingRules, isRefetching, isUpgradingSecurityPackages, upgradeRules] + + await upgradeSpecificRulesRequest({ + pickVersion: 'TARGET', + rules: ruleUpgradeSpecifiers, + }); + } catch (err) { + addError(err, { title: i18n.UPDATE_ERROR }); + } finally { + const upgradedRuleIdsSet = new Set(ruleIds); + + setLoadingRules((prev) => prev.filter((id) => !upgradedRuleIdsSet.has(id))); + } + }, + [confirmLegacyMLJobs, rulesUpgradeState, upgradeSpecificRulesRequest, addError] + ); + + const upgradeRules = useCallback( + async (ruleIds: RuleSignatureId[]) => { + if (isPrebuiltRulesCustomizationEnabled) { + await upgradeRulesToResolved(ruleIds); + } else { + await upgradeRulesToTarget(ruleIds); + } + }, + [isPrebuiltRulesCustomizationEnabled, upgradeRulesToResolved, upgradeRulesToTarget] + ); + + const ruleActionsFactory = useCallback( + (rule: RuleResponse, closeRulePreview: () => void) => { + const ruleUpgradeState = rulesUpgradeState[rule.rule_id]; + if (!ruleUpgradeState) { + return null; + } + + const hasRuleTypeChange = ruleUpgradeState.diff.fields.type?.has_update ?? false; + return ( + <EuiButton + disabled={ + loadingRules.includes(rule.rule_id) || + isRefetching || + isUpgradingSecurityPackages || + (ruleUpgradeState.hasUnresolvedConflicts && !hasRuleTypeChange) + } + onClick={() => { + if (hasRuleTypeChange) { + // If there is a rule type change, we can't resolve conflicts, only accept the target rule + upgradeRulesToTarget([rule.rule_id]); + } else { + upgradeRulesToResolved([rule.rule_id]); + } + closeRulePreview(); + }} + fill + data-test-subj="updatePrebuiltRuleFromFlyoutButton" + > + {i18n.UPDATE_BUTTON_LABEL} + </EuiButton> + ); + }, + [ + rulesUpgradeState, + loadingRules, + isRefetching, + isUpgradingSecurityPackages, + upgradeRulesToTarget, + upgradeRulesToResolved, + ] ); const extraTabsFactory = useCallback( (rule: RuleResponse) => { @@ -263,7 +312,39 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ return []; } - const jsonViewUpdates = { + const hasRuleTypeChange = ruleUpgradeState.diff.fields.type?.has_update ?? false; + const shouldShowRuleTypeChangeCallout = + hasRuleTypeChange && isPrebuiltRulesCustomizationEnabled; + let updateTabContent = ( + <PerFieldRuleDiffTab + header={shouldShowRuleTypeChangeCallout ? <RuleTypeChangeCallout /> : null} + ruleDiff={ruleUpgradeState.diff} + /> + ); + + // Show the resolver tab only if rule customization is enabled and there + // is no rule type change. In case of rule type change users can't resolve + // conflicts, only accept the target rule. + if (isPrebuiltRulesCustomizationEnabled && !hasRuleTypeChange) { + updateTabContent = ( + <RuleUpgradeConflictsResolverTab + ruleUpgradeState={ruleUpgradeState} + setRuleFieldResolvedValue={setRuleFieldResolvedValue} + /> + ); + } + + const updatesTab = { + id: 'updates', + name: ( + <EuiToolTip position="top" content={i18n.UPDATE_FLYOUT_PER_FIELD_TOOLTIP_DESCRIPTION}> + <>{ruleDetailsI18n.UPDATES_TAB_LABEL}</> + </EuiToolTip> + ), + content: <TabContentPadding>{updateTabContent}</TabContentPadding>, + }; + + const jsonViewTab = { id: 'jsonViewUpdates', name: ( <EuiToolTip position="top" content={i18n.UPDATE_FLYOUT_JSON_VIEW_TOOLTIP_DESCRIPTION}> @@ -280,44 +361,7 @@ export const UpgradePrebuiltRulesTableContextProvider = ({ ), }; - if (isPrebuiltRulesCustomizationEnabled) { - return [ - { - id: 'updates', - name: ( - <EuiToolTip position="top" content={i18n.UPDATE_FLYOUT_PER_FIELD_TOOLTIP_DESCRIPTION}> - <>{ruleDetailsI18n.UPDATES_TAB_LABEL}</> - </EuiToolTip> - ), - content: ( - <TabContentPadding> - <RuleUpgradeConflictsResolverTab - ruleUpgradeState={ruleUpgradeState} - setRuleFieldResolvedValue={setRuleFieldResolvedValue} - /> - </TabContentPadding> - ), - }, - jsonViewUpdates, - ]; - } - - return [ - { - id: 'updates', - name: ( - <EuiToolTip position="top" content={i18n.UPDATE_FLYOUT_PER_FIELD_TOOLTIP_DESCRIPTION}> - <>{ruleDetailsI18n.UPDATES_TAB_LABEL}</> - </EuiToolTip> - ), - content: ( - <TabContentPadding> - <PerFieldRuleDiffTab ruleDiff={ruleUpgradeState.diff} /> - </TabContentPadding> - ), - }, - jsonViewUpdates, - ]; + return [updatesTab, jsonViewTab]; }, [rulesUpgradeState, setRuleFieldResolvedValue, isPrebuiltRulesCustomizationEnabled] ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx index 3e20d914dabc..256ccf47c194 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/upgrade_prebuilt_rules_table/use_upgrade_modals.tsx @@ -5,6 +5,7 @@ * 2.0. */ +import { useCallback } from 'react'; import { useInstalledSecurityJobs } from '../../../../../common/components/ml/hooks/use_installed_security_jobs'; import { useBoolState } from '../../../../../common/hooks/use_bool_state'; import { affectedJobIds } from '../../../../../../common/machine_learning/affected_job_ids'; @@ -19,10 +20,17 @@ export const useMlJobUpgradeModal = () => { onFinish: hideModal, }); + const handleLegacyMLJobsConfirm = useCallback(async () => { + if (legacyJobsInstalled.length > 0) { + return confirmLegacyMLJobs(); + } + return true; + }, [confirmLegacyMLJobs, legacyJobsInstalled]); + return { isVisible, legacyJobsInstalled, - confirmLegacyMLJobs, + confirmLegacyMLJobs: handleLegacyMLJobsConfirm, handleConfirm, handleCancel, loadingJobs, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx index f0480cbef8f3..ec8a06c621f0 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_events_table/use_execution_events.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { cleanup, waitFor, renderHook } from '@testing-library/react'; import { LogLevelEnum, @@ -39,9 +39,9 @@ describe('useExecutionEvents', () => { it('calls the API via fetchRuleExecutionEvents', async () => { const fetchRuleExecutionEvents = jest.spyOn(api, 'fetchRuleExecutionEvents'); - const { waitForNextUpdate } = render(); + render(); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(fetchRuleExecutionEvents).toHaveBeenCalledTimes(1); expect(fetchRuleExecutionEvents).toHaveBeenLastCalledWith( @@ -50,7 +50,7 @@ describe('useExecutionEvents', () => { }); it('fetches data from the API', async () => { - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -58,28 +58,28 @@ describe('useExecutionEvents', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents returns - await waitForNextUpdate(); - - // It switches to a success state - expect(result.current.isLoading).toEqual(false); - expect(result.current.isSuccess).toEqual(true); - expect(result.current.isError).toEqual(false); - expect(result.current.data).toEqual({ - events: [ - { - timestamp: '2021-12-29T10:42:59.996Z', - sequence: 0, - level: LogLevelEnum.info, - type: RuleExecutionEventTypeEnum['status-change'], - execution_id: 'execution-id-1', - message: 'Rule changed status to "succeeded". Rule execution completed without errors', + await waitFor(() => { + // It switches to a success state + expect(result.current.isLoading).toEqual(false); + expect(result.current.isSuccess).toEqual(true); + expect(result.current.isError).toEqual(false); + expect(result.current.data).toEqual({ + events: [ + { + timestamp: '2021-12-29T10:42:59.996Z', + sequence: 0, + level: LogLevelEnum.info, + type: RuleExecutionEventTypeEnum['status-change'], + execution_id: 'execution-id-1', + message: 'Rule changed status to "succeeded". Rule execution completed without errors', + }, + ], + pagination: { + page: 1, + per_page: 20, + total: 1, }, - ], - pagination: { - page: 1, - per_page: 20, - total: 1, - }, + }); }); }); @@ -87,7 +87,7 @@ describe('useExecutionEvents', () => { const exception = new Error('Boom!'); jest.spyOn(api, 'fetchRuleExecutionEvents').mockRejectedValue(exception); - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -95,18 +95,18 @@ describe('useExecutionEvents', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents throws - await waitForNextUpdate(); - - // It switches to an error state - expect(result.current.isLoading).toEqual(false); - expect(result.current.isSuccess).toEqual(false); - expect(result.current.isError).toEqual(true); - expect(result.current.error).toEqual(exception); - - // And shows a toast with the caught exception - expect(useToasts().addError).toHaveBeenCalledTimes(1); - expect(useToasts().addError).toHaveBeenCalledWith(exception, { - title: 'Failed to fetch rule execution events', + await waitFor(() => { + // It switches to an error state + expect(result.current.isLoading).toEqual(false); + expect(result.current.isSuccess).toEqual(false); + expect(result.current.isError).toEqual(true); + expect(result.current.error).toEqual(exception); + + // And shows a toast with the caught exception + expect(useToasts().addError).toHaveBeenCalledTimes(1); + expect(useToasts().addError).toHaveBeenCalledWith(exception, { + title: 'Failed to fetch rule execution events', + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx index d5d2e2409e2a..7e5da70ad0b3 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_monitoring/components/execution_results_table/use_execution_results.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { cleanup, waitFor, renderHook } from '@testing-library/react'; import { useExecutionResults } from './use_execution_results'; import { useToasts } from '../../../../common/lib/kibana'; @@ -48,18 +48,17 @@ describe('useExecutionResults', () => { it('calls the API via fetchRuleExecutionResults', async () => { const fetchRuleExecutionResults = jest.spyOn(api, 'fetchRuleExecutionResults'); - const { waitForNextUpdate } = render(); + render(); - await waitForNextUpdate(); + await waitFor(() => expect(fetchRuleExecutionResults).toHaveBeenCalledTimes(1)); - expect(fetchRuleExecutionResults).toHaveBeenCalledTimes(1); expect(fetchRuleExecutionResults).toHaveBeenLastCalledWith( expect.objectContaining({ ruleId: SOME_RULE_ID }) ); }); it('fetches data from the API', async () => { - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -67,10 +66,9 @@ describe('useExecutionResults', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents returns - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toEqual(false)); // It switches to a success state - expect(result.current.isLoading).toEqual(false); expect(result.current.isSuccess).toEqual(true); expect(result.current.isError).toEqual(false); expect(result.current.data).toEqual({ @@ -107,7 +105,7 @@ describe('useExecutionResults', () => { const exception = new Error('Boom!'); jest.spyOn(api, 'fetchRuleExecutionResults').mockRejectedValue(exception); - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -115,10 +113,9 @@ describe('useExecutionResults', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents throws - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toEqual(false)); // It switches to an error state - expect(result.current.isLoading).toEqual(false); expect(result.current.isSuccess).toEqual(false); expect(result.current.isError).toEqual(true); expect(result.current.error).toEqual(exception); diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx index 0ca0e99bb7fd..7a39c6ea0439 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/index.tsx @@ -12,7 +12,7 @@ import type { FC } from 'react'; import React, { useRef, useEffect, useState, useCallback, useMemo } from 'react'; import type { AlertsTableStateProps } from '@kbn/triggers-actions-ui-plugin/public/application/sections/alerts_table/alerts_table_state'; import type { Alert } from '@kbn/triggers-actions-ui-plugin/public/types'; -import { ALERT_BUILDING_BLOCK_TYPE } from '@kbn/rule-data-utils'; +import { ALERT_BUILDING_BLOCK_TYPE, AlertConsumers } from '@kbn/rule-data-utils'; import styled from 'styled-components'; import { useDispatch } from 'react-redux'; import { getEsQueryConfig } from '@kbn/data-plugin/public'; @@ -22,6 +22,7 @@ import { tableDefaults, TableId, } from '@kbn/securitysolution-data-table'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; import { useGlobalTime } from '../../../common/containers/use_global_time'; import { useLicense } from '../../../common/hooks/use_license'; @@ -55,7 +56,7 @@ const { updateIsLoading, updateTotalCount } = dataTableActions; const DEFAULT_DATA_GRID_HEIGHT = 600; -const ALERT_TABLE_FEATURE_ID: AlertsTableStateProps['featureIds'] = ['siem']; +const ALERT_TABLE_CONSUMERS: AlertsTableStateProps['consumers'] = [AlertConsumers.SIEM]; // Highlight rows with building block alerts const shouldHighlightRow = (alert: Alert) => !!alert[ALERT_BUILDING_BLOCK_TYPE]; @@ -283,7 +284,8 @@ export const AlertsTableComponent: FC<DetectionEngineAlertTableProps> = ({ configurationId: configId, // stores separate configuration based on the view of the table id: `detection-engine-alert-table-${configId}-${tableView}`, - featureIds: ALERT_TABLE_FEATURE_ID, + ruleTypeIds: SECURITY_SOLUTION_RULE_TYPE_IDS, + consumers: ALERT_TABLE_CONSUMERS, query: finalBoolQuery, gridStyle, shouldHighlightRow, diff --git a/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx b/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx index 6c60aec51382..5a01ea1f939d 100644 --- a/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/detection_engine_filters/detection_engine_filters.tsx @@ -7,12 +7,12 @@ import React, { useCallback, useMemo } from 'react'; import type { FilterControlConfig } from '@kbn/alerts-ui-shared'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { createKbnUrlStateStorage, Storage } from '@kbn/kibana-utils-plugin/public'; import { ControlGroupRenderer } from '@kbn/controls-plugin/public'; import type { AlertFilterControlsProps } from '@kbn/alerts-ui-shared/src/alert_filter_controls'; import { AlertFilterControls } from '@kbn/alerts-ui-shared/src/alert_filter_controls'; import { useHistory } from 'react-router-dom'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; import type { DataViewSpec } from '@kbn/data-plugin/common'; import { useKibana } from '../../../common/lib/kibana'; import { DEFAULT_DETECTION_PAGE_FILTERS } from '../../../../common/constants'; @@ -78,7 +78,7 @@ export const DetectionEngineFilters = ({ controlsUrlState={filterControlsUrlState} setControlsUrlState={setFilterControlsUrlState} spaceId={spaceId} - featureIds={[AlertConsumers.SIEM]} + ruleTypeIds={SECURITY_SOLUTION_RULE_TYPE_IDS} chainingSystem="HIERARCHICAL" defaultControls={DEFAULT_DETECTION_PAGE_FILTERS} dataViewSpec={dataViewSpec} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx index eba2248f82a4..710cb86970a4 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/related_integrations/use_integrations.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, cleanup } from '@testing-library/react-hooks'; +import { cleanup, waitFor, renderHook } from '@testing-library/react'; import { useIntegrations } from './use_integrations'; @@ -39,11 +39,9 @@ describe('useIntegrations', () => { it('calls the API via fetchAllIntegrations', async () => { const fetchAllIntegrations = jest.spyOn(fleetIntegrationsApi, 'fetchAllIntegrations'); - const { waitForNextUpdate } = render(); + render(); - await waitForNextUpdate(); - - expect(fetchAllIntegrations).toHaveBeenCalledTimes(1); + await waitFor(() => expect(fetchAllIntegrations).toHaveBeenCalledTimes(1)); }); it('does not call the API when skip is true', async () => { @@ -55,7 +53,7 @@ describe('useIntegrations', () => { }); it('fetches data from the API', async () => { - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -63,10 +61,9 @@ describe('useIntegrations', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents returns - await waitForNextUpdate(); + await waitFor(() => expect(result.current.isLoading).toEqual(false)); // It switches to a success state - expect(result.current.isLoading).toEqual(false); expect(result.current.isSuccess).toEqual(true); expect(result.current.isError).toEqual(false); expect(result.current.data).toEqual([ @@ -105,7 +102,7 @@ describe('useIntegrations', () => { const exception = new Error('Boom!'); jest.spyOn(fleetIntegrationsApi, 'fetchAllIntegrations').mockRejectedValue(exception); - const { result, waitForNextUpdate } = render(); + const { result } = render(); // It starts from a loading state expect(result.current.isLoading).toEqual(true); @@ -113,7 +110,7 @@ describe('useIntegrations', () => { expect(result.current.isError).toEqual(false); // When fetchRuleExecutionEvents throws - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); // It switches to an error state expect(result.current.isLoading).toEqual(false); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts index 2a07746a6d67..ba939fabe1e9 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useRuleFromTimeline } from './use_rule_from_timeline'; import { useGetInitialUrlParamValue } from '../../../../common/utils/global_query_string/helpers'; @@ -117,10 +117,11 @@ describe('useRuleFromTimeline', () => { }); it('does not reset timeline sourcerer if it originally had same data view as the timeline used in the rule', async () => { - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); - expect(setRuleQuery).toHaveBeenCalled(); + await waitFor(() => { + expect(setRuleQuery).toHaveBeenCalled(); + }); }); }); @@ -147,9 +148,9 @@ describe('useRuleFromTimeline', () => { }); it('if timeline id in URL, set active timeline data view to from timeline data view', async () => { - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(setRuleQuery).toHaveBeenCalled(); expect(mockDispatch).toHaveBeenCalledTimes(2); @@ -167,9 +168,9 @@ describe('useRuleFromTimeline', () => { (useGetInitialUrlParamValue as jest.Mock) .mockReturnValueOnce(() => timelineId) .mockReturnValue(() => undefined); - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.loading).toEqual(false); expect(setRuleQuery).toHaveBeenCalledWith({ index: ['awesome-*'], @@ -235,9 +236,9 @@ describe('useRuleFromTimeline', () => { (useGetInitialUrlParamValue as jest.Mock) .mockReturnValueOnce(() => undefined) .mockReturnValue(() => timelineId); - const { result, waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); + const { result } = renderHook(() => useRuleFromTimeline(setRuleQuery)); expect(result.current.loading).toEqual(true); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(result.current.loading).toEqual(false); expect(setRuleQuery).toHaveBeenCalledWith({ index: ['awesome-*'], @@ -327,16 +328,17 @@ describe('useRuleFromTimeline', () => { }); it('resets timeline sourcerer if it originally had different data view from the timeline used in the rule', async () => { - const { waitForNextUpdate } = renderHook(() => useRuleFromTimeline(setRuleQuery)); - await waitForNextUpdate(); - expect(setRuleQuery).toHaveBeenCalled(); - expect(mockDispatch).toHaveBeenNthCalledWith(2, { - type: 'x-pack/security_solution/local/sourcerer/SET_SELECTED_DATA_VIEW', - payload: { - id: 'timeline', - selectedDataViewId: 'security-solution', - selectedPatterns: ['auditbeat-*'], - }, + renderHook(() => useRuleFromTimeline(setRuleQuery)); + await waitFor(() => { + expect(setRuleQuery).toHaveBeenCalled(); + expect(mockDispatch).toHaveBeenNthCalledWith(2, { + type: 'x-pack/security_solution/local/sourcerer/SET_SELECTED_DATA_VIEW', + payload: { + id: 'timeline', + selectedDataViewId: 'security-solution', + selectedPatterns: ['auditbeat-*'], + }, + }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx index b72c043ffa40..221c78f629ff 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_from_timeline.tsx @@ -14,7 +14,7 @@ import { convertKueryToElasticSearchQuery } from '../../../../common/lib/kuery'; import { useAppToasts } from '../../../../common/hooks/use_app_toasts'; import { useSourcererDataView } from '../../../../sourcerer/containers'; import type { TimelineModel } from '../../../..'; -import type { FieldValueQueryBar } from '../../../../detection_engine/rule_creation_ui/components/query_bar'; +import type { FieldValueQueryBar } from '../../../../detection_engine/rule_creation_ui/components/query_bar_field'; import { sourcererActions } from '../../../../sourcerer/store'; import { useQueryTimelineById } from '../../../../timelines/components/open_timeline/helpers'; import { useGetInitialUrlParamValue } from '../../../../common/utils/global_query_string/helpers'; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts index 2f0cf92737f4..3cfbf6e0fd5e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts @@ -30,7 +30,7 @@ import type { ALERT_SUPPRESSION_MISSING_FIELDS_FIELD_NAME, } from '../../../../detection_engine/rule_creation/components/alert_suppression_edit'; import type { THRESHOLD_ALERT_SUPPRESSION_ENABLED } from '../../../../detection_engine/rule_creation/components/threshold_alert_suppression_edit'; -import type { FieldValueQueryBar } from '../../../../detection_engine/rule_creation_ui/components/query_bar'; +import type { FieldValueQueryBar } from '../../../../detection_engine/rule_creation_ui/components/query_bar_field'; import type { FieldValueTimeline } from '../../../../detection_engine/rule_creation/components/pick_timeline'; import type { FieldValueThreshold } from '../../../../detection_engine/rule_creation_ui/components/threshold_input'; import type { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts index 55a461d94683..88d2fb3d6eee 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts @@ -14,6 +14,7 @@ import { ALERT_SUPPRESSION_DEFAULT_DURATION, } from '../../../../detection_engine/rule_creation/components/alert_suppression_edit'; import { THRESHOLD_ALERT_SUPPRESSION_ENABLED } from '../../../../detection_engine/rule_creation/components/threshold_alert_suppression_edit'; +import { DEFAULT_KQL_QUERY_FIELD_VALUE } from '../../../../detection_engine/rule_creation_ui/components/query_bar_field'; import { isThreatMatchRule } from '../../../../../common/detection_engine/utils'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import { DEFAULT_MAX_SIGNALS, DEFAULT_THREAT_MATCH_QUERY } from '../../../../../common/constants'; @@ -44,11 +45,7 @@ export const stepDefineDefaultValue: DefineStepRule = { machineLearningJobId: [], ruleType: 'query', threatIndex: [], - queryBar: { - query: { query: '', language: 'kuery' }, - filters: [], - saved_id: null, - }, + queryBar: DEFAULT_KQL_QUERY_FIELD_VALUE, threatQueryBar: { query: { query: DEFAULT_THREAT_MATCH_QUERY, language: 'kuery' }, filters: [], @@ -125,24 +122,3 @@ export const getStepScheduleDefaultValue = (ruleType: Type | undefined): Schedul from: isThreatMatchRule(ruleType) ? THREAT_MATCH_FROM : DEFAULT_FROM, }; }; - -/** - * This default query will be used for threat query/indicator matches - * as the default when the user swaps to using it by changing their - * rule type from any rule type to the "threatMatchRule" type. Only - * difference is that "*:*" is used instead of '' for its query. - */ -const threatQueryBarDefaultValue: DefineStepRule['queryBar'] = { - ...stepDefineDefaultValue.queryBar, - query: { ...stepDefineDefaultValue.queryBar.query, query: '*:*' }, -}; - -export const defaultCustomQuery = { - forNormalRules: stepDefineDefaultValue.queryBar, - forThreatMatchRules: threatQueryBarDefaultValue, - forEsqlRules: { - query: { query: '', language: 'esql' }, - filters: [], - saved_id: null, - }, -}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts index 54f5415d24a3..0098b842748e 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/entity_store.ts @@ -5,10 +5,14 @@ * 2.0. */ import { useMemo } from 'react'; +import type { GetEntityStoreStatusResponse } from '../../../common/api/entity_analytics/entity_store/status.gen'; +import type { + InitEntityStoreRequestBody, + InitEntityStoreResponse, +} from '../../../common/api/entity_analytics/entity_store/enable.gen'; import type { DeleteEntityEngineResponse, EntityType, - GetEntityEngineResponse, InitEntityEngineResponse, ListEntityEnginesResponse, StopEntityEngineResponse, @@ -20,26 +24,37 @@ export const useEntityStoreRoutes = () => { const http = useKibana().services.http; return useMemo(() => { - const initEntityStore = async (entityType: EntityType) => { - return http.fetch<InitEntityEngineResponse>(`/api/entity_store/engines/${entityType}/init`, { + const enableEntityStore = async ( + options: InitEntityStoreRequestBody = { fieldHistoryLength: 10 } + ) => { + return http.fetch<InitEntityStoreResponse>('/api/entity_store/enable', { method: 'POST', version: API_VERSIONS.public.v1, - body: JSON.stringify({}), + body: JSON.stringify(options), }); }; - const stopEntityStore = async (entityType: EntityType) => { - return http.fetch<StopEntityEngineResponse>(`/api/entity_store/engines/${entityType}/stop`, { + const getEntityStoreStatus = async (withComponents = false) => { + return http.fetch<GetEntityStoreStatusResponse>('/api/entity_store/status', { + method: 'GET', + version: API_VERSIONS.public.v1, + query: { include_components: withComponents }, + }); + }; + + const initEntityEngine = async (entityType: EntityType) => { + return http.fetch<InitEntityEngineResponse>(`/api/entity_store/engines/${entityType}/init`, { method: 'POST', version: API_VERSIONS.public.v1, body: JSON.stringify({}), }); }; - const getEntityEngine = async (entityType: EntityType) => { - return http.fetch<GetEntityEngineResponse>(`/api/entity_store/engines/${entityType}`, { - method: 'GET', + const stopEntityEngine = async (entityType: EntityType) => { + return http.fetch<StopEntityEngineResponse>(`/api/entity_store/engines/${entityType}/stop`, { + method: 'POST', version: API_VERSIONS.public.v1, + body: JSON.stringify({}), }); }; @@ -59,9 +74,10 @@ export const useEntityStoreRoutes = () => { }; return { - initEntityStore, - stopEntityStore, - getEntityEngine, + enableEntityStore, + getEntityStoreStatus, + initEntityEngine, + stopEntityEngine, deleteEntityEngine, listEntityEngines, }; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts index a9c9dc0939b0..14ab3fc7ca15 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/api/hooks/use_risk_engine_status.ts @@ -38,7 +38,7 @@ export const useIsNewRiskScoreModuleInstalled = (): RiskScoreModuleStatus => { return { isLoading: false, installed: !!riskEngineStatus?.isNewRiskScoreModuleInstalled }; }; -interface RiskEngineStatus extends RiskEngineStatusResponse { +export interface RiskEngineStatus extends RiskEngineStatusResponse { isUpdateAvailable: boolean; isNewRiskScoreModuleInstalled: boolean; isNewRiskScoreModuleAvailable: boolean; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality/use_asset_criticality.test.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality/use_asset_criticality.test.ts index d4671a5bc628..df9e39022f1e 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality/use_asset_criticality.test.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/asset_criticality/use_asset_criticality.test.ts @@ -5,7 +5,11 @@ * 2.0. */ -import { renderMutation, renderQuery } from '../../../management/hooks/test_utils'; +import { + renderMutation, + renderQuery, + renderWrappedHook, +} from '../../../management/hooks/test_utils'; import type { Entity } from './use_asset_criticality'; import { useAssetCriticalityPrivileges, useAssetCriticalityData } from './use_asset_criticality'; @@ -69,10 +73,7 @@ describe('useAssetCriticality', () => { mockCreateAssetCriticality.mockResolvedValue({}); const entity: Entity = { name: 'test_entity_name', type: 'host' }; - const { mutation } = await renderQuery( - () => useAssetCriticalityData({ entity }), - 'isSuccess' - ); + const { mutation } = await renderWrappedHook(() => useAssetCriticalityData({ entity })); await renderMutation(async () => mutation.mutate({ @@ -91,10 +92,7 @@ describe('useAssetCriticality', () => { mockCreateAssetCriticality.mockResolvedValue({}); const entity: Entity = { name: 'test_entity_name', type: 'host' }; - const { mutation } = await renderQuery( - () => useAssetCriticalityData({ entity }), - 'isSuccess' - ); + const { mutation } = await renderWrappedHook(() => useAssetCriticalityData({ entity })); await renderMutation(async () => mutation.mutate({ diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_enablement_panel.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_enablement_panel.tsx new file mode 100644 index 000000000000..38449fa1e72f --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_enablement_panel.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 React, { useCallback, useState } from 'react'; +import { + EuiCallOut, + EuiPanel, + EuiEmptyPrompt, + EuiLoadingLogo, + EuiToolTip, + EuiButton, + EuiImage, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n-react'; +import type { UseQueryResult } from '@tanstack/react-query'; +import type { GetEntityStoreStatusResponse } from '../../../../../common/api/entity_analytics/entity_store/status.gen'; +import type { StoreStatus } from '../../../../../common/api/entity_analytics'; +import { RiskEngineStatusEnum } from '../../../../../common/api/entity_analytics'; +import { useInitRiskEngineMutation } from '../../../api/hooks/use_init_risk_engine_mutation'; +import { useEnableEntityStoreMutation } from '../hooks/use_entity_store'; +import { + ENABLEMENT_INITIALIZING_RISK_ENGINE, + ENABLEMENT_INITIALIZING_ENTITY_STORE, + ENABLE_ALL_TITLE, + ENABLEMENT_DESCRIPTION_BOTH, + ENABLE_RISK_SCORE_TITLE, + ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY, + ENABLE_ENTITY_STORE_TITLE, + ENABLEMENT_DESCRIPTION_ENTITY_STORE_ONLY, +} from '../translations'; +import type { Enablements } from './enablement_modal'; +import { EntityStoreEnablementModal } from './enablement_modal'; +import dashboardEnableImg from '../../../images/entity_store_dashboard.png'; +import type { RiskEngineStatus } from '../../../api/hooks/use_risk_engine_status'; + +interface EnableEntityStorePanelProps { + state: { + riskEngine: UseQueryResult<RiskEngineStatus>; + entityStore: UseQueryResult<GetEntityStoreStatusResponse>; + }; +} + +export const EnablementPanel: React.FC<EnableEntityStorePanelProps> = ({ state }) => { + const riskEngineStatus = state.riskEngine.data?.risk_engine_status; + const entityStoreStatus = state.entityStore.data?.status; + + const [modal, setModalState] = useState({ visible: false }); + const [riskEngineInitializing, setRiskEngineInitializing] = useState(false); + + const initRiskEngine = useInitRiskEngineMutation(); + const storeEnablement = useEnableEntityStoreMutation(); + + const enableEntityStore = useCallback( + (enable: Enablements) => () => { + if (enable.riskScore) { + const options = { + onSuccess: () => { + setRiskEngineInitializing(false); + if (enable.entityStore) { + storeEnablement.mutate(); + } + }, + }; + setRiskEngineInitializing(true); + initRiskEngine.mutate(undefined, options); + setModalState({ visible: false }); + return; + } + + if (enable.entityStore) { + storeEnablement.mutate(); + setModalState({ visible: false }); + } + }, + [storeEnablement, initRiskEngine] + ); + + if (storeEnablement.error) { + return ( + <> + <EuiCallOut + title={ + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enablement.mutation.errorTitle" + defaultMessage={'There was a problem initializing the entity store'} + /> + } + color="danger" + iconType="error" + > + <p>{storeEnablement.error.body.message}</p> + </EuiCallOut> + </> + ); + } + + if (riskEngineInitializing) { + return ( + <EuiPanel hasBorder data-test-subj="riskEngineInitializingPanel"> + <EuiEmptyPrompt + icon={<EuiLoadingLogo logo="logoElastic" size="xl" />} + title={<h2>{ENABLEMENT_INITIALIZING_RISK_ENGINE}</h2>} + /> + </EuiPanel> + ); + } + + if (entityStoreStatus === 'installing' || storeEnablement.isLoading) { + return ( + <EuiPanel hasBorder data-test-subj="entityStoreInitializingPanel"> + <EuiEmptyPrompt + icon={<EuiLoadingLogo logo="logoElastic" size="xl" />} + title={<h2>{ENABLEMENT_INITIALIZING_ENTITY_STORE}</h2>} + body={ + <p> + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.description" + defaultMessage="This can take up to 5 minutes." + /> + </p> + } + /> + </EuiPanel> + ); + } + + if ( + riskEngineStatus !== RiskEngineStatusEnum.NOT_INSTALLED && + (entityStoreStatus === 'running' || entityStoreStatus === 'stopped') + ) { + return null; + } + + const [title, body] = getEnablementTexts(entityStoreStatus, riskEngineStatus); + return ( + <> + <EuiEmptyPrompt + css={{ minWidth: '100%' }} + hasBorder + layout="horizontal" + title={<h2>{title}</h2>} + body={<p>{body}</p>} + actions={ + <EuiToolTip content={title}> + <EuiButton + color="primary" + fill + onClick={() => setModalState({ visible: true })} + data-test-subj={`entityStoreEnablementButton`} + > + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enablement.enableButton" + defaultMessage="Enable" + /> + </EuiButton> + </EuiToolTip> + } + icon={<EuiImage size="l" hasShadow src={dashboardEnableImg} alt={title} />} + data-test-subj="entityStoreEnablementPanel" + /> + + <EntityStoreEnablementModal + visible={modal.visible} + toggle={(visible) => setModalState({ visible })} + enableStore={enableEntityStore} + riskScore={{ + disabled: riskEngineStatus !== RiskEngineStatusEnum.NOT_INSTALLED, + checked: riskEngineStatus === RiskEngineStatusEnum.NOT_INSTALLED, + }} + entityStore={{ + disabled: entityStoreStatus === 'running', + checked: entityStoreStatus === 'not_installed', + }} + /> + </> + ); +}; + +const getEnablementTexts = ( + entityStoreStatus?: StoreStatus, + riskEngineStatus?: RiskEngineStatus['risk_engine_status'] +): [string, string] => { + if ( + (entityStoreStatus === 'not_installed' || entityStoreStatus === 'stopped') && + riskEngineStatus === RiskEngineStatusEnum.NOT_INSTALLED + ) { + return [ENABLE_ALL_TITLE, ENABLEMENT_DESCRIPTION_BOTH]; + } + + if (riskEngineStatus === RiskEngineStatusEnum.NOT_INSTALLED) { + return [ENABLE_RISK_SCORE_TITLE, ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY]; + } + + return [ENABLE_ENTITY_STORE_TITLE, ENABLEMENT_DESCRIPTION_ENTITY_STORE_ONLY]; +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_entity_store_panels.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_entity_store_panels.tsx new file mode 100644 index 000000000000..0870d37a6b2b --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_entity_store_panels.tsx @@ -0,0 +1,95 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { + EuiEmptyPrompt, + EuiLoadingSpinner, + EuiFlexItem, + EuiFlexGroup, + EuiPanel, + EuiCallOut, +} from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n-react'; +import { RiskEngineStatusEnum } from '../../../../../common/api/entity_analytics'; +import { RiskScoreEntity } from '../../../../../common/search_strategy'; +import { EntitiesList } from '../entities_list'; +import { useEntityStoreStatus } from '../hooks/use_entity_store'; +import { EntityAnalyticsRiskScores } from '../../entity_analytics_risk_score'; +import { useRiskEngineStatus } from '../../../api/hooks/use_risk_engine_status'; + +import { EnablementPanel } from './dashboard_enablement_panel'; + +const EntityStoreDashboardPanelsComponent = () => { + const riskEngineStatus = useRiskEngineStatus(); + const storeStatusQuery = useEntityStoreStatus({}); + + const callouts = (storeStatusQuery.data?.engines ?? []) + .filter((engine) => engine.status === 'error') + .map((engine) => { + const err = engine.error as { + message: string; + }; + return ( + <EuiCallOut + title={ + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.title" + defaultMessage={'An error occurred during entity store resource initialization'} + /> + } + color="danger" + iconType="error" + > + <p>{err?.message}</p> + </EuiCallOut> + ); + }); + + if (storeStatusQuery.status === 'loading') { + return ( + <EuiPanel hasBorder> + <EuiEmptyPrompt icon={<EuiLoadingSpinner size="xl" />} /> + </EuiPanel> + ); + } + + return ( + <EuiFlexGroup direction="column" data-test-subj="entityStorePanelsGroup"> + {storeStatusQuery.status === 'error' ? ( + callouts + ) : ( + <EnablementPanel + state={{ + riskEngine: riskEngineStatus, + entityStore: storeStatusQuery, + }} + /> + )} + + {riskEngineStatus.data?.risk_engine_status !== RiskEngineStatusEnum.NOT_INSTALLED && ( + <> + <EuiFlexItem> + <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.user} /> + </EuiFlexItem> + <EuiFlexItem> + <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.host} /> + </EuiFlexItem> + </> + )} + {storeStatusQuery.data?.status !== 'not_installed' && + storeStatusQuery.data?.status !== 'installing' && ( + <EuiFlexItem data-test-subj="entitiesListPanel"> + <EntitiesList /> + </EuiFlexItem> + )} + </EuiFlexGroup> + ); +}; + +export const EntityStoreDashboardPanels = React.memo(EntityStoreDashboardPanelsComponent); +EntityStoreDashboardPanels.displayName = 'EntityStoreDashboardPanels'; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx deleted file mode 100644 index d70eb9fe34b5..000000000000 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/dashboard_panels.tsx +++ /dev/null @@ -1,313 +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, { useState } from 'react'; -import { - EuiEmptyPrompt, - EuiToolTip, - EuiButton, - EuiLoadingSpinner, - EuiFlexItem, - EuiFlexGroup, - EuiLoadingLogo, - EuiPanel, - EuiImage, - EuiCallOut, -} from '@elastic/eui'; - -import { FormattedMessage } from '@kbn/i18n-react'; -import { RiskEngineStatusEnum } from '../../../../../common/api/entity_analytics'; -import { RiskScoreEntity } from '../../../../../common/search_strategy'; - -import { EntitiesList } from '../entities_list'; - -import { useEntityStoreEnablement } from '../hooks/use_entity_store'; -import { EntityStoreEnablementModal, type Enablements } from './enablement_modal'; - -import { EntityAnalyticsRiskScores } from '../../entity_analytics_risk_score'; -import { useInitRiskEngineMutation } from '../../../api/hooks/use_init_risk_engine_mutation'; -import { useEntityEngineStatus } from '../hooks/use_entity_engine_status'; - -import dashboardEnableImg from '../../../images/entity_store_dashboard.png'; -import { - ENABLEMENT_DESCRIPTION_BOTH, - ENABLEMENT_DESCRIPTION_ENTITY_STORE_ONLY, - ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY, - ENABLEMENT_INITIALIZING_ENTITY_STORE, - ENABLEMENT_INITIALIZING_RISK_ENGINE, - ENABLE_ALL_TITLE, - ENABLE_ENTITY_STORE_TITLE, - ENABLE_RISK_SCORE_TITLE, -} from '../translations'; -import { useRiskEngineStatus } from '../../../api/hooks/use_risk_engine_status'; - -const EntityStoreDashboardPanelsComponent = () => { - const [modal, setModalState] = useState({ visible: false }); - const [riskEngineInitializing, setRiskEngineInitializing] = useState(false); - - const entityStore = useEntityEngineStatus(); - const riskEngineStatus = useRiskEngineStatus(); - - const { enable: enableStore, query } = useEntityStoreEnablement(); - - const { mutate: initRiskEngine } = useInitRiskEngineMutation(); - - const callouts = entityStore.errors.map((err) => ( - <EuiCallOut - title={ - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.title" - defaultMessage={'An error occurred during entity store resource initialization'} - /> - } - color="danger" - iconType="error" - > - <p>{err?.message}</p> - </EuiCallOut> - )); - - const enableEntityStore = (enable: Enablements) => () => { - setModalState({ visible: false }); - if (enable.riskScore) { - const options = { - onSuccess: () => { - setRiskEngineInitializing(false); - if (enable.entityStore) { - enableStore(); - } - }, - }; - setRiskEngineInitializing(true); - initRiskEngine(undefined, options); - return; - } - - if (enable.entityStore) { - enableStore(); - } - }; - - if (query.error) { - return ( - <> - <EuiCallOut - title={ - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStore.enablement.errors.queryErrorTitle" - defaultMessage={'There was a problem initializing the entity store'} - /> - } - color="danger" - iconType="error" - > - <p>{(query.error as { body: { message: string } }).body.message}</p> - </EuiCallOut> - {callouts} - </> - ); - } - - if (entityStore.status === 'loading') { - return ( - <EuiPanel hasBorder> - <EuiEmptyPrompt - icon={<EuiLoadingSpinner size="xl" />} - title={<h2>{ENABLEMENT_INITIALIZING_ENTITY_STORE}</h2>} - /> - </EuiPanel> - ); - } - - if (entityStore.status === 'installing') { - return ( - <EuiPanel hasBorder> - <EuiEmptyPrompt - icon={<EuiLoadingLogo logo="logoElastic" size="xl" />} - title={<h2>{ENABLEMENT_INITIALIZING_ENTITY_STORE}</h2>} - body={ - <p> - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStore.enablement.initializing.description" - defaultMessage="This can take up to 5 minutes." - /> - </p> - } - /> - </EuiPanel> - ); - } - - // TODO Rename variable because the Risk score could be installed but disabled - const isRiskScoreAvailable = - riskEngineStatus.data && - riskEngineStatus.data.risk_engine_status !== RiskEngineStatusEnum.NOT_INSTALLED; - - return ( - <EuiFlexGroup direction="column" data-test-subj="entityStorePanelsGroup"> - {entityStore.status === 'error' && isRiskScoreAvailable && ( - <> - {callouts} - <EuiFlexItem> - <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.user} /> - </EuiFlexItem> - <EuiFlexItem> - <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.host} /> - </EuiFlexItem> - </> - )} - {entityStore.status === 'error' && !isRiskScoreAvailable && ( - <> - {callouts} - <EuiFlexItem> - <EnableEntityStore - onEnable={() => setModalState({ visible: true })} - loadingRiskEngine={riskEngineInitializing} - enablements="riskScore" - /> - </EuiFlexItem> - </> - )} - {entityStore.status === 'enabled' && isRiskScoreAvailable && ( - <> - <EuiFlexItem> - <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.user} /> - </EuiFlexItem> - <EuiFlexItem> - <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.host} /> - </EuiFlexItem> - <EuiFlexItem> - <EntitiesList /> - </EuiFlexItem> - </> - )} - {entityStore.status === 'enabled' && !isRiskScoreAvailable && ( - <> - <EuiFlexItem> - <EnableEntityStore - onEnable={() => setModalState({ visible: true })} - loadingRiskEngine={riskEngineInitializing} - enablements="riskScore" - /> - </EuiFlexItem> - - <EuiFlexItem> - <EntitiesList /> - </EuiFlexItem> - </> - )} - - {(entityStore.status === 'not_installed' || entityStore.status === 'stopped') && - !isRiskScoreAvailable && ( - // TODO: Move modal inside EnableEntityStore component, eliminating the onEnable prop in favour of forwarding the riskScoreEnabled status - <EnableEntityStore - enablements="both" - onEnable={() => setModalState({ visible: true })} - loadingRiskEngine={riskEngineInitializing} - /> - )} - - {(entityStore.status === 'not_installed' || entityStore.status === 'stopped') && - isRiskScoreAvailable && ( - <> - <EuiFlexItem> - <EnableEntityStore - enablements="store" - onEnable={() => - setModalState({ - visible: true, - }) - } - /> - </EuiFlexItem> - <EuiFlexItem> - <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.user} /> - </EuiFlexItem> - <EuiFlexItem> - <EntityAnalyticsRiskScores riskEntity={RiskScoreEntity.host} /> - </EuiFlexItem> - </> - )} - - <EntityStoreEnablementModal - visible={modal.visible} - toggle={(visible) => setModalState({ visible })} - enableStore={enableEntityStore} - riskScore={{ disabled: isRiskScoreAvailable, checked: !isRiskScoreAvailable }} - entityStore={{ - disabled: entityStore.status === 'enabled', - checked: entityStore.status !== 'enabled', - }} - /> - </EuiFlexGroup> - ); -}; - -interface EnableEntityStoreProps { - onEnable: () => void; - enablements: 'store' | 'riskScore' | 'both'; - loadingRiskEngine?: boolean; -} - -export const EnableEntityStore: React.FC<EnableEntityStoreProps> = ({ - onEnable, - enablements, - loadingRiskEngine, -}) => { - const title = - enablements === 'store' - ? ENABLE_ENTITY_STORE_TITLE - : enablements === 'riskScore' - ? ENABLE_RISK_SCORE_TITLE - : ENABLE_ALL_TITLE; - - const body = - enablements === 'store' - ? ENABLEMENT_DESCRIPTION_ENTITY_STORE_ONLY - : enablements === 'riskScore' - ? ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY - : ENABLEMENT_DESCRIPTION_BOTH; - - if (loadingRiskEngine) { - return ( - <EuiPanel hasBorder> - <EuiEmptyPrompt - icon={<EuiLoadingLogo logo="logoElastic" size="xl" />} - title={<h2>{ENABLEMENT_INITIALIZING_RISK_ENGINE}</h2>} - /> - </EuiPanel> - ); - } - return ( - <EuiEmptyPrompt - css={{ minWidth: '100%' }} - hasBorder - layout="horizontal" - className="eui-fullWidth" - title={<h2>{title}</h2>} - body={<p>{body}</p>} - actions={ - <EuiToolTip content={title}> - <EuiButton - color="primary" - fill - onClick={onEnable} - data-test-subj={`enable_entity_store_btn`} - > - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStore.enablement.enableButton" - defaultMessage="Enable" - /> - </EuiButton> - </EuiToolTip> - } - icon={<EuiImage size="l" hasShadow src={dashboardEnableImg} alt={title} />} - /> - ); -}; - -export const EntityStoreDashboardPanels = React.memo(EntityStoreDashboardPanelsComponent); -EntityStoreDashboardPanels.displayName = 'EntityStoreDashboardPanels'; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.test.tsx index cccccb175ff1..c16eb7e557a4 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.test.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { fireEvent, render, screen } from '@testing-library/react'; import { EntityStoreEnablementModal } from './enablement_modal'; import { TestProviders } from '../../../../common/mock'; @@ -25,6 +26,11 @@ jest.mock('../../../hooks/use_missing_risk_engine_privileges', () => ({ useMissingRiskEnginePrivileges: () => mockUseMissingRiskEnginePrivileges(), })); +const mockUseContractComponents = jest.fn(() => ({})); +jest.mock('../../../../common/hooks/use_contract_component', () => ({ + useContractComponents: () => mockUseContractComponents(), +})); + const defaultProps = { visible: true, toggle: mockToggle, @@ -77,8 +83,10 @@ const missingRiskEnginePrivileges: RiskEngineMissingPrivilegesResponse = { }, }; -const renderComponent = (props = defaultProps) => { - return render(<EntityStoreEnablementModal {...props} />, { wrapper: TestProviders }); +const renderComponent = async (props = defaultProps) => { + await act(async () => { + return render(<EntityStoreEnablementModal {...props} />, { wrapper: TestProviders }); + }); }; describe('EntityStoreEnablementModal', () => { @@ -172,5 +180,16 @@ describe('EntityStoreEnablementModal', () => { renderComponent(); expect(screen.getByTestId('callout-missing-risk-engine-privileges')).toBeInTheDocument(); }); + + it('should render additional charges message when available', async () => { + const EnablementModalCalloutMock = () => <span data-test-subj="enablement-modal-test" />; + mockUseContractComponents.mockReturnValue({ + EnablementModalCallout: EnablementModalCalloutMock, + }); + + await renderComponent(); + + expect(screen.queryByTestId('enablement-modal-test')).toBeInTheDocument(); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx index 4252f71ec4ba..e3d01ec82907 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/enablement_modal.tsx @@ -26,6 +26,7 @@ import { import { css } from '@emotion/react'; import React, { useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useContractComponents } from '../../../../common/hooks/use_contract_component'; import { TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_TOOLTIP } from '../../../../common/translations'; import { ENABLEMENT_DESCRIPTION_RISK_ENGINE_ONLY, @@ -72,6 +73,7 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp useEntityEnginePrivileges(); const riskEnginePrivileges = useMissingRiskEnginePrivileges(); const enablementOptions = enablements.riskScore || enablements.entityStore; + const { EnablementModalCallout } = useContractComponents(); if (!visible) { return null; @@ -88,7 +90,7 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp </EuiCallOut> ); return ( - <EuiModal onClose={() => toggle(false)}> + <EuiModal onClose={() => toggle(false)} data-test-subj="entityStoreEnablementModal"> <EuiModalHeader> <EuiModalHeaderTitle> <FormattedMessage @@ -100,6 +102,7 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp <EuiModalBody> <EuiFlexGroup direction="column"> + <EuiFlexItem>{EnablementModalCallout && <EnablementModalCallout />}</EuiFlexItem> <EuiFlexItem> <EuiSwitch label={ @@ -114,6 +117,7 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp (!riskEnginePrivileges.isLoading && !riskEnginePrivileges?.hasAllRequiredPrivileges) } onChange={() => setEnablements((prev) => ({ ...prev, riskScore: !prev.riskScore }))} + data-test-subj="enablementRiskScoreSwitch" /> </EuiFlexItem> {!riskEnginePrivileges.isLoading && !riskEnginePrivileges.hasAllRequiredPrivileges && ( @@ -142,6 +146,7 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp onChange={() => setEnablements((prev) => ({ ...prev, entityStore: !prev.entityStore })) } + data-test-subj="enablementEntityStoreSwitch" /> <EuiToolTip content={TECHNICAL_PREVIEW_TOOLTIP}> <EuiBetaBadge label={TECHNICAL_PREVIEW} /> @@ -170,6 +175,7 @@ export const EntityStoreEnablementModal: React.FC<EntityStoreEnablementModalProp fill isDisabled={!enablementOptions} aria-disabled={!enablementOptions} + data-test-subj="entityStoreEnablementModalButton" > <FormattedMessage id="xpack.securitySolution.entityAnalytics.enablements.modal.enable" diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/components/engine_components_status.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/components/engine_components_status.test.tsx new file mode 100644 index 000000000000..e97c9f961bb5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/components/engine_components_status.test.tsx @@ -0,0 +1,118 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { EngineComponentsStatusTable } from './engine_components_status'; +import { + EngineComponentResourceEnum, + type EngineComponentStatus, +} from '../../../../../../../common/api/entity_analytics'; +import { TestProviders } from '../../../../../../common/mock'; + +const uninstalledWithErrorsComponent = { + id: 'entity_engine_id', + installed: false, + resource: EngineComponentResourceEnum.entity_engine, + errors: [{ title: 'Error 1', message: 'Error message 1' }], +}; + +const installedComponent = { + id: 'index_id', + resource: EngineComponentResourceEnum.index, + errors: [], + installed: true, +}; + +const mockComponents: EngineComponentStatus[] = [ + uninstalledWithErrorsComponent, + installedComponent, +]; + +const mockGetUrlForApp = jest.fn(); + +jest.mock('../../../../../../common/lib/kibana', () => { + return { + useKibana: jest.fn().mockReturnValue({ + services: { + application: { + getUrlForApp: () => mockGetUrlForApp(), + navigateToApp: jest.fn(), + }, + }, + }), + }; +}); + +describe('EngineComponentsStatusTable', () => { + it('renders the table with components', () => { + render(<EngineComponentsStatusTable components={mockComponents} />, { wrapper: TestProviders }); + expect(screen.getByTestId('engine-components-status-table')).toBeInTheDocument(); + }); + + it('expands and collapses rows correctly', () => { + render(<EngineComponentsStatusTable components={mockComponents} />, { wrapper: TestProviders }); + + const toggleButton = screen.getByLabelText('Expand'); + fireEvent.click(toggleButton); + + expect(screen.getByText('Error 1')).toBeInTheDocument(); + expect(screen.getByText('Error message 1')).toBeInTheDocument(); + + fireEvent.click(toggleButton); + + expect(screen.queryByText('Error 1')).not.toBeInTheDocument(); + expect(screen.queryByText('Error message 1')).not.toBeInTheDocument(); + }); + + describe('columns', () => { + it('renders the correct resource text', () => { + render(<EngineComponentsStatusTable components={[installedComponent]} />, { + wrapper: TestProviders, + }); + expect(screen.getByText('Index')).toBeInTheDocument(); + }); + + it('renders checkmark on installation column when installed', () => { + render(<EngineComponentsStatusTable components={[installedComponent]} />, { + wrapper: TestProviders, + }); + + const icon = screen.getByTestId('installation-status'); + + expect(icon).toHaveAttribute('data-euiicon-type', 'check'); + }); + + it('renders cross on installation column when installed', () => { + render(<EngineComponentsStatusTable components={[uninstalledWithErrorsComponent]} />, { + wrapper: TestProviders, + }); + + const icon = screen.getByTestId('installation-status'); + + expect(icon).toHaveAttribute('data-euiicon-type', 'cross'); + }); + + it('renders the correct health status', () => { + render(<EngineComponentsStatusTable components={[installedComponent]} />, { + wrapper: TestProviders, + }); + + expect(screen.queryByRole('img', { name: /health/i })).not.toBeInTheDocument(); + }); + + it('renders the correct identifier link', () => { + mockGetUrlForApp.mockReturnValue('mockedUrl'); + + render(<EngineComponentsStatusTable components={[installedComponent]} />, { + wrapper: TestProviders, + }); + const link = screen.getByRole('link'); + expect(link).toHaveAttribute('href', 'mockedUrl'); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/components/engine_components_status.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/components/engine_components_status.tsx new file mode 100644 index 000000000000..eb789035d566 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/components/engine_components_status.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { ReactNode } from 'react'; +import React, { useState, useMemo, useCallback, Fragment } from 'react'; +import { EuiSpacer, EuiHealth, EuiCodeBlock } from '@elastic/eui'; +import { BasicTable } from '../../../../../../common/components/ml/tables/basic_table'; +import { useColumns } from '../hooks/use_columns'; +import type { EngineComponentStatus } from '../../../../../../../common/api/entity_analytics'; + +type ExpandedRowMap = Record<string, ReactNode>; + +const componentToId = ({ id, resource }: EngineComponentStatus) => `${resource}-${id}`; + +export const EngineComponentsStatusTable = ({ + components, +}: { + components: EngineComponentStatus[]; +}) => { + const [expandedItems, setExpandedItems] = useState<EngineComponentStatus[]>([]); + + const itemIdToExpandedRowMap: ExpandedRowMap = useMemo(() => { + return expandedItems.reduce<ExpandedRowMap>((acc, componentStatus) => { + if (componentStatus.errors && componentStatus.errors.length > 0) { + acc[componentToId(componentStatus)] = ( + <TransformExtendedData errors={componentStatus.errors} /> + ); + } + return acc; + }, {}); + }, [expandedItems]); + + const onToggle = useCallback( + (component: EngineComponentStatus) => { + const isItemExpanded = expandedItems.includes(component); + + if (isItemExpanded) { + setExpandedItems(expandedItems.filter((item) => component !== item)); + } else { + setExpandedItems([...expandedItems, component]); + } + }, + [expandedItems] + ); + + const columns = useColumns(onToggle, expandedItems); + + return ( + <BasicTable + data-test-subj="engine-components-status-table" + columns={columns} + itemId={componentToId} + itemIdToExpandedRowMap={itemIdToExpandedRowMap} + items={components} + /> + ); +}; + +const TransformExtendedData = ({ errors }: { errors: EngineComponentStatus['errors'] }) => { + return ( + <> + {errors?.map(({ title, message }) => ( + <Fragment key={title}> + <EuiSpacer size="m" /> + <EuiHealth color="danger">{title}</EuiHealth> + <EuiSpacer size="s" /> + <EuiCodeBlock>{message}</EuiCodeBlock> + </Fragment> + ))} + </> + ); +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/hooks/use_columns.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/hooks/use_columns.tsx new file mode 100644 index 000000000000..3156c768bf4f --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/hooks/use_columns.tsx @@ -0,0 +1,184 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IconColor } from '@elastic/eui'; +import { + EuiLink, + type EuiBasicTableColumn, + EuiHealth, + EuiScreenReaderOnly, + EuiButtonIcon, + EuiIcon, +} from '@elastic/eui'; +import React, { useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { + EngineComponentResourceEnum, + type EngineComponentResource, +} from '../../../../../../../common/api/entity_analytics'; +import type { EngineComponentStatus } from '../../../../../../../common/api/entity_analytics'; +import { useKibana } from '../../../../../../common/lib/kibana'; + +type TableColumn = EuiBasicTableColumn<EngineComponentStatus>; + +export const HEALTH_COLOR: Record<Required<EngineComponentStatus>['health'], IconColor> = { + green: 'success', + unknown: 'subdued', + yellow: 'warning', + red: 'danger', +} as const; + +const RESOURCE_TO_TEXT: Record<EngineComponentResource, string> = { + ingest_pipeline: 'Ingest Pipeline', + enrich_policy: 'Enrich Policy', + index: 'Index', + component_template: 'Component Template', + task: 'Task', + transform: 'Transform', + entity_definition: 'Entity Definition', + entity_engine: 'Engine', + index_template: 'Index Template', +}; + +export const useColumns = ( + onToggleExpandedItem: (item: EngineComponentStatus) => void, + expandedItems: EngineComponentStatus[] +): TableColumn[] => { + const { getUrlForApp } = useKibana().services.application; + + return useMemo( + () => [ + { + field: 'resource', + name: ( + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.resourceColumnTitle" + defaultMessage="Resource" + /> + ), + width: '20%', + render: (resource: EngineComponentStatus['resource']) => RESOURCE_TO_TEXT[resource], + }, + { + field: 'id', + name: ( + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.idColumnTitle" + defaultMessage="Identifier" + /> + ), + render: (id: EngineComponentStatus['id'], { resource, installed }) => { + const path = getResourcePath(id, resource); + + if (!installed || !path) { + return id; + } + + return ( + <EuiLink + target="_blank" + href={getUrlForApp('management', { + path, + })} + > + {id} + </EuiLink> + ); + }, + }, + { + field: 'installed', + name: ( + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.installedColumnTitle" + defaultMessage="Installed" + /> + ), + width: '10%', + align: 'center', + render: (value: boolean) => + value ? ( + <EuiIcon data-test-subj="installation-status" type="check" color="success" size="l" /> + ) : ( + <EuiIcon data-test-subj="installation-status" type="cross" color="danger" size="l" /> + ), + }, + { + name: ( + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.healthColumnTitle" + defaultMessage="Health" + /> + ), + width: '10%', + align: 'center', + render: ({ installed, resource, health }: EngineComponentStatus) => { + if (!installed) { + return null; + } + + return <EuiHealth color={HEALTH_COLOR[health ?? 'green']} />; + }, + }, + { + isExpander: true, + align: 'right', + width: '40px', + name: ( + <EuiScreenReaderOnly> + <span> + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.expandRow" + defaultMessage="Expand row" + /> + </span> + </EuiScreenReaderOnly> + ), + mobileOptions: { header: false }, + render: (component: EngineComponentStatus) => { + const isItemExpanded = expandedItems.includes(component); + + return component.errors && component.errors.length > 0 ? ( + <EuiButtonIcon + onClick={() => onToggleExpandedItem(component)} + aria-label={isItemExpanded ? 'Collapse' : 'Expand'} + iconType={isItemExpanded ? 'arrowDown' : 'arrowRight'} + /> + ) : null; + }, + }, + ], + [expandedItems, getUrlForApp, onToggleExpandedItem] + ); +}; + +const getResourcePath = (id: string, resource: EngineComponentResource) => { + if (resource === EngineComponentResourceEnum.ingest_pipeline) { + return `ingest/ingest_pipelines?pipeline=${id}`; + } + + if (resource === EngineComponentResourceEnum.index_template) { + return `data/index_management/templates/${id}`; + } + + if (resource === EngineComponentResourceEnum.index) { + return `data/index_management/indices/index_details?indexName=${id}`; + } + + if (resource === EngineComponentResourceEnum.component_template) { + return `data/index_management/component_templates/${id}`; + } + + if (resource === EngineComponentResourceEnum.enrich_policy) { + return `data/index_management/enrich_policies?policy=${id}`; + } + + if (resource === EngineComponentResourceEnum.transform) { + return `data/transform/enrich_policies?_a=(transform:(queryText:'${id}'))`; + } + return null; +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/index.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/index.test.tsx new file mode 100644 index 000000000000..2f9e74df39d3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/index.test.tsx @@ -0,0 +1,100 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { EngineStatus } from '.'; + +import { TestProviders } from '@kbn/timelines-plugin/public/mock'; + +const mockUseEntityStore = jest.fn(); +jest.mock('../../hooks/use_entity_store', () => ({ + useEntityStoreStatus: () => mockUseEntityStore(), +})); + +const mockDownloadBlob = jest.fn(); +jest.mock('../../../../../common/utils/download_blob', () => ({ + downloadBlob: () => mockDownloadBlob(), +})); + +describe('EngineStatus', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('renders loading spinner when data is loading', () => { + mockUseEntityStore.mockReturnValue({ + data: undefined, + isLoading: true, + error: null, + }); + + render(<EngineStatus />, { wrapper: TestProviders }); + + expect(screen.getByRole('progressbar')).toBeInTheDocument(); + }); + + it('renders error state when there is an error', () => { + mockUseEntityStore.mockReturnValue({ + data: null, + isLoading: false, + error: new Error('Error'), + }); + + render(<EngineStatus />, { wrapper: TestProviders }); + + expect(screen.getByText('There was an error loading the engine status')).toBeInTheDocument(); + }); + + it('renders "No engines found" message when there are no engines', () => { + mockUseEntityStore.mockReturnValue({ + data: { engines: [] }, + isLoading: false, + error: null, + }); + + render(<EngineStatus />, { wrapper: TestProviders }); + + expect(screen.getByText('No engines found')).toBeInTheDocument(); + }); + + it('renders engine components when data is available', () => { + const mockData = { + engines: [ + { + type: 'test', + components: [{ id: 'entity_engine_id', installed: true, resource: 'entity_engine' }], + }, + ], + }; + mockUseEntityStore.mockReturnValue({ data: mockData, isLoading: false, error: null }); + + render(<EngineStatus />, { wrapper: TestProviders }); + + expect(screen.getByText('Test Store')).toBeInTheDocument(); + expect(screen.getByText('Download status')).toBeInTheDocument(); + }); + + it('calls downloadJson when download button is clicked', () => { + const mockData = { + engines: [ + { + type: 'test', + components: [{ id: 'entity_engine_id', installed: true, resource: 'entity_engine' }], + }, + ], + }; + mockUseEntityStore.mockReturnValue({ data: mockData, isLoading: false, error: null }); + + render(<EngineStatus />, { wrapper: TestProviders }); + + const downloadButton = screen.getByText('Download status'); + fireEvent.click(downloadButton); + + expect(mockDownloadBlob).toHaveBeenCalled(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/index.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/index.tsx new file mode 100644 index 000000000000..692841334bd5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/components/engines_status/index.tsx @@ -0,0 +1,103 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { Fragment } from 'react'; +import { + EuiLoadingSpinner, + EuiPanel, + EuiSpacer, + EuiButtonEmpty, + EuiFlexItem, + EuiTitle, + EuiFlexGroup, + EuiCallOut, +} from '@elastic/eui'; +import { capitalize } from 'lodash/fp'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { i18n } from '@kbn/i18n'; +import { useErrorToast } from '../../../../../common/hooks/use_error_toast'; +import { downloadBlob } from '../../../../../common/utils/download_blob'; +import { EngineComponentsStatusTable } from './components/engine_components_status'; +import { useEntityStoreStatus } from '../../hooks/use_entity_store'; + +const FILE_NAME = 'engines_status.json'; + +export const EngineStatus: React.FC = () => { + const { data, isLoading, error } = useEntityStoreStatus({ withComponents: true }); + + const downloadJson = () => { + downloadBlob(new Blob([JSON.stringify(data)]), FILE_NAME); + }; + + const errorMessage = i18n.translate( + 'xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.queryError', + { + defaultMessage: 'There was an error loading the engine status', + } + ); + + useErrorToast(errorMessage, error); + + if (error) { + return <EuiCallOut title={errorMessage} color="danger" iconType="alert" />; + } + + if (!data || isLoading) return <EuiLoadingSpinner size="xl" />; + + if (data.engines.length === 0) { + return ( + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.notFoundMessage" + defaultMessage="No engines found" + /> + ); + } + + return ( + <EuiFlexGroup direction="column" gutterSize="none"> + {data?.engines?.length > 0 && ( + <EuiFlexItem grow={false}> + <EuiFlexGroup justifyContent="flexEnd"> + <EuiFlexItem grow={false}> + <EuiButtonEmpty size="s" onClick={downloadJson}> + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.downloadButton" + defaultMessage="Download status" + /> + </EuiButtonEmpty> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + )} + <EuiFlexItem> + {(data?.engines ?? []).map((engine) => ( + <Fragment key={engine.type}> + <EuiTitle size="s"> + <h4> + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStore.enginesStatus.title" + defaultMessage="{type} Store" + values={{ + type: capitalize(engine.type), + }} + /> + </h4> + </EuiTitle> + + <EuiSpacer size="s" /> + + <EuiPanel hasShadow={false} hasBorder={false}> + {engine.components && <EngineComponentsStatusTable components={engine.components} />} + </EuiPanel> + + <EuiSpacer size="xl" /> + </Fragment> + ))} + </EuiFlexItem> + </EuiFlexGroup> + ); +}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_engine_status.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_engine_status.ts deleted file mode 100644 index 8a1760728074..000000000000 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_engine_status.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { UseQueryOptions } from '@tanstack/react-query'; -import { useQuery } from '@tanstack/react-query'; -import type { ListEntityEnginesResponse } from '../../../../../common/api/entity_analytics'; -import { useEntityStoreRoutes } from '../../../api/entity_store'; - -export const ENTITY_STORE_ENGINE_STATUS = 'ENTITY_STORE_ENGINE_STATUS'; - -interface Options { - disabled?: boolean; - polling?: UseQueryOptions<ListEntityEnginesResponse>['refetchInterval']; -} - -interface EngineError { - message: string; -} - -export const useEntityEngineStatus = (opts: Options = {}) => { - // QUESTION: Maybe we should have an `EnablementStatus` API route for this? - const { listEntityEngines } = useEntityStoreRoutes(); - - const { isLoading, data } = useQuery<ListEntityEnginesResponse>({ - queryKey: [ENTITY_STORE_ENGINE_STATUS], - queryFn: () => listEntityEngines(), - refetchInterval: opts.polling, - enabled: !opts.disabled, - }); - - const status = (() => { - if (data?.count === 0) { - return 'not_installed'; - } - - if (data?.engines?.some((engine) => engine.status === 'error')) { - return 'error'; - } - - if (data?.engines?.every((engine) => engine.status === 'stopped')) { - return 'stopped'; - } - - if (data?.engines?.some((engine) => engine.status === 'installing')) { - return 'installing'; - } - - if (isLoading) { - return 'loading'; - } - - if (!data) { - return 'error'; - } - - return 'enabled'; - })(); - - const errors = (data?.engines - ?.filter((engine) => engine.status === 'error') - .map((engine) => engine.error) ?? []) as EngineError[]; - - return { - status, - errors, - }; -}; diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts index 8aefbe2b44af..ceb93d164af6 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/entity_store/hooks/use_entity_store.ts @@ -7,8 +7,10 @@ import type { UseMutationOptions } from '@tanstack/react-query'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; -import { useCallback, useState } from 'react'; +import type { IHttpFetchError } from '@kbn/core-http-browser'; +import type { GetEntityStoreStatusResponse } from '../../../../../common/api/entity_analytics/entity_store/status.gen'; +import type { InitEntityStoreResponse } from '../../../../../common/api/entity_analytics/entity_store/enable.gen'; import { useKibana } from '../../../../common/lib/kibana/kibana_react'; import type { DeleteEntityEngineResponse, @@ -16,138 +18,105 @@ import type { StopEntityEngineResponse, } from '../../../../../common/api/entity_analytics'; import { useEntityStoreRoutes } from '../../../api/entity_store'; -import { ENTITY_STORE_ENGINE_STATUS, useEntityEngineStatus } from './use_entity_engine_status'; import { EntityEventTypes } from '../../../../common/lib/telemetry'; -const ENTITY_STORE_ENABLEMENT_INIT = 'ENTITY_STORE_ENABLEMENT_INIT'; +const ENTITY_STORE_STATUS = ['GET', 'ENTITY_STORE_STATUS']; -export const useEntityStoreEnablement = () => { - const [polling, setPolling] = useState(false); - const { telemetry } = useKibana().services; +interface ResponseError { + body: { message: string }; +} + +interface Options { + withComponents?: boolean; +} + +export const useEntityStoreStatus = (opts: Options = {}) => { + const { getEntityStoreStatus } = useEntityStoreRoutes(); - useEntityEngineStatus({ - disabled: !polling, - polling: (data) => { - const shouldStopPolling = - data?.engines && - data.engines.length > 0 && - data.engines.every((engine) => engine.status === 'started'); - - if (shouldStopPolling) { - setPolling(false); - return false; + return useQuery<GetEntityStoreStatusResponse, IHttpFetchError>({ + queryKey: [...ENTITY_STORE_STATUS, opts.withComponents], + queryFn: () => getEntityStoreStatus(opts.withComponents), + refetchInterval: (data) => { + if (data?.status === 'installing') { + return 5000; } - return 5000; + return false; }, }); - - const { initEntityStore } = useEntityStoreRoutes(); - const { refetch: initialize, ...query } = useQuery({ - queryKey: [ENTITY_STORE_ENABLEMENT_INIT], - queryFn: async () => - initEntityStore('user').then((usr) => initEntityStore('host').then((host) => [usr, host])), - enabled: false, - }); - - const enable = useCallback(() => { - telemetry?.reportEvent(EntityEventTypes.EntityStoreDashboardInitButtonClicked, { - timestamp: new Date().toISOString(), - }); - return initialize().then(() => setPolling(true)); - }, [initialize, telemetry]); - - return { enable, query }; }; -export const INIT_ENTITY_ENGINE_STATUS_KEY = ['POST', 'INIT_ENTITY_ENGINE']; - -export const useInvalidateEntityEngineStatusQuery = () => { +export const ENABLE_STORE_STATUS_KEY = ['POST', 'ENABLE_ENTITY_STORE']; +export const useEnableEntityStoreMutation = (options?: UseMutationOptions<{}>) => { + const { telemetry } = useKibana().services; const queryClient = useQueryClient(); + const { enableEntityStore } = useEntityStoreRoutes(); - return useCallback(() => { - queryClient.invalidateQueries([ENTITY_STORE_ENGINE_STATUS], { - refetchType: 'active', - }); - }, [queryClient]); -}; - -export const useInitEntityEngineMutation = (options?: UseMutationOptions<{}>) => { - const { telemetry } = useKibana().services; - const invalidateEntityEngineStatusQuery = useInvalidateEntityEngineStatusQuery(); - const { initEntityStore } = useEntityStoreRoutes(); - return useMutation<InitEntityEngineResponse[]>( + return useMutation<InitEntityStoreResponse, ResponseError>( () => { telemetry?.reportEvent(EntityEventTypes.EntityStoreEnablementToggleClicked, { timestamp: new Date().toISOString(), action: 'start', }); - return initEntityStore('user').then((usr) => - initEntityStore('host').then((host) => [usr, host]) - ); + return enableEntityStore(); }, { + mutationKey: ENABLE_STORE_STATUS_KEY, + onSuccess: () => queryClient.refetchQueries(ENTITY_STORE_STATUS), ...options, - mutationKey: INIT_ENTITY_ENGINE_STATUS_KEY, - onSettled: (...args) => { - invalidateEntityEngineStatusQuery(); + } + ); +}; - if (options?.onSettled) { - options.onSettled(...args); - } - }, +export const INIT_ENTITY_ENGINE_STATUS_KEY = ['POST', 'INIT_ENTITY_ENGINE']; +export const useInitEntityEngineMutation = (options?: UseMutationOptions<{}>) => { + const queryClient = useQueryClient(); + + const { initEntityEngine } = useEntityStoreRoutes(); + return useMutation<InitEntityEngineResponse[]>( + () => Promise.all([initEntityEngine('user'), initEntityEngine('host')]), + + { + mutationKey: INIT_ENTITY_ENGINE_STATUS_KEY, + onSuccess: () => queryClient.refetchQueries({ queryKey: ENTITY_STORE_STATUS }), + ...options, } ); }; export const STOP_ENTITY_ENGINE_STATUS_KEY = ['POST', 'STOP_ENTITY_ENGINE']; - export const useStopEntityEngineMutation = (options?: UseMutationOptions<{}>) => { const { telemetry } = useKibana().services; - const invalidateEntityEngineStatusQuery = useInvalidateEntityEngineStatusQuery(); - const { stopEntityStore } = useEntityStoreRoutes(); + const queryClient = useQueryClient(); + + const { stopEntityEngine } = useEntityStoreRoutes(); return useMutation<StopEntityEngineResponse[]>( () => { telemetry?.reportEvent(EntityEventTypes.EntityStoreEnablementToggleClicked, { timestamp: new Date().toISOString(), action: 'stop', }); - return stopEntityStore('user').then((usr) => - stopEntityStore('host').then((host) => [usr, host]) - ); + return Promise.all([stopEntityEngine('user'), stopEntityEngine('host')]); }, { - ...options, mutationKey: STOP_ENTITY_ENGINE_STATUS_KEY, - onSettled: (...args) => { - invalidateEntityEngineStatusQuery(); - - if (options?.onSettled) { - options.onSettled(...args); - } - }, + onSuccess: () => queryClient.refetchQueries({ queryKey: ENTITY_STORE_STATUS }), + ...options, } ); }; export const DELETE_ENTITY_ENGINE_STATUS_KEY = ['POST', 'STOP_ENTITY_ENGINE']; - -export const useDeleteEntityEngineMutation = (options?: UseMutationOptions<{}>) => { - const invalidateEntityEngineStatusQuery = useInvalidateEntityEngineStatusQuery(); +export const useDeleteEntityEngineMutation = ({ onSuccess }: { onSuccess?: () => void }) => { + const queryClient = useQueryClient(); const { deleteEntityEngine } = useEntityStoreRoutes(); + return useMutation<DeleteEntityEngineResponse[]>( - () => - deleteEntityEngine('user', true).then((usr) => - deleteEntityEngine('host', true).then((host) => [usr, host]) - ), + () => Promise.all([deleteEntityEngine('user', true), deleteEntityEngine('host', true)]), { - ...options, mutationKey: DELETE_ENTITY_ENGINE_STATUS_KEY, - onSettled: (...args) => { - invalidateEntityEngineStatusQuery(); - - if (options?.onSettled) { - options.onSettled(...args); - } + onSuccess: () => { + queryClient.refetchQueries({ queryKey: ENTITY_STORE_STATUS }); + onSuccess?.(); }, } ); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx index 494cfd5c16b2..9cc773df320b 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/components/risk_summary_flyout/risk_summary.test.tsx @@ -17,6 +17,7 @@ import type { LensAttributes, VisualizationEmbeddableProps, } from '../../../common/components/visualization_actions/types'; +import type { Query } from '@kbn/es-query'; const mockVisualizationEmbeddable = jest .fn() @@ -159,7 +160,7 @@ describe('FlyoutRiskSummary', () => { ); const firstColumn = Object.values(datasourceLayers[0].columns)[0]; - expect(lensAttributes.state.query.query).toEqual('host.name: test'); + expect((lensAttributes.state.query as Query).query).toEqual('host.name: test'); expect(firstColumn).toEqual( expect.objectContaining({ sourceField: 'host.risk.calculated_score_norm', @@ -230,7 +231,7 @@ describe('FlyoutRiskSummary', () => { ); const firstColumn = Object.values(datasourceLayers[0].columns)[0]; - expect(lensAttributes.state.query.query).toEqual('user.name: test'); + expect((lensAttributes.state.query as Query).query).toEqual('user.name: test'); expect(firstColumn).toEqual( expect.objectContaining({ sourceField: 'user.risk.calculated_score_norm', diff --git a/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts b/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts index 2a00cb169197..ac7028fa9028 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts +++ b/x-pack/plugins/security_solution/public/entity_analytics/lens_attributes/risk_score_summary.test.ts @@ -12,6 +12,7 @@ import { RiskSeverity } from '../../../common/search_strategy'; import type { MetricVisualizationState } from '@kbn/lens-plugin/public'; import { wrapper } from '../../common/components/visualization_actions/mocks'; import { useLensAttributes } from '../../common/components/visualization_actions/use_lens_attributes'; +import type { Query } from '@kbn/es-query'; jest.mock('../../sourcerer/containers', () => ({ useSourcererDataView: jest.fn().mockReturnValue({ @@ -78,6 +79,6 @@ describe('getRiskScoreSummaryAttributes', () => { { wrapper } ); - expect(result?.current?.state.query.query).toBe(query); + expect((result?.current?.state.query as Query).query).toBe(query); }); }); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_dashboard.tsx b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_dashboard.tsx index 2fbc4f67ab6e..9c99ac168717 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_dashboard.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_analytics_dashboard.tsx @@ -24,19 +24,23 @@ import { useHasSecurityCapability } from '../../helper_hooks'; import { EntityAnalyticsHeader } from '../components/entity_analytics_header'; import { EntityAnalyticsAnomalies } from '../components/entity_analytics_anomalies'; -import { EntityStoreDashboardPanels } from '../components/entity_store/components/dashboard_panels'; +import { EntityStoreDashboardPanels } from '../components/entity_store/components/dashboard_entity_store_panels'; import { EntityAnalyticsRiskScores } from '../components/entity_analytics_risk_score'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; const EntityAnalyticsComponent = () => { + const [skipEmptyPrompt, setSkipEmptyPrompt] = React.useState(false); + const onSkip = React.useCallback(() => setSkipEmptyPrompt(true), [setSkipEmptyPrompt]); const { data: riskScoreEngineStatus } = useRiskEngineStatus(); const { indicesExist, loading: isSourcererLoading, sourcererDataView } = useSourcererDataView(); const isRiskScoreModuleLicenseAvailable = useHasSecurityCapability('entity-analytics'); const isEntityStoreFeatureFlagDisabled = useIsExperimentalFeatureEnabled('entityStoreDisabled'); - + const showEmptyPrompt = !indicesExist && !skipEmptyPrompt; return ( <> - {indicesExist ? ( + {showEmptyPrompt ? ( + <EmptyPrompt onSkip={onSkip} /> + ) : ( <> <FiltersGlobal> <SiemSearchBar id={InputsModelId.global} sourcererDataView={sourcererDataView} /> @@ -82,8 +86,6 @@ const EntityAnalyticsComponent = () => { )} </SecuritySolutionPageWrapper> </> - ) : ( - <EmptyPrompt /> )} <SpyRoute pageName={SecurityPageName.entityAnalytics} /> diff --git a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.test.tsx b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.test.tsx new file mode 100644 index 000000000000..cc15a5360a3d --- /dev/null +++ b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.test.tsx @@ -0,0 +1,207 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { EntityStoreManagementPage } from './entity_store_management_page'; +import { TestProviders } from '../../common/mock'; + +jest.mock('../components/entity_store/components/engines_status', () => ({ + EngineStatus: () => <span>{'Mocked Engine Status Tab'}</span>, +})); + +const mockUseAssetCriticalityPrivileges = jest.fn(); +jest.mock('../components/asset_criticality/use_asset_criticality', () => ({ + useAssetCriticalityPrivileges: () => mockUseAssetCriticalityPrivileges(), +})); + +const mockUseIsExperimentalFeatureEnabled = jest.fn(); +jest.mock('../../common/hooks/use_experimental_features', () => ({ + useIsExperimentalFeatureEnabled: () => mockUseIsExperimentalFeatureEnabled(), +})); + +const mockUseHasSecurityCapability = jest.fn().mockReturnValue(true); +jest.mock('../../helper_hooks', () => ({ + useHasSecurityCapability: () => mockUseHasSecurityCapability(), +})); + +const mockUseEntityStoreStatus = jest.fn(); +jest.mock('../components/entity_store/hooks/use_entity_store', () => ({ + ...jest.requireActual('../components/entity_store/hooks/use_entity_store'), + useEntityStoreStatus: () => mockUseEntityStoreStatus(), +})); + +const mockUseEntityEnginePrivileges = jest.fn(); +jest.mock('../components/entity_store/hooks/use_entity_engine_privileges', () => ({ + useEntityEnginePrivileges: () => mockUseEntityEnginePrivileges(), +})); + +describe('EntityStoreManagementPage', () => { + beforeEach(() => { + jest.clearAllMocks(); + + mockUseAssetCriticalityPrivileges.mockReturnValue({ + isLoading: false, + data: { has_write_permissions: true }, + }); + + mockUseEntityEnginePrivileges.mockReturnValue({ + data: { has_all_required: true }, + }); + + mockUseEntityStoreStatus.mockReturnValue({ + data: { + status: 'running', + }, + errors: [], + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + }); + + it('does not render page when asset criticality is loading', () => { + mockUseAssetCriticalityPrivileges.mockReturnValue({ + isLoading: true, + }); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect(screen.queryByTestId('entityStoreManagementPage')).not.toBeInTheDocument(); + }); + + it('renders the page header', () => { + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect(screen.getByTestId('entityStoreManagementPage')).toBeInTheDocument(); + expect(screen.getByText('Entity Store')).toBeInTheDocument(); + }); + + it('disables the switch when status is installing', () => { + mockUseEntityStoreStatus.mockReturnValue({ + data: { + status: 'installing', + }, + errors: [], + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect(screen.getByTestId('entity-store-switch')).toBeDisabled(); + }); + + it('show clear entity data modal when clear data button clicked', () => { + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + fireEvent.click(screen.getByText('Clear Entity Data')); + + expect(screen.getByText('Clear Entity data?')).toBeInTheDocument(); + }); + + it('renders the AssetCriticalityIssueCallout when there is an error', () => { + mockUseAssetCriticalityPrivileges.mockReturnValue({ + isLoading: false, + error: { body: { message: 'Error message', status_code: 403 } }, + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect( + screen.getByText('Asset criticality CSV file upload functionality unavailable.') + ).toBeInTheDocument(); + expect(screen.getByText('Error message')).toBeInTheDocument(); + }); + + it('renders the InsufficientAssetCriticalityPrivilegesCallout when there are no write permissions', () => { + mockUseAssetCriticalityPrivileges.mockReturnValue({ + isLoading: false, + data: { has_write_permissions: false }, + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect( + screen.getByText('Insufficient index privileges to perform CSV upload') + ).toBeInTheDocument(); + }); + + it('selects the Import tab by default', () => { + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect(screen.getByText('Import Entities').parentNode).toHaveAttribute('aria-selected', 'true'); + }); + + it('switches to the Status tab when clicked', () => { + mockUseEntityStoreStatus.mockReturnValue({ + data: { + status: 'running', + }, + errors: [], + }); + + mockUseEntityEnginePrivileges.mockReturnValue({ + data: { has_all_required: true }, + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + fireEvent.click(screen.getByText('Engine Status')); + + expect(screen.getByText('Engine Status').parentNode).toHaveAttribute('aria-selected', 'true'); + }); + + it('does not render the Status tab when entity store is not installed', () => { + mockUseEntityStoreStatus.mockReturnValue({ + data: { + status: 'not_installed', + }, + errors: [], + }); + + mockUseEntityEnginePrivileges.mockReturnValue({ + data: { has_all_required: true }, + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect(screen.queryByText('Engine Status')).not.toBeInTheDocument(); + }); + + it('does not render the Status tab when privileges are missing', () => { + mockUseEntityStoreStatus.mockReturnValue({ + data: { + status: 'running', + }, + errors: [], + }); + + mockUseEntityEnginePrivileges.mockReturnValue({ + data: { has_all_required: false, privileges: { kibana: {}, elasticsearch: {} } }, + }); + + mockUseIsExperimentalFeatureEnabled.mockReturnValue(false); + + render(<EntityStoreManagementPage />, { wrapper: TestProviders }); + + expect(screen.queryByText('Engine Status')).not.toBeInTheDocument(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx index 84648d89f912..3cf3eb58355c 100644 --- a/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx +++ b/x-pack/plugins/security_solution/public/entity_analytics/pages/entity_store_management_page.tsx @@ -21,14 +21,19 @@ import { EuiCode, EuiSwitch, EuiHealth, - EuiButton, EuiLoadingSpinner, EuiToolTip, EuiBetaBadge, + EuiTabs, + EuiTab, + EuiButtonEmpty, } from '@elastic/eui'; -import React, { useCallback, useState } from 'react'; +import type { ReactNode } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useEntityEngineStatus } from '../components/entity_store/hooks/use_entity_engine_status'; + +import type { SecurityAppError } from '@kbn/securitysolution-t-grid'; +import type { StoreStatus } from '../../../common/api/entity_analytics'; import { useIsExperimentalFeatureEnabled } from '../../common/hooks/use_experimental_features'; import { ASSET_CRITICALITY_INDEX_PATTERN } from '../../../common/entity_analytics/asset_criticality'; import { useKibana } from '../../common/lib/kibana'; @@ -37,16 +42,25 @@ import { useAssetCriticalityPrivileges } from '../components/asset_criticality/u import { useHasSecurityCapability } from '../../helper_hooks'; import { useDeleteEntityEngineMutation, - useInitEntityEngineMutation, + useEnableEntityStoreMutation, + useEntityStoreStatus, useStopEntityEngineMutation, } from '../components/entity_store/hooks/use_entity_store'; import { TECHNICAL_PREVIEW, TECHNICAL_PREVIEW_TOOLTIP } from '../../common/translations'; import { useEntityEnginePrivileges } from '../components/entity_store/hooks/use_entity_engine_privileges'; import { MissingPrivilegesCallout } from '../components/entity_store/components/missing_privileges_callout'; +import { EngineStatus } from '../components/entity_store/components/engines_status'; + +enum TabId { + Import = 'import', + Status = 'status', +} -const entityStoreEnabledStatuses = ['enabled']; -const switchDisabledStatuses = ['error', 'loading', 'installing']; -const entityStoreInstallingStatuses = ['installing', 'loading']; +const isSwitchDisabled = (status?: StoreStatus) => status === 'error' || status === 'installing'; +const isEntityStoreEnabled = (status?: StoreStatus) => status === 'running'; +const canDeleteEntityEngine = (status?: StoreStatus) => + !['not_installed', 'installing'].includes(status || ''); +const isEntityStoreInstalled = (status?: StoreStatus) => status && status !== 'not_installed'; export const EntityStoreManagementPage = () => { const hasEntityAnalyticsCapability = useHasSecurityCapability('entity-analytics'); @@ -57,26 +71,10 @@ export const EntityStoreManagementPage = () => { isLoading: assetCriticalityIsLoading, } = useAssetCriticalityPrivileges('AssetCriticalityUploadPage'); const hasAssetCriticalityWritePermissions = assetCriticalityPrivileges?.has_write_permissions; + const [selectedTabId, setSelectedTabId] = useState(TabId.Import); + const entityStoreStatus = useEntityStoreStatus({}); - const [polling, setPolling] = useState(false); - const entityStoreStatus = useEntityEngineStatus({ - disabled: false, - polling: !polling - ? undefined - : (data) => { - const shouldStopPolling = - data?.engines && - data.engines.length > 0 && - data.engines.every((engine) => engine.status === 'started'); - - if (shouldStopPolling) { - setPolling(false); - return false; - } - return 1000; - }, - }); - const initEntityEngineMutation = useInitEntityEngineMutation(); + const enableStoreMutation = useEnableEntityStoreMutation(); const stopEntityEngineMutation = useStopEntityEngineMutation(); const deleteEntityEngineMutation = useDeleteEntityEngineMutation({ onSuccess: () => { @@ -89,187 +87,60 @@ export const EntityStoreManagementPage = () => { const showClearModal = useCallback(() => setIsClearModalVisible(true), []); const onSwitchClick = useCallback(() => { - if (switchDisabledStatuses.includes(entityStoreStatus.status)) { + if (isSwitchDisabled(entityStoreStatus.data?.status)) { return; } - if (entityStoreEnabledStatuses.includes(entityStoreStatus.status)) { + if (isEntityStoreEnabled(entityStoreStatus.data?.status)) { stopEntityEngineMutation.mutate(); } else { - setPolling(true); - initEntityEngineMutation.mutate(); + enableStoreMutation.mutate(); } - }, [initEntityEngineMutation, stopEntityEngineMutation, entityStoreStatus]); + }, [entityStoreStatus.data?.status, stopEntityEngineMutation, enableStoreMutation]); const { data: privileges } = useEntityEnginePrivileges(); + const shouldDisplayEngineStatusTab = + isEntityStoreInstalled(entityStoreStatus.data?.status) && privileges?.has_all_required; + + useEffect(() => { + if (selectedTabId === TabId.Status && !shouldDisplayEngineStatusTab) { + setSelectedTabId(TabId.Import); + } + }, [shouldDisplayEngineStatusTab, selectedTabId]); + if (assetCriticalityIsLoading) { // Wait for permission before rendering content to avoid flickering return null; } - const AssetCriticalityIssueCallout: React.FC = () => { - const errorMessage = assetCriticalityPrivilegesError?.body.message ?? ( - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.advancedSettingDisabledMessage" - defaultMessage="The don't have privileges to access Asset Criticality feature. Contact your administrator for further assistance." - /> - ); + const isMutationLoading = + enableStoreMutation.isLoading || + stopEntityEngineMutation.isLoading || + deleteEntityEngineMutation.isLoading; - return ( - <EuiFlexItem grow={false}> + const callouts = (entityStoreStatus.data?.engines || []) + .filter((engine) => engine.status === 'error') + .map((engine) => { + const err = engine.error as { + message: string; + }; + + return ( <EuiCallOut title={ <FormattedMessage - id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unavailable" - defaultMessage="Asset criticality CSV file upload functionality unavailable." + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.title" + defaultMessage={'An error occurred during entity store resource initialization'} /> } - color="primary" - iconType="iInCircle" + color="danger" + iconType="alert" > - <EuiText size="s">{errorMessage}</EuiText> + <p>{err?.message}</p> </EuiCallOut> - </EuiFlexItem> - ); - }; - - const ClearEntityDataPanel: React.FC = () => { - return ( - <> - <EuiPanel - paddingSize="l" - grow={false} - color="subdued" - borderRadius="none" - hasShadow={false} - > - <EuiText size="s"> - <h3> - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntityData" - defaultMessage="Clear entity data" - /> - </h3> - <EuiSpacer size="s" /> - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntityData" - defaultMessage={`Remove all extracted entity data from the store. This action will - permanently delete persisted user and host records, and data will no longer be available for analysis. - Proceed with caution, as this cannot be undone. Note that this operation will not delete source data, - Entity risk scores, or Asset Criticality assignments.`} - /> - </EuiText> - <EuiSpacer size="m" /> - <EuiButton - color="danger" - iconType="trash" - onClick={() => { - showClearModal(); - }} - > - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clear" - defaultMessage="Clear" - /> - </EuiButton> - </EuiPanel> - {isClearModalVisible && ( - <EuiConfirmModal - isLoading={deleteEntityEngineMutation.isLoading} - title={ - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.title" - defaultMessage="Clear Entity data?" - /> - } - onCancel={closeClearModal} - onConfirm={() => { - deleteEntityEngineMutation.mutate(); - }} - cancelButtonText={ - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.close" - defaultMessage="Close" - /> - } - confirmButtonText={ - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.clearAllEntities" - defaultMessage="Clear All Entities" - /> - } - buttonColor="danger" - defaultFocusedButton="confirm" - > - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearConfirmation" - defaultMessage={ - 'This will delete all Security Entity store records. Source data, Entity risk scores, and Asset criticality assignments are unaffected by this action. This operation cannot be undone.' - } - /> - </EuiConfirmModal> - )} - </> - ); - }; - - const FileUploadSection: React.FC = () => { - if ( - !hasEntityAnalyticsCapability || - assetCriticalityPrivilegesError?.body.status_code === 403 - ) { - return <AssetCriticalityIssueCallout />; - } - if (!hasAssetCriticalityWritePermissions) { - return <InsufficientAssetCriticalityPrivilegesCallout />; - } - return ( - <EuiFlexItem grow={3}> - <EuiTitle size="s"> - <h2> - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.subTitle" - defaultMessage="Import entities using a text file" - /> - </h2> - </EuiTitle> - <EuiSpacer size="m" /> - <EuiText size="s"> - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.description" - defaultMessage="Bulk assign asset criticality by importing a CSV, TXT, or TSV file exported from your asset management tools. This ensures data accuracy and reduces manual input errors." - /> - </EuiText> - <EuiSpacer size="s" /> - <AssetCriticalityFileUploader /> - </EuiFlexItem> - ); - }; - - const canDeleteEntityEngine = !['not_installed', 'loading', 'installing'].includes( - entityStoreStatus.status - ); - - const isMutationLoading = - initEntityEngineMutation.isLoading || - stopEntityEngineMutation.isLoading || - deleteEntityEngineMutation.isLoading; - - const callouts = entityStoreStatus.errors.map((error) => ( - <EuiCallOut - title={ - <FormattedMessage - id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.errors.title" - defaultMessage={'An error occurred during entity store resource initialization'} - /> - } - color="danger" - iconType="alert" - > - <p>{error.message}</p> - </EuiCallOut> - )); + ); + }); return ( <> @@ -291,18 +162,23 @@ export const EntityStoreManagementPage = () => { !isEntityStoreFeatureFlagDisabled && privileges?.has_all_required ? [ <EnablementButton - isLoading={ - isMutationLoading || - entityStoreInstallingStatuses.includes(entityStoreStatus.status) - } - isDisabled={ - isMutationLoading || switchDisabledStatuses.includes(entityStoreStatus.status) - } + isLoading={isMutationLoading} + isDisabled={isSwitchDisabled(entityStoreStatus.data?.status)} onSwitch={onSwitchClick} - status={entityStoreStatus.status} + status={entityStoreStatus.data?.status} />, + canDeleteEntityEngine(entityStoreStatus.data?.status) ? ( + <ClearEntityDataButton + {...{ + deleteEntityEngineMutation, + isClearModalVisible, + closeClearModal, + showClearModal, + }} + /> + ) : null, ] - : [] + : undefined } /> <EuiSpacer size="s" /> @@ -321,13 +197,47 @@ export const EntityStoreManagementPage = () => { </> )} - <EuiHorizontalRule /> - <EuiSpacer size="l" /> + <EuiSpacer size="m" /> + + <EuiTabs data-test-subj="tabs"> + <EuiTab + key={TabId.Import} + isSelected={selectedTabId === TabId.Import} + onClick={() => setSelectedTabId(TabId.Import)} + > + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.importEntities.tabTitle" + defaultMessage="Import Entities" + /> + </EuiTab> + + {shouldDisplayEngineStatusTab && ( + <EuiTab + key={TabId.Status} + isSelected={selectedTabId === TabId.Status} + onClick={() => setSelectedTabId(TabId.Status)} + > + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.engineStatus.tabTitle" + defaultMessage="Engine Status" + /> + </EuiTab> + )} + </EuiTabs> + + <EuiSpacer size="s" /> <EuiFlexGroup gutterSize="xl"> - <FileUploadSection /> + {selectedTabId === TabId.Import && ( + <FileUploadSection + assetCriticalityPrivilegesError={assetCriticalityPrivilegesError} + hasEntityAnalyticsCapability={hasEntityAnalyticsCapability} + hasAssetCriticalityWritePermissions={hasAssetCriticalityWritePermissions} + /> + )} + {selectedTabId === TabId.Status && <EngineStatus />} <EuiFlexItem grow={2}> <EuiFlexGroup direction="column"> - {initEntityEngineMutation.isError && ( + {enableStoreMutation.isError && ( <EuiCallOut title={ <FormattedMessage @@ -338,9 +248,7 @@ export const EntityStoreManagementPage = () => { color="danger" iconType="alert" > - <p> - {(initEntityEngineMutation.error as { body: { message: string } }).body.message} - </p> + <p>{(enableStoreMutation.error as { body: { message: string } }).body.message}</p> </EuiCallOut> )} {deleteEntityEngineMutation.isError && ( @@ -360,10 +268,7 @@ export const EntityStoreManagementPage = () => { </EuiCallOut> )} {callouts} - <WhatIsAssetCriticalityPanel /> - {!isEntityStoreFeatureFlagDisabled && - privileges?.has_all_required && - canDeleteEntityEngine && <ClearEntityDataPanel />} + {selectedTabId === TabId.Import && <WhatIsAssetCriticalityPanel />} </EuiFlexGroup> </EuiFlexItem> </EuiFlexGroup> @@ -452,15 +357,15 @@ const EntityStoreFeatureFlagNotAvailableCallout: React.FC = () => { ); }; -const EntityStoreHealth: React.FC<{ currentEntityStoreStatus: string }> = ({ +const EntityStoreHealth: React.FC<{ currentEntityStoreStatus?: StoreStatus }> = ({ currentEntityStoreStatus, }) => { return ( <EuiHealth textSize="m" - color={entityStoreEnabledStatuses.includes(currentEntityStoreStatus) ? 'success' : 'subdued'} + color={isEntityStoreEnabled(currentEntityStoreStatus) ? 'success' : 'subdued'} > - {entityStoreEnabledStatuses.includes(currentEntityStoreStatus) ? 'On' : 'Off'} + {isEntityStoreEnabled(currentEntityStoreStatus) ? 'On' : 'Off'} </EuiHealth> ); }; @@ -468,7 +373,7 @@ const EntityStoreHealth: React.FC<{ currentEntityStoreStatus: string }> = ({ const EnablementButton: React.FC<{ isLoading: boolean; isDisabled: boolean; - status: string; + status?: StoreStatus; onSwitch: () => void; }> = ({ isLoading, isDisabled, status, onSwitch }) => { return ( @@ -484,7 +389,7 @@ const EnablementButton: React.FC<{ label="" onChange={onSwitch} data-test-subj="entity-store-switch" - checked={entityStoreEnabledStatuses.includes(status)} + checked={isEntityStoreEnabled(status)} disabled={isDisabled} /> </EuiFlexGroup> @@ -515,3 +420,124 @@ const InsufficientAssetCriticalityPrivilegesCallout: React.FC = () => { </EuiCallOut> ); }; + +const AssetCriticalityIssueCallout: React.FC<{ errorMessage?: string | ReactNode }> = ({ + errorMessage, +}) => { + const msg = errorMessage ?? ( + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.advancedSettingDisabledMessage" + defaultMessage="Privileges to access the Asset Criticality feature are missing for your user. Contact your administrator for further assistance." + /> + ); + + return ( + <EuiFlexItem grow={false}> + <EuiCallOut + title={ + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unavailable" + defaultMessage="Asset criticality CSV file upload functionality unavailable." + /> + } + color="primary" + iconType="iInCircle" + > + <EuiText size="s">{msg}</EuiText> + </EuiCallOut> + </EuiFlexItem> + ); +}; + +const ClearEntityDataButton: React.FC<{ + deleteEntityEngineMutation: ReturnType<typeof useDeleteEntityEngineMutation>; + isClearModalVisible: boolean; + closeClearModal: () => void; + showClearModal: () => void; +}> = ({ deleteEntityEngineMutation, isClearModalVisible, closeClearModal, showClearModal }) => { + return ( + <> + <EuiButtonEmpty + color="danger" + iconType="trash" + onClick={() => { + showClearModal(); + }} + > + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clear" + defaultMessage="Clear Entity Data" + /> + </EuiButtonEmpty> + + {isClearModalVisible && ( + <EuiConfirmModal + isLoading={deleteEntityEngineMutation.isLoading} + title={ + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.title" + defaultMessage="Clear Entity data?" + /> + } + onCancel={closeClearModal} + onConfirm={() => { + deleteEntityEngineMutation.mutate(); + }} + cancelButtonText={ + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.close" + defaultMessage="Close" + /> + } + confirmButtonText={ + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.clearAllEntities" + defaultMessage="Clear All Entities" + /> + } + buttonColor="danger" + defaultFocusedButton="confirm" + > + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearConfirmation" + defaultMessage={ + 'This will delete all Security Entity store records. Source data, Entity risk scores, and Asset criticality assignments are unaffected by this action. This operation cannot be undone.' + } + /> + </EuiConfirmModal> + )} + </> + ); +}; + +const FileUploadSection: React.FC<{ + assetCriticalityPrivilegesError: SecurityAppError | null; + hasEntityAnalyticsCapability: boolean; + hasAssetCriticalityWritePermissions?: boolean; +}> = ({ + assetCriticalityPrivilegesError, + hasEntityAnalyticsCapability, + hasAssetCriticalityWritePermissions, +}) => { + if (!hasEntityAnalyticsCapability || assetCriticalityPrivilegesError?.body.status_code === 403) { + return ( + <AssetCriticalityIssueCallout errorMessage={assetCriticalityPrivilegesError?.body.message} /> + ); + } + if (!hasAssetCriticalityWritePermissions) { + return <InsufficientAssetCriticalityPrivilegesCallout />; + } + return ( + <EuiFlexItem grow={3}> + <EuiSpacer size="m" /> + <EuiText size="s"> + <FormattedMessage + id="xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.description" + defaultMessage="Bulk assign asset criticality by importing a CSV, TXT, or TSV file exported from your asset management tools. This ensures data accuracy and reduces manual input errors." + /> + </EuiText> + <EuiSpacer size="s" /> + <AssetCriticalityFileUploader /> + </EuiFlexItem> + ); +}; diff --git a/x-pack/plugins/security_solution/public/explore/links.ts b/x-pack/plugins/security_solution/public/explore/links.ts index b1cad1b34db3..a65eccc95c37 100644 --- a/x-pack/plugins/security_solution/public/explore/links.ts +++ b/x-pack/plugins/security_solution/public/explore/links.ts @@ -34,6 +34,7 @@ const networkLinks: LinkItem = { defaultMessage: 'Network', }), ], + capabilities: [`${SERVER_APP_ID}.show`], links: [ { id: SecurityPageName.networkFlows, @@ -68,6 +69,7 @@ const networkLinks: LinkItem = { title: i18n.translate('xpack.securitySolution.appLinks.hosts.anomalies', { defaultMessage: 'Anomalies', }), + capabilities: ['ml.canGetJobs'], path: `${NETWORK_PATH}/anomalies`, licenseType: 'gold', }, @@ -95,6 +97,7 @@ const usersLinks: LinkItem = { defaultMessage: 'Users', }), ], + capabilities: [`${SERVER_APP_ID}.show`], links: [ { id: SecurityPageName.usersAll, @@ -115,6 +118,7 @@ const usersLinks: LinkItem = { title: i18n.translate('xpack.securitySolution.appLinks.users.anomalies', { defaultMessage: 'Anomalies', }), + capabilities: ['ml.canGetJobs'], path: `${USERS_PATH}/anomalies`, licenseType: 'gold', }, @@ -148,6 +152,7 @@ const hostsLinks: LinkItem = { defaultMessage: 'Hosts', }), ], + capabilities: [`${SERVER_APP_ID}.show`], links: [ { id: SecurityPageName.hostsAll, @@ -169,6 +174,7 @@ const hostsLinks: LinkItem = { title: i18n.translate('xpack.securitySolution.appLinks.hosts.anomalies', { defaultMessage: 'Anomalies', }), + capabilities: ['ml.canGetJobs'], path: `${HOSTS_PATH}/anomalies`, licenseType: 'gold', }, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx index 023b0202ecb6..7ccc3477a9d5 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.test.tsx @@ -14,6 +14,7 @@ import { NOTES_COUNT_TEST_ID, NOTES_LOADING_TEST_ID, NOTES_TITLE_TEST_ID, + NOTES_VIEW_NOTES_BUTTON_TEST_ID, } from './test_ids'; import { FETCH_NOTES_ERROR, Notes } from './notes'; import { mockContextValue } from '../../shared/mocks/mock_context'; @@ -24,8 +25,10 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { LeftPanelNotesTab } from '../../left'; import { getEmptyValue } from '../../../../common/components/empty_value'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; jest.mock('@kbn/expandable-flyout'); +jest.mock('../../../../common/components/user_privileges'); const mockAddError = jest.fn(); jest.mock('../../../../common/hooks/use_app_toasts', () => ({ @@ -45,6 +48,9 @@ jest.mock('react-redux', () => { describe('<Notes />', () => { beforeEach(() => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: true }, + }); jest.clearAllMocks(); }); @@ -297,4 +303,69 @@ describe('<Notes />', () => { title: FETCH_NOTES_ERROR, }); }); + + it('should show View note button if user does not have the correct privileges but notes have already been created', () => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: false }, + }); + + const mockOpenLeftPanel = jest.fn(); + (useExpandableFlyoutApi as jest.Mock).mockReturnValue({ openLeftPanel: mockOpenLeftPanel }); + + const contextValue = { + ...mockContextValue, + eventId: '1', + }; + + const { getByTestId, queryByTestId } = render( + <TestProviders> + <DocumentDetailsContext.Provider value={contextValue}> + <Notes /> + </DocumentDetailsContext.Provider> + </TestProviders> + ); + + expect(mockDispatch).toHaveBeenCalled(); + + expect(getByTestId(NOTES_COUNT_TEST_ID)).toBeInTheDocument(); + expect(getByTestId(NOTES_COUNT_TEST_ID)).toHaveTextContent('1'); + + expect(queryByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + const button = getByTestId(NOTES_VIEW_NOTES_BUTTON_TEST_ID); + expect(button).toBeInTheDocument(); + + button.click(); + + expect(mockOpenLeftPanel).toHaveBeenCalledWith({ + id: DocumentDetailsLeftPanelKey, + path: { tab: LeftPanelNotesTab }, + params: { + id: contextValue.eventId, + indexName: mockContextValue.indexName, + scopeId: mockContextValue.scopeId, + }, + }); + }); + + it('should show a - if user does not have the correct privileges and no notes have been created', () => { + (useUserPrivileges as jest.Mock).mockReturnValue({ + kibanaSecuritySolutionsPrivileges: { crud: false }, + }); + + const { getByText, queryByTestId } = render( + <TestProviders> + <DocumentDetailsContext.Provider value={mockContextValue}> + <Notes /> + </DocumentDetailsContext.Provider> + </TestProviders> + ); + + expect(mockDispatch).toHaveBeenCalled(); + + expect(queryByTestId(NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(NOTES_ADD_NOTE_BUTTON_TEST_ID)).not.toBeInTheDocument(); + expect(queryByTestId(NOTES_COUNT_TEST_ID)).not.toBeInTheDocument(); + expect(getByText(getEmptyValue())).toBeInTheDocument(); + }); }); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx index b0e2008c0410..e10a1ff23919 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/notes.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { memo, useCallback, useEffect } from 'react'; +import React, { memo, useCallback, useEffect, useMemo } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { FormattedMessage } from '@kbn/i18n-react'; import { i18n } from '@kbn/i18n'; @@ -19,6 +19,7 @@ import { } from '@elastic/eui'; import { css } from '@emotion/react'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; +import { useUserPrivileges } from '../../../../common/components/user_privileges'; import { getEmptyTagValue } from '../../../../common/components/empty_value'; import { DocumentDetailsLeftPanelKey } from '../../shared/constants/panel_keys'; import { FormattedCount } from '../../../../common/components/formatted_number'; @@ -29,6 +30,7 @@ import { NOTES_COUNT_TEST_ID, NOTES_LOADING_TEST_ID, NOTES_TITLE_TEST_ID, + NOTES_VIEW_NOTES_BUTTON_TEST_ID, } from './test_ids'; import type { State } from '../../../../common/store'; import type { Note } from '../../../../../common/api/timeline'; @@ -55,6 +57,12 @@ export const ADD_NOTE_BUTTON = i18n.translate( defaultMessage: 'Add note', } ); +export const VIEW_NOTES_BUTTON_ARIA_LABEL = i18n.translate( + 'xpack.securitySolution.flyout.right.notes.viewNoteButtonAriaLabel', + { + defaultMessage: 'View notes', + } +); /** * Renders a block with the number of notes for the event @@ -64,6 +72,7 @@ export const Notes = memo(() => { const dispatch = useDispatch(); const { eventId, indexName, scopeId, isPreview, isPreviewMode } = useDocumentDetailsContext(); const { addError: addErrorToast } = useAppToasts(); + const { kibanaSecuritySolutionsPrivileges } = useUserPrivileges(); const { openLeftPanel } = useExpandableFlyoutApi(); const openExpandedFlyoutNotesTab = useCallback( @@ -101,6 +110,61 @@ export const Notes = memo(() => { } }, [addErrorToast, fetchError, fetchStatus]); + const viewNotesButton = useMemo( + () => ( + <EuiButtonEmpty + onClick={openExpandedFlyoutNotesTab} + size="s" + disabled={isPreviewMode || isPreview} + aria-label={VIEW_NOTES_BUTTON_ARIA_LABEL} + data-test-subj={NOTES_VIEW_NOTES_BUTTON_TEST_ID} + > + <FormattedMessage + id="xpack.securitySolution.flyout.right.notes.viewNoteButtonLabel" + defaultMessage="View {count, plural, one {note} other {notes}}" + values={{ count: notes.length }} + /> + </EuiButtonEmpty> + ), + [isPreview, isPreviewMode, notes.length, openExpandedFlyoutNotesTab] + ); + const addNoteButton = useMemo( + () => ( + <EuiButtonEmpty + iconType="plusInCircle" + onClick={openExpandedFlyoutNotesTab} + size="s" + disabled={isPreviewMode || isPreview} + aria-label={ADD_NOTE_BUTTON} + data-test-subj={NOTES_ADD_NOTE_BUTTON_TEST_ID} + > + {ADD_NOTE_BUTTON} + </EuiButtonEmpty> + ), + [isPreview, isPreviewMode, openExpandedFlyoutNotesTab] + ); + const addNoteButtonIcon = useMemo( + () => ( + <EuiButtonIcon + onClick={openExpandedFlyoutNotesTab} + iconType="plusInCircle" + disabled={isPreviewMode || isPreview || !kibanaSecuritySolutionsPrivileges.crud} + css={css` + margin-left: ${euiTheme.size.xs}; + `} + aria-label={ADD_NOTE_BUTTON} + data-test-subj={NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID} + /> + ), + [ + euiTheme.size.xs, + isPreview, + isPreviewMode, + kibanaSecuritySolutionsPrivileges.crud, + openExpandedFlyoutNotesTab, + ] + ); + return ( <AlertHeaderBlock title={ @@ -120,32 +184,14 @@ export const Notes = memo(() => { ) : ( <> {notes.length === 0 ? ( - <EuiButtonEmpty - iconType="plusInCircle" - onClick={openExpandedFlyoutNotesTab} - size="s" - disabled={isPreviewMode || isPreview} - aria-label={ADD_NOTE_BUTTON} - data-test-subj={NOTES_ADD_NOTE_BUTTON_TEST_ID} - > - {ADD_NOTE_BUTTON} - </EuiButtonEmpty> + <>{kibanaSecuritySolutionsPrivileges.crud ? addNoteButton : getEmptyTagValue()}</> ) : ( <EuiFlexGroup responsive={false} alignItems="center" gutterSize="none"> <EuiFlexItem data-test-subj={NOTES_COUNT_TEST_ID}> <FormattedCount count={notes.length} /> </EuiFlexItem> <EuiFlexItem> - <EuiButtonIcon - onClick={openExpandedFlyoutNotesTab} - iconType="plusInCircle" - disabled={isPreviewMode || isPreview} - css={css` - margin-left: ${euiTheme.size.xs}; - `} - aria-label={ADD_NOTE_BUTTON} - data-test-subj={NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID} - /> + {kibanaSecuritySolutionsPrivileges.crud ? addNoteButtonIcon : viewNotesButton} </EuiFlexItem> </EuiFlexGroup> )} diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx index 8de7c909548b..ee680f106162 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/table_field_value_cell.test.tsx @@ -22,11 +22,6 @@ import { createTelemetryServiceMock } from '../../../../common/lib/telemetry/tel jest.mock('@kbn/expandable-flyout', () => ({ useExpandableFlyoutApi: jest.fn(), ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}</>, - withExpandableFlyoutProvider: <T extends object>(Component: React.ComponentType<T>) => { - return (props: T) => { - return <Component {...props} />; - }; - }, })); const mockedTelemetry = createTelemetryServiceMock(); diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts index 959f8f106bb0..78afeb19e0b8 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts +++ b/x-pack/plugins/security_solution/public/flyout/document_details/right/components/test_ids.ts @@ -35,6 +35,8 @@ export const CHAT_BUTTON_TEST_ID = 'newChatByTitle' as const; export const NOTES_TITLE_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesTitle` as const; export const NOTES_ADD_NOTE_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesAddNoteButton` as const; +export const NOTES_VIEW_NOTES_BUTTON_TEST_ID = + `${FLYOUT_HEADER_TEST_ID}NotesViewNotesButton` as const; export const NOTES_ADD_NOTE_ICON_BUTTON_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesAddNoteIconButton` as const; export const NOTES_COUNT_TEST_ID = `${FLYOUT_HEADER_TEST_ID}NotesCount` as const; diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx index e7ebb371fb02..6ccada3134f9 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/misconfiguration_insight.tsx @@ -10,7 +10,7 @@ import { EuiFlexItem, type EuiFlexGroupProps, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/css'; import { useMisconfigurationPreview } from '@kbn/cloud-security-posture/src/hooks/use_misconfiguration_preview'; -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { buildGenericEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { MISCONFIGURATION_INSIGHT, uiMetricService, @@ -58,7 +58,7 @@ export const MisconfigurationsInsight: React.FC<MisconfigurationsInsightProps> = const { scopeId, isPreview } = useDocumentDetailsContext(); const { euiTheme } = useEuiTheme(); const { data } = useMisconfigurationPreview({ - query: buildEntityFlyoutPreviewQuery(fieldName, name), + query: buildGenericEntityFlyoutPreviewQuery(fieldName, name), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx index 1dab4660194b..8991124a77e2 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/components/vulnerabilities_insight.tsx @@ -10,7 +10,7 @@ import { EuiFlexItem, type EuiFlexGroupProps, useEuiTheme } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { css } from '@emotion/css'; import { useVulnerabilitiesPreview } from '@kbn/cloud-security-posture/src/hooks/use_vulnerabilities_preview'; -import { buildEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; +import { buildGenericEntityFlyoutPreviewQuery } from '@kbn/cloud-security-posture-common'; import { getVulnerabilityStats, hasVulnerabilitiesData } from '@kbn/cloud-security-posture'; import { uiMetricService, @@ -53,7 +53,7 @@ export const VulnerabilitiesInsight: React.FC<VulnerabilitiesInsightProps> = ({ const { scopeId, isPreview } = useDocumentDetailsContext(); const { euiTheme } = useEuiTheme(); const { data } = useVulnerabilitiesPreview({ - query: buildEntityFlyoutPreviewQuery('host.name', hostName), + query: buildGenericEntityFlyoutPreviewQuery('host.name', hostName), sort: [], enabled: true, pageSize: 1, diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/threat_intelligence.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/threat_intelligence.tsx index 2f5bd6510430..fefacf3e7fc1 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/threat_intelligence.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/shared/utils/threat_intelligence.tsx @@ -7,11 +7,11 @@ import { groupBy, isObject } from 'lodash'; import type { TimelineEventsDetailsItem } from '@kbn/timelines-plugin/common'; +import { getDataFromFieldsHits } from '@kbn/timelines-plugin/common'; import { i18n } from '@kbn/i18n'; import type { ThreatDetailsRow } from '../../left/components/threat_details_view_enrichment_accordion'; import type { CtiEnrichment, EventFields } from '../../../../../common/search_strategy'; import { isValidEventField } from '../../../../../common/search_strategy'; -import { getDataFromFieldsHits } from '../../../../../common/utils/field_formatters'; import { DEFAULT_INDICATOR_SOURCE_PATH, ENRICHMENT_DESTINATION_PATH, diff --git a/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.test.tsx b/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.test.tsx index c1dfc456f40c..f1dedc18d3b1 100644 --- a/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.test.tsx +++ b/x-pack/plugins/security_solution/public/flyout/shared/components/preview_link.test.tsx @@ -34,11 +34,6 @@ jest.mock('../../../common/lib/kibana', () => { jest.mock('@kbn/expandable-flyout', () => ({ useExpandableFlyoutApi: jest.fn(), ExpandableFlyoutProvider: ({ children }: React.PropsWithChildren<{}>) => <>{children}</>, - withExpandableFlyoutProvider: <T extends object>(Component: React.ComponentType<T>) => { - return (props: T) => { - return <Component {...props} />; - }; - }, })); const renderPreviewLink = (field: string, value: string, dataTestSuj?: string) => diff --git a/x-pack/plugins/security_solution/public/kubernetes/routes.tsx b/x-pack/plugins/security_solution/public/kubernetes/routes.tsx index 67bd4a9fcad8..7520de8cffa5 100644 --- a/x-pack/plugins/security_solution/public/kubernetes/routes.tsx +++ b/x-pack/plugins/security_solution/public/kubernetes/routes.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { TrackApplicationView } from '@kbn/usage-collection-plugin/public'; +import { allowedExperimentalValues } from '../../common'; import { KubernetesContainer } from './pages'; import type { SecuritySubPluginRoutes } from '../app/types'; @@ -24,7 +25,7 @@ export const KubernetesRoutes = () => ( export const routes: SecuritySubPluginRoutes = [ { - path: KUBERNETES_PATH, + path: allowedExperimentalValues.kubernetesEnabled ? KUBERNETES_PATH : [], component: KubernetesRoutes, }, ]; diff --git a/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_flyout.test.tsx b/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_flyout.test.tsx index 83b868219010..66f372b7903b 100644 --- a/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_flyout.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/artifact_list_page/components/artifact_flyout.test.tsx @@ -47,9 +47,9 @@ describe('When the flyout is opened in the ArtifactListPage component', () => { render = async (props = {}) => { renderResult = renderSetup.renderArtifactListPage(props); - await waitFor(async () => { - expect(renderResult.getByTestId('testPage-flyout')); - }); + await waitFor(async () => + expect(renderResult.getByTestId('testPage-flyout')).toBeInTheDocument() + ); return renderResult; }; diff --git a/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/console_manager.tsx b/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/console_manager.tsx index deb6967da2c2..7d85f5c11575 100644 --- a/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/console_manager.tsx +++ b/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/console_manager.tsx @@ -113,13 +113,9 @@ export const ConsoleManager = memo<ConsoleManagerProps>(({ storage = {}, childre validateIdOrThrow(id); setConsoleStorage((prevState) => { - return { - ...prevState, - [id]: { - ...prevState[id], - isOpen: false, - }, - }; + const newState = { ...prevState }; + newState[id].isOpen = false; + return newState; }); }, [validateIdOrThrow] // << IMPORTANT: this callback should have only immutable dependencies diff --git a/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/integration_tests/console_manager.test.tsx b/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/integration_tests/console_manager.test.tsx index 8cf7b94f9bcd..912b96b4406c 100644 --- a/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/integration_tests/console_manager.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/console/components/console_manager/integration_tests/console_manager.test.tsx @@ -5,8 +5,6 @@ * 2.0. */ -import type { RenderHookResult } from '@testing-library/react-hooks'; -import { renderHook as _renderHook, act } from '@testing-library/react-hooks'; import { useConsoleManager } from '../console_manager'; import React from 'react'; import type { @@ -22,12 +20,13 @@ import { getNewConsoleRegistrationMock, } from '../mocks'; import userEvent, { type UserEvent } from '@testing-library/user-event'; -import { waitFor } from '@testing-library/react'; +import type { RenderHookResult } from '@testing-library/react'; +import { waitFor, act, renderHook as _renderHook } from '@testing-library/react'; import { enterConsoleCommand } from '../../../mocks'; describe('When using ConsoleManager', () => { describe('and using the ConsoleManagerInterface via the hook', () => { - type RenderResultInterface = RenderHookResult<never, ConsoleManagerClient>; + type RenderResultInterface = RenderHookResult<ConsoleManagerClient, never>; let renderHook: () => RenderResultInterface; let renderResult: RenderResultInterface; @@ -103,20 +102,27 @@ describe('When using ConsoleManager', () => { ); }); - it('should hide a console by `id`', () => { + it('should hide a console by `id`', async () => { renderHook(); const { id: consoleId } = registerNewConsole(); + + let consoleClient: ReturnType<ConsoleManagerClient['getOne']>; + + act(() => { + consoleClient = renderResult.result.current.getOne(consoleId); + }); + act(() => { renderResult.result.current.show(consoleId); }); - expect(renderResult.result.current.getOne(consoleId)!.isVisible()).toBe(true); + await waitFor(() => expect(consoleClient!.isVisible()).toBe(true)); act(() => { renderResult.result.current.hide(consoleId); }); - expect(renderResult.result.current.getOne(consoleId)!.isVisible()).toBe(false); + await waitFor(() => expect(consoleClient!.isVisible()).toBe(false)); }); it('should throw if attempting to hide a console with invalid `id`', () => { @@ -163,7 +169,9 @@ describe('When using ConsoleManager', () => { beforeEach(() => { renderHook(); ({ id: consoleId } = registerNewConsole()); - registeredConsole = renderResult.result.current.getOne(consoleId)!; + act(() => { + registeredConsole = renderResult.result.current.getOne(consoleId)!; + }); }); it('should have the expected interface', () => { @@ -178,27 +186,31 @@ describe('When using ConsoleManager', () => { }); it('should display the console when `.show()` is called', async () => { - registeredConsole.show(); - await renderResult.waitForNextUpdate(); - - expect(registeredConsole.isVisible()).toBe(true); + act(() => { + registeredConsole.show(); + }); + await waitFor(() => expect(registeredConsole.isVisible()).toBe(true)); }); it('should hide the console when `.hide()` is called', async () => { - registeredConsole.show(); - await renderResult.waitForNextUpdate(); - expect(registeredConsole.isVisible()).toBe(true); + act(() => { + registeredConsole.show(); + }); - registeredConsole.hide(); - await renderResult.waitForNextUpdate(); - expect(registeredConsole.isVisible()).toBe(false); + await waitFor(() => expect(registeredConsole.isVisible()).toBe(true)); + + act(() => { + registeredConsole.hide(); + }); + + await waitFor(() => expect(registeredConsole.isVisible()).toBe(false)); }); it('should un-register the console when `.terminate() is called', async () => { - registeredConsole.terminate(); - await renderResult.waitForNextUpdate(); - - expect(renderResult.result.current.getOne(consoleId)).toBeUndefined(); + act(() => { + registeredConsole.terminate(); + }); + await waitFor(() => expect(renderResult.result.current.getOne(consoleId)).toBeUndefined()); }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/execute_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/execute_action.test.tsx index 7e2a5bf62223..cd125348a688 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/execute_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/execute_action.test.tsx @@ -73,6 +73,7 @@ describe('When using execute action from response actions console', () => { endpointAgentId: 'a.b.c', endpointCapabilities: [...capabilities], endpointPrivileges, + platform: 'linux', }), }, }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_file_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_file_action.test.tsx index 101c24c84e67..11fa0213394c 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_file_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_file_action.test.tsx @@ -71,6 +71,7 @@ describe('When using get-file action from response actions console', () => { endpointAgentId: 'a.b.c', endpointCapabilities: [...ENDPOINT_CAPABILITIES], endpointPrivileges, + platform: 'linux', }; render = async (capabilities: EndpointCapabilities[] = [...ENDPOINT_CAPABILITIES]) => { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx index d1922a7bf6e5..48a837a57443 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/get_processes_action.test.tsx @@ -59,6 +59,7 @@ describe('When using processes action from response actions console', () => { canSuspendProcess: true, canGetRunningProcesses: true, }, + platform: 'linux', }); }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/isolate_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/isolate_action.test.tsx index b022fe15d5ed..d702bfca9945 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/isolate_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/isolate_action.test.tsx @@ -67,6 +67,7 @@ describe('When using isolate action from response actions console', () => { loading: false, canIsolateHost: true, }, + platform: 'linux', }), }, }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/kill_process_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/kill_process_action.test.tsx index f1cf6937eef0..5f4a40b50d8a 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/kill_process_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/kill_process_action.test.tsx @@ -63,6 +63,7 @@ describe.skip('When using the kill-process action from response actions console' canSuspendProcess: true, canGetRunningProcesses: true, }, + platform: 'linux', }); }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/release_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/release_action.test.tsx index 75278dd0f2c0..8e98d0524794 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/release_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/release_action.test.tsx @@ -46,6 +46,7 @@ const prepareTest = () => { canUnIsolateHost: true, loading: false, }, + platform: 'linux', }), }, }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/scan_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/scan_action.test.tsx index e0fde4a2133d..f82ad0aa19b6 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/scan_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/scan_action.test.tsx @@ -83,6 +83,7 @@ describe('When using scan action from response actions console', () => { endpointAgentId: 'agent-a', endpointCapabilities: [...ENDPOINT_CAPABILITIES], endpointPrivileges, + platform: 'linux', }; render = async (capabilities: EndpointCapabilities[] = [...ENDPOINT_CAPABILITIES]) => { diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/status_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/status_action.test.tsx index 47f1c0b9a47e..b1367ee132ee 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/status_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/status_action.test.tsx @@ -111,6 +111,7 @@ describe.skip('When using processes action from response actions console', () => ...getEndpointAuthzInitialState(), loading: false, }, + platform: 'linux', }), }, }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/suspend_process_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/suspend_process_action.test.tsx index 1492acd86287..dd69a31ad36e 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/suspend_process_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/suspend_process_action.test.tsx @@ -73,6 +73,7 @@ describe('When using the suspend-process action from response actions console', canSuspendProcess: true, canGetRunningProcesses: true, }, + platform: 'linux', }), }, }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/upload_action.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/upload_action.test.tsx index a6493430615f..ced1ea4d0e0a 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/upload_action.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/integration_tests/upload_action.test.tsx @@ -88,6 +88,7 @@ describe.skip('When using `upload` response action', () => { endpointAgentId: 'a.b.c', endpointCapabilities, endpointPrivileges, + platform: 'linux', }), }, }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts index c81674bd4f7b..efc52fd59c32 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/console_commands_definition.ts @@ -153,6 +153,8 @@ export interface GetEndpointConsoleCommandsOptions { /** Applicable only for Endpoint Agents */ endpointCapabilities: ImmutableArray<string>; endpointPrivileges: EndpointPrivileges; + /** Host's platform: windows, linux, macos */ + platform: string; } export const getEndpointConsoleCommands = ({ @@ -160,6 +162,7 @@ export const getEndpointConsoleCommands = ({ agentType, endpointCapabilities, endpointPrivileges, + platform, }: GetEndpointConsoleCommandsOptions): CommandDefinition[] => { const featureFlags = ExperimentalFeaturesService.get(); @@ -523,7 +526,7 @@ export const getEndpointConsoleCommands = ({ switch (agentType) { case 'sentinel_one': - return adjustCommandsForSentinelOne({ commandList: consoleCommands }); + return adjustCommandsForSentinelOne({ commandList: consoleCommands, platform }); case 'crowdstrike': return adjustCommandsForCrowdstrike({ commandList: consoleCommands }); default: @@ -543,8 +546,10 @@ const disableCommand = (command: CommandDefinition, agentType: ResponseActionAge /** @private */ const adjustCommandsForSentinelOne = ({ commandList, + platform, }: { commandList: CommandDefinition[]; + platform: string; }): CommandDefinition[] => { const featureFlags = ExperimentalFeaturesService.get(); const isKillProcessEnabled = featureFlags.responseActionsSentinelOneKillProcessEnabled; @@ -580,6 +585,28 @@ const adjustCommandsForSentinelOne = ({ ) ) { disableCommand(command, 'sentinel_one'); + } else { + // processes is not currently supported for Windows hosts + if (command.name === 'processes' && platform.toLowerCase() === 'windows') { + const message = i18n.translate( + 'xpack.securitySolution.consoleCommandsDefinition.sentineloneProcessesWindowRestriction', + { + defaultMessage: + 'Processes command is not currently supported for SentinelOne hosts running on Windows', + } + ); + + command.helpDisabled = true; + command.about = getCommandAboutInfo({ + aboutInfo: command.about, + isSupported: false, + dataTestSubj: 'sentineloneProcessesWindowsWarningTooltip', + tooltipContent: message, + }); + command.validate = () => { + return message; + }; + } } return command; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/get_command_about_info.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/get_command_about_info.tsx index ddb5e345acc2..2b22d0067dc5 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/get_command_about_info.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/get_command_about_info.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import type { EuiToolTipProps } from '@elastic/eui'; import { EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -17,23 +18,28 @@ const UNSUPPORTED_COMMAND_INFO = i18n.translate( } ); -const DisabledTooltip = React.memo(() => { - return <EuiIconTip content={UNSUPPORTED_COMMAND_INFO} type="warning" color="danger" />; -}); -DisabledTooltip.displayName = 'DisabledTooltip'; - export const getCommandAboutInfo = ({ aboutInfo, isSupported, + tooltipContent = UNSUPPORTED_COMMAND_INFO, + dataTestSubj, }: { - aboutInfo: string; + aboutInfo: React.ReactNode; isSupported: boolean; + tooltipContent?: EuiToolTipProps['content']; + dataTestSubj?: string; }) => { return isSupported ? ( aboutInfo ) : ( <> - {aboutInfo} <DisabledTooltip /> + {aboutInfo}{' '} + <EuiIconTip + anchorProps={{ 'data-test-subj': dataTestSubj }} + content={tooltipContent} + type="warning" + color="danger" + /> </> ); }; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx index 7c1e5cf118df..caf33de458f8 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/lib/integration_tests/console_commands_definition.test.tsx @@ -52,6 +52,7 @@ describe('When displaying Endpoint Response Actions', () => { endpointAgentId: '123', endpointCapabilities: endpointMetadata.Endpoint.capabilities ?? [], endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + platform: 'linux', }); }); @@ -89,6 +90,8 @@ describe('When displaying Endpoint Response Actions', () => { responseActionsCrowdstrikeManualHostIsolationEnabled: true, responseActionsSentinelOneV1Enabled: true, responseActionsSentinelOneGetFileEnabled: true, + responseActionsSentinelOneKillProcessEnabled: true, + responseActionsSentinelOneProcessesEnabled: true, }); commands = getEndpointConsoleCommands({ @@ -96,6 +99,7 @@ describe('When displaying Endpoint Response Actions', () => { endpointAgentId: '123', endpointCapabilities: endpointMetadata.Endpoint.capabilities ?? [], endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + platform: 'linux', }); }); @@ -110,13 +114,34 @@ describe('When displaying Endpoint Response Actions', () => { }); it('should display response action commands in the help panel in expected order', () => { - render({ commands }); + const { queryByTestId } = render({ commands }); consoleSelectors.openHelpPanel(); const commandsInPanel = helpPanelSelectors.getHelpCommandNames( HELP_GROUPS.responseActions.label ); - expect(commandsInPanel).toEqual(['isolate', 'release', 'get-file --path']); + expect(commandsInPanel).toEqual([ + 'isolate', + 'release', + 'processes', + 'kill-process --processName', + 'get-file --path', + ]); + expect(queryByTestId('sentineloneProcessesWindowsWarningTooltip')).toBeNull(); + }); + + it('should display warning icon on processes command if host is running on windows', () => { + commands = getEndpointConsoleCommands({ + agentType: 'sentinel_one', + endpointAgentId: '123', + endpointCapabilities: endpointMetadata.Endpoint.capabilities ?? [], + endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + platform: 'windows', + }); + const { getByTestId } = render({ commands }); + consoleSelectors.openHelpPanel(); + + expect(getByTestId('sentineloneProcessesWindowsWarningTooltip')).not.toBeNull(); }); }); @@ -130,6 +155,7 @@ describe('When displaying Endpoint Response Actions', () => { endpointAgentId: '123', endpointCapabilities: endpointMetadata.Endpoint.capabilities ?? [], endpointPrivileges: getEndpointPrivilegesInitialStateMock(), + platform: 'linux', }); }); diff --git a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts index 03d9ab659016..51530fd0d7a7 100644 --- a/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts +++ b/x-pack/plugins/security_solution/public/management/cypress/tasks/response_actions.ts @@ -80,7 +80,7 @@ export const fillUpNewEsqlRule = (name = 'Test', description = 'Test', query: st cy.getByTestSubj('create-new-rule').click(); cy.getByTestSubj('stepDefineRule').within(() => { cy.getByTestSubj('esqlRuleType').click(); - cy.getByTestSubj('detectionEngineStepDefineRuleEsqlQueryBar').within(() => { + cy.getByTestSubj('ruleEsqlQueryBar').within(() => { cy.getByTestSubj('globalQueryBar').click(); cy.getByTestSubj('kibanaCodeEditor').type(query); }); diff --git a/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.test.ts b/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.test.ts index 300fd11a700a..ce8bb96a2c08 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.test.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/agents/use_get_agent_status.test.ts @@ -10,14 +10,15 @@ import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; import { useGetAgentStatus } from './use_get_agent_status'; import { agentStatusGetHttpMock } from '../../mocks'; import { AGENT_STATUS_ROUTE } from '../../../../common/endpoint/constants'; -import type { RenderHookResult } from '@testing-library/react-hooks/src/types'; +import type { RenderHookResult } from '@testing-library/react'; +import { waitFor } from '@testing-library/react'; describe('useGetAgentStatus hook', () => { let httpMock: AppContextTestRender['coreStart']['http']; let agentIdsProp: Parameters<typeof useGetAgentStatus>[0]; let optionsProp: Parameters<typeof useGetAgentStatus>[2]; let apiMock: ReturnType<typeof agentStatusGetHttpMock>; - let renderHook: () => RenderHookResult<unknown, ReturnType<typeof useGetAgentStatus>>; + let renderHook: () => RenderHookResult<ReturnType<typeof useGetAgentStatus>, unknown>; beforeEach(() => { const appTestContext = createAppRootMockRenderer(); @@ -25,7 +26,7 @@ describe('useGetAgentStatus hook', () => { httpMock = appTestContext.coreStart.http; apiMock = agentStatusGetHttpMock(httpMock); renderHook = () => { - return appTestContext.renderHook<unknown, ReturnType<typeof useGetAgentStatus>>(() => + return appTestContext.renderHook(() => useGetAgentStatus(agentIdsProp, 'endpoint', optionsProp) ); }; @@ -63,28 +64,28 @@ describe('useGetAgentStatus hook', () => { }); it('should return expected data', async () => { - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current); - - expect(result.current.data).toEqual({ - '1-2-3': { - agentId: '1-2-3', - agentType: 'endpoint', - found: true, - isolated: false, - lastSeen: expect.any(String), - pendingActions: {}, - status: 'healthy', - }, - }); + const { result } = renderHook(); + await waitFor(() => + expect(result.current.data).toEqual({ + '1-2-3': { + agentId: '1-2-3', + agentType: 'endpoint', + found: true, + isolated: false, + lastSeen: expect.any(String), + pendingActions: {}, + status: 'healthy', + }, + }) + ); }); it('should NOT call agent status api if list of agent ids is empty', async () => { agentIdsProp = ['', ' ']; - const { result, waitForValueToChange } = renderHook(); - await waitForValueToChange(() => result.current); - - expect(result.current.data).toEqual({}); - expect(apiMock.responseProvider.getAgentStatus).not.toHaveBeenCalled(); + const { result } = renderHook(); + await waitFor(() => { + expect(result.current.data).toEqual({}); + expect(apiMock.responseProvider.getAgentStatus).not.toHaveBeenCalled(); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_delete_artifact.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_delete_artifact.test.tsx index 403731566ef3..2c6c6ff92003 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_delete_artifact.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_delete_artifact.test.tsx @@ -15,7 +15,7 @@ import { renderMutation, } from '../test_utils'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { act } from '@testing-library/react-hooks'; +import { act } from '@testing-library/react'; const apiVersion = '2023-10-31'; diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_update_artifact.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_update_artifact.test.tsx index 5db9734c61f9..24f142773ae5 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_update_artifact.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_bulk_update_artifact.test.tsx @@ -15,7 +15,7 @@ import { renderMutation, } from '../test_utils'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { act } from '@testing-library/react-hooks'; +import { act } from '@testing-library/react'; const apiVersion = '2023-10-31'; diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_create_artifact.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_create_artifact.test.tsx index 853ea0df96a3..71d88d373227 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_create_artifact.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_create_artifact.test.tsx @@ -15,7 +15,7 @@ import { renderMutation, } from '../test_utils'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { act } from '@testing-library/react-hooks'; +import { act } from '@testing-library/react'; describe('Create artifact hook', () => { let result: ReturnType<typeof useCreateArtifact>; diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_delete_artifact.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_delete_artifact.test.tsx index 9473a50fa8a3..f988494bdceb 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_delete_artifact.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_delete_artifact.test.tsx @@ -15,7 +15,7 @@ import { renderMutation, } from '../test_utils'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { act } from '@testing-library/react-hooks'; +import { act } from '@testing-library/react'; describe('Delete artifact hook', () => { let result: ReturnType<typeof useDeleteArtifact>; diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_get_updated_tags.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_get_updated_tags.test.tsx index 0fb481a489c2..1461f68fd1aa 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_get_updated_tags.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_get_updated_tags.test.tsx @@ -6,7 +6,7 @@ */ import { useGetUpdatedTags } from '.'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; import type { TagFilter } from '../../../../common/endpoint/service/artifacts/utils'; diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_host_isolation_exceptions_access.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_host_isolation_exceptions_access.test.tsx index 2bd673f68095..8cf4c30cdda7 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_host_isolation_exceptions_access.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_host_isolation_exceptions_access.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook, waitFor } from '@testing-library/react'; import { useHostIsolationExceptionsAccess } from './use_host_isolation_exceptions_access'; import { checkArtifactHasData } from '../../services/exceptions_list/check_artifact_has_data'; @@ -29,7 +29,7 @@ describe('useHostIsolationExceptionsAccess', () => { }; test('should set access to true if canAccessHostIsolationExceptions is true', async () => { - const { result, waitFor } = setupHook(true, false); + const { result } = setupHook(true, false); await waitFor(() => expect(result.current.hasAccessToHostIsolationExceptions).toBe(true)); }); @@ -37,7 +37,7 @@ describe('useHostIsolationExceptionsAccess', () => { test('should check for artifact data if canReadHostIsolationExceptions is true and canAccessHostIsolationExceptions is false', async () => { mockArtifactHasData(); - const { result, waitFor } = setupHook(false, true); + const { result } = setupHook(false, true); await waitFor(() => { expect(checkArtifactHasData).toHaveBeenCalledWith(mockApiClient()); @@ -48,7 +48,7 @@ describe('useHostIsolationExceptionsAccess', () => { test('should set access to false if canReadHostIsolationExceptions is true but no artifact data exists', async () => { mockArtifactHasData(false); - const { result, waitFor } = setupHook(false, true); + const { result } = setupHook(false, true); await waitFor(() => { expect(checkArtifactHasData).toHaveBeenCalledWith(mockApiClient()); @@ -57,14 +57,14 @@ describe('useHostIsolationExceptionsAccess', () => { }); test('should set access to false if neither canAccessHostIsolationExceptions nor canReadHostIsolationExceptions is true', async () => { - const { result, waitFor } = setupHook(false, false); + const { result } = setupHook(false, false); await waitFor(() => { expect(result.current.hasAccessToHostIsolationExceptions).toBe(false); }); }); test('should not call checkArtifactHasData if canAccessHostIsolationExceptions is true', async () => { - const { result, waitFor } = setupHook(true, true); + const { result } = setupHook(true, true); await waitFor(() => { expect(checkArtifactHasData).not.toHaveBeenCalled(); @@ -73,7 +73,7 @@ describe('useHostIsolationExceptionsAccess', () => { }); test('should set loading state correctly while checking access', async () => { - const { result, waitFor } = setupHook(false, true); + const { result } = setupHook(false, true); expect(result.current.isHostIsolationExceptionsAccessLoading).toBe(true); diff --git a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_update_artifact.test.tsx b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_update_artifact.test.tsx index 14607a33f209..4c932812c8c0 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_update_artifact.test.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/artifacts/use_update_artifact.test.tsx @@ -15,7 +15,7 @@ import { renderMutation, } from '../test_utils'; import { getExceptionListItemSchemaMock } from '@kbn/lists-plugin/common/schemas/response/exception_list_item_schema.mock'; -import { act } from '@testing-library/react-hooks'; +import { act } from '@testing-library/react'; describe('Update artifact hook', () => { let result: ReturnType<typeof useUpdateArtifact>; diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_details.test.ts b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_details.test.ts index b82f25f1bf86..84fcc89f36dc 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_details.test.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoint_details.test.ts @@ -27,7 +27,7 @@ jest.mock('@tanstack/react-query', () => { // FLAKY: https://github.com/elastic/kibana/issues/192435 describe.skip('useGetEndpointDetails hook', () => { let renderReactQueryHook: ReactQueryHookRenderer< - Parameters<typeof useGetEndpointDetails>, + Parameters<typeof useGetEndpointDetails>[number], ReturnType<typeof useGetEndpointDetails> >; let http: AppContextTestRender['coreStart']['http']; diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.test.ts b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.test.ts index d7f073b2a833..3c9ed815536d 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.test.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.test.ts @@ -7,7 +7,7 @@ import type { AppContextTestRender, ReactQueryHookRenderer } from '../../../common/mock/endpoint'; import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; -import { useGetEndpointsList } from './use_get_endpoints_list'; +import { useGetEndpointsList, PAGING_PARAMS } from './use_get_endpoints_list'; import { HOST_METADATA_LIST_ROUTE } from '../../../../common/endpoint/constants'; import { useQuery as _useQuery } from '@tanstack/react-query'; import { endpointMetadataHttpMocks } from '../../pages/endpoint_hosts/mocks'; @@ -117,13 +117,15 @@ describe('useGetEndpointsList hook', () => { it('should also list inactive agents', async () => { const getApiResponse = apiMocks.responseProvider.metadataList.getMockImplementation(); + const inActiveIndex = [0, 1, 3]; + // set a few of the agents as inactive/unenrolled apiMocks.responseProvider.metadataList.mockImplementation(() => { if (getApiResponse) { return { ...getApiResponse(), data: getApiResponse().data.map((item, i) => { - const isInactiveIndex = [0, 1, 3].includes(i); + const isInactiveIndex = inActiveIndex.includes(i); return { ...item, host_status: isInactiveIndex ? HostStatus.INACTIVE : item.host_status, @@ -154,7 +156,7 @@ describe('useGetEndpointsList hook', () => { const res = await renderReactQueryHook(() => useGetEndpointsList({ searchString: 'inactive' })); expect( res.data?.map((host) => host.name.split('-')[2]).filter((name) => name === 'inactive').length - ).toEqual(3); + ).toEqual(inActiveIndex.length); }); it('should only list 50 agents when more than 50 in the metadata list API', async () => { @@ -192,7 +194,7 @@ describe('useGetEndpointsList hook', () => { // verify useGetEndpointsList hook returns all 50 agents in the list const res = await renderReactQueryHook(() => useGetEndpointsList({ searchString: '' })); - expect(res.data?.length).toEqual(50); + expect(res.data?.length).toEqual(PAGING_PARAMS.default); }); it('should only list 10 more agents when 50 or more agents are already selected', async () => { @@ -232,7 +234,7 @@ describe('useGetEndpointsList hook', () => { const agentIdsToSelect = apiMocks.responseProvider .metadataList() .data.map((d) => d.metadata.agent.id) - .slice(0, 50); + .slice(0, PAGING_PARAMS.default); // call useGetEndpointsList with all 50 agents selected const res = await renderReactQueryHook(() => diff --git a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.ts b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.ts index 632b7d8ff48a..b0072d73b832 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/endpoint/use_get_endpoints_list.ts @@ -18,7 +18,7 @@ type GetEndpointsListResponse = Array<{ selected: boolean; }>; -const PAGING_PARAMS = Object.freeze({ +export const PAGING_PARAMS = Object.freeze({ default: 50, all: 10000, }); diff --git a/x-pack/plugins/security_solution/public/management/hooks/policy/use_update_endpoint_policy.test.ts b/x-pack/plugins/security_solution/public/management/hooks/policy/use_update_endpoint_policy.test.ts index 8b6be08b41b4..6d27b5ccf447 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/policy/use_update_endpoint_policy.test.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/policy/use_update_endpoint_policy.test.ts @@ -13,7 +13,7 @@ import type { UseUpdateEndpointPolicyOptions, UseUpdateEndpointPolicyResult, } from './use_update_endpoint_policy'; -import type { RenderHookResult } from '@testing-library/react-hooks/src/types'; +import type { RenderHookResult } from '@testing-library/react'; import { useUpdateEndpointPolicy } from './use_update_endpoint_policy'; import type { PolicyData } from '../../../../common/endpoint/types'; import { FleetPackagePolicyGenerator } from '../../../../common/endpoint/data_generators/fleet_package_policy_generator'; @@ -37,8 +37,8 @@ describe('When using the `useFetchEndpointPolicyAgentSummary()` hook', () => { let apiMocks: ReturnType<typeof allFleetHttpMocks>; let policy: PolicyData; let renderHook: () => RenderHookResult< - UseUpdateEndpointPolicyOptions, - UseUpdateEndpointPolicyResult + UseUpdateEndpointPolicyResult, + UseUpdateEndpointPolicyOptions >; beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_scan_request.test.ts b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_scan_request.test.ts index f5b3f20d21d8..b6afc01e131a 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_scan_request.test.ts +++ b/x-pack/plugins/security_solution/public/management/hooks/response_actions/use_send_scan_request.test.ts @@ -7,7 +7,7 @@ import { useMutation as _useMutation } from '@tanstack/react-query'; import type { AppContextTestRender } from '../../../common/mock/endpoint'; -import type { RenderHookResult } from '@testing-library/react-hooks/src/types'; +import type { RenderHookResult } from '@testing-library/react'; import { createAppRootMockRenderer } from '../../../common/mock/endpoint'; import { responseActionsHttpMocks } from '../../mocks/response_actions_http_mocks'; import { @@ -38,7 +38,7 @@ describe('When using the `useSendScanRequest()` hook', () => { let customOptions: ScanRequestCustomOptions; let http: AppContextTestRender['coreStart']['http']; let apiMocks: ReturnType<typeof responseActionsHttpMocks>; - let renderHook: () => RenderHookResult<ScanRequestCustomOptions, UseSendScanRequestResult>; + let renderHook: () => RenderHookResult<UseSendScanRequestResult, ScanRequestCustomOptions>; beforeEach(() => { const testContext = createAppRootMockRenderer(); diff --git a/x-pack/plugins/security_solution/public/management/hooks/test_utils.tsx b/x-pack/plugins/security_solution/public/management/hooks/test_utils.tsx index 149eee55872a..cc674610bbae 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/test_utils.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/test_utils.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import type { HttpSetup } from '@kbn/core/public'; import type { CreateExceptionListSchema } from '@kbn/securitysolution-io-ts-list-types'; import { coreMock } from '@kbn/core/public/mocks'; @@ -39,10 +39,10 @@ export const renderQuery = async ( const wrapper = ({ children }: { children: React.ReactNode }): JSX.Element => ( <ReactQueryClientProvider>{children}</ReactQueryClientProvider> ); - const { result: resultHook, waitFor } = renderHook(() => hook(), { + const { result: resultHook } = renderHook(() => hook(), { wrapper, }); - await waitFor(() => resultHook.current[waitForHook]); + await waitFor(() => expect(resultHook.current[waitForHook]).toBeTruthy()); return resultHook.current; }; @@ -58,3 +58,5 @@ export const renderMutation = async ( }); return resultHook.current; }; + +export const renderWrappedHook = renderMutation; diff --git a/x-pack/plugins/security_solution/public/management/hooks/use_with_show_responder.tsx b/x-pack/plugins/security_solution/public/management/hooks/use_with_show_responder.tsx index f7622681112b..e3e830efcb04 100644 --- a/x-pack/plugins/security_solution/public/management/hooks/use_with_show_responder.tsx +++ b/x-pack/plugins/security_solution/public/management/hooks/use_with_show_responder.tsx @@ -71,6 +71,7 @@ export const useWithShowResponder = (): ShowResponseActionsConsole => { endpointAgentId: agentId, endpointCapabilities: capabilities, endpointPrivileges, + platform, }), 'data-test-subj': `${agentType}ResponseActionsConsole`, storagePrefix: 'xpack.securitySolution.Responder', diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights.tsx new file mode 100644 index 000000000000..1ee7600eda2e --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights.tsx @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EuiHorizontalRule, EuiAccordion, EuiSpacer, EuiText } from '@elastic/eui'; +import React from 'react'; +import { WorkflowInsightsResults } from './workflow_insights_results'; +import { WorkflowInsightsScanSection } from './workflow_insights_scan'; +import { useIsExperimentalFeatureEnabled } from '../../../../../../../common/hooks/use_experimental_features'; +import { WORKFLOW_INSIGHTS } from '../../../translations'; + +export const WorkflowInsights = () => { + const isWorkflowInsightsEnabled = useIsExperimentalFeatureEnabled('defendInsights'); + + if (!isWorkflowInsightsEnabled) { + return null; + } + + const results = null; + + const renderLastResultsCaption = () => { + if (!results) { + return null; + } + return ( + <EuiText color={'subdued'} size={'xs'}> + {WORKFLOW_INSIGHTS.titleRight} + </EuiText> + ); + }; + + return ( + <> + <EuiAccordion + id={'workflow-insights-wrapper'} + buttonContent={ + <EuiText size={'m'}> + <h4>{WORKFLOW_INSIGHTS.title}</h4> + </EuiText> + } + initialIsOpen + extraAction={renderLastResultsCaption()} + paddingSize={'none'} + > + <EuiSpacer size={'m'} /> + <WorkflowInsightsScanSection /> + <EuiSpacer size={'m'} /> + <WorkflowInsightsResults results={true} /> + <EuiHorizontalRule /> + </EuiAccordion> + <EuiSpacer size="l" /> + </> + ); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_results.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_results.tsx new file mode 100644 index 000000000000..cb2f0bc0889a --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_results.tsx @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { + EuiButtonIcon, + EuiCallOut, + EuiFlexGroup, + EuiFlexItem, + EuiIcon, + EuiPanel, + EuiSpacer, + EuiText, +} from '@elastic/eui'; +import { WORKFLOW_INSIGHTS } from '../../../translations'; + +interface WorkflowInsightsResultsProps { + results: boolean; +} + +const CustomEuiCallOut = styled(EuiCallOut)` + & .euiButtonIcon { + margin-top: 5px; /* Lower the close button */ + } +`; + +export const WorkflowInsightsResults = ({ results }: WorkflowInsightsResultsProps) => { + const [showEmptyResultsCallout, setShowEmptyResultsCallout] = useState(true); + const hideEmptyStateCallout = () => setShowEmptyResultsCallout(false); + if (!results) { + return null; + } + + return ( + <> + <EuiText size={'s'}> + <h4>{WORKFLOW_INSIGHTS.issues.title}</h4> + </EuiText> + <EuiSpacer size={'s'} /> + <EuiPanel paddingSize="m" hasShadow={false} hasBorder> + <EuiFlexGroup alignItems={'center'} gutterSize={'m'}> + <EuiFlexItem grow={false}> + <EuiIcon type="warning" size="l" color="warning" /> + </EuiFlexItem> + + <EuiFlexItem> + <EuiText size="s"> + <EuiText size={'s'}> + <strong>{'McAfee EndpointSecurity'}</strong> + </EuiText> + <EuiText size={'s'} color={'subdued'}> + {'Add McAfee as a trusted application'} + </EuiText> + </EuiText> + </EuiFlexItem> + + <EuiFlexItem grow={false} style={{ marginLeft: 'auto' }}> + <EuiButtonIcon + iconType="popout" + aria-label="External link" + href="https://google.com" + target="_blank" + /> + </EuiFlexItem> + </EuiFlexGroup> + </EuiPanel> + {showEmptyResultsCallout && ( + <CustomEuiCallOut onDismiss={hideEmptyStateCallout} color={'success'}> + {WORKFLOW_INSIGHTS.issues.emptyResults} + </CustomEuiCallOut> + )} + </> + ); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx new file mode 100644 index 000000000000..b8c51e004fd3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/components/insights/workflow_insights_scan.tsx @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback, useMemo } from 'react'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiPanel, EuiText } from '@elastic/eui'; +import { + AssistantAvatar, + DEFEND_INSIGHTS_STORAGE_KEY, + ConnectorSelectorInline, + DEFAULT_ASSISTANT_NAMESPACE, + useLoadConnectors, +} from '@kbn/elastic-assistant'; +import { noop } from 'lodash/fp'; +import useLocalStorage from 'react-use/lib/useLocalStorage'; +import { some } from 'lodash'; +import { useSpaceId } from '../../../../../../../common/hooks/use_space_id'; +import { WORKFLOW_INSIGHTS } from '../../../translations'; +import { useKibana } from '../../../../../../../common/lib/kibana'; + +export const WorkflowInsightsScanSection = () => { + const CONNECTOR_ID_LOCAL_STORAGE_KEY = 'connectorId'; + + const spaceId = useSpaceId() ?? 'default'; + const { http } = useKibana().services; + const { data: aiConnectors } = useLoadConnectors({ + http, + }); + + // Store the selected connector id in local storage so that it persists across page reloads + const [localStorageWorkflowInsightsConnectorId, setLocalStorageWorkflowInsightsConnectorId] = + useLocalStorage<string>( + `${DEFAULT_ASSISTANT_NAMESPACE}.${DEFEND_INSIGHTS_STORAGE_KEY}.${spaceId}.${CONNECTOR_ID_LOCAL_STORAGE_KEY}` + ); + + const [connectorId, setConnectorId] = React.useState<string | undefined>( + localStorageWorkflowInsightsConnectorId + ); + + const onConnectorIdSelected = useCallback( + (selectedConnectorId: string) => { + setConnectorId(selectedConnectorId); + setLocalStorageWorkflowInsightsConnectorId(selectedConnectorId); + }, + [setLocalStorageWorkflowInsightsConnectorId] + ); + + // Check if the selected connector exists in the list of connectors, i.e. it is not deleted + const connectorExists = useMemo( + () => some(aiConnectors, ['id', connectorId]), + [aiConnectors, connectorId] + ); + + // Render the scan button only if a connector is selected + const renderScanButton = useMemo(() => { + if (!connectorExists) { + return null; + } + return ( + <EuiFlexItem grow={false}> + <EuiButton size="s">{WORKFLOW_INSIGHTS.scan.button}</EuiButton> + </EuiFlexItem> + ); + }, [connectorExists]); + + return ( + <EuiPanel paddingSize="m" hasShadow={false} hasBorder> + <EuiFlexGroup justifyContent="spaceBetween" alignItems="center" gutterSize="m"> + <EuiFlexItem grow={false}> + <EuiFlexGroup alignItems="center" gutterSize="s"> + <EuiFlexItem grow={false}> + <AssistantAvatar size={'xs'} /> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiText size="s"> + <h4>{WORKFLOW_INSIGHTS.scan.title}</h4> + </EuiText> + </EuiFlexItem> + </EuiFlexGroup> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiFlexGroup alignItems="center" gutterSize="s"> + <EuiFlexItem grow={false}> + <ConnectorSelectorInline + onConnectorSelected={noop} + onConnectorIdSelected={onConnectorIdSelected} + selectedConnectorId={connectorId} + /> + </EuiFlexItem> + {renderScanButton} + </EuiFlexGroup> + </EuiFlexItem> + </EuiFlexGroup> + </EuiPanel> + ); +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx index 7f458953022c..c329c5c603bf 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx @@ -11,11 +11,11 @@ import { EuiFlexItem, EuiHealth, EuiLink, - EuiSpacer, EuiText, } from '@elastic/eui'; import React, { memo, useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; +import { WorkflowInsights } from './components/insights/workflow_insights'; import { isPolicyOutOfDate } from '../../utils'; import { AgentStatus } from '../../../../../common/components/endpoint/agents/agent_status'; import type { HostInfo } from '../../../../../../common/endpoint/types'; @@ -184,7 +184,7 @@ export const EndpointDetailsContent = memo<EndpointDetailsContentProps>( return ( <div> - <EuiSpacer size="s" /> + <WorkflowInsights /> <EuiDescriptionList columnWidths={[1, 3]} compressed diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/translations.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/translations.ts index 9ec5b0eee65c..e06280852c24 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/translations.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/translations.ts @@ -11,6 +11,37 @@ export const OVERVIEW = i18n.translate('xpack.securitySolution.endpointDetails.o defaultMessage: 'Overview', }); +export const WORKFLOW_INSIGHTS = { + title: i18n.translate('xpack.securitySolution.endpointDetails.workflowInsights.sectionTitle', { + defaultMessage: 'Issues', + }), + titleRight: i18n.translate( + 'xpack.securitySolution.endpointDetails.workflowInsights.extraAction', + { + defaultMessage: 'Last scans: ', + } + ), + scan: { + title: i18n.translate('xpack.securitySolution.endpointDetails.workflowInsights.scan.title', { + defaultMessage: 'AI-Powered issue scan', + }), + button: i18n.translate('xpack.securitySolution.endpointDetails.workflowInsights.scan.button', { + defaultMessage: 'Scan', + }), + }, + issues: { + title: i18n.translate('xpack.securitySolution.endpointDetails.workflowInsights.issues.title', { + defaultMessage: 'Issues', + }), + emptyResults: i18n.translate( + 'xpack.securitySolution.endpointDetails.workflowInsights.issues.emptyResults', + { + defaultMessage: 'No issues had been found', + } + ), + }, +}; + export const ACTIVITY_LOG = { tabTitle: i18n.translate('xpack.securitySolution.endpointDetails.responseActionsHistory', { defaultMessage: 'Response actions history', diff --git a/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/mocks.ts b/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/mocks.ts new file mode 100644 index 000000000000..8947800d529c --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/mocks.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. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 mockReportCardOpen = jest.fn(); +export const mockReportCardComplete = jest.fn(); +export const mockReportCardLinkClicked = jest.fn(); + +export const telemetry = { + reportCardOpen: mockReportCardOpen, + reportCardComplete: mockReportCardComplete, + reportCardLinkClicked: mockReportCardLinkClicked, +}; +export const mockTelemetry = jest.fn(() => telemetry); + +export const onboardingContext = { + spaceId: 'default', + telemetry: mockTelemetry(), + config: new Map(), +}; +export const mockOnboardingContext = jest.fn(() => onboardingContext); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context.tsx b/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context.tsx index d1c9afcef33d..a8b7eecf273b 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/__mocks__/onboarding_context.tsx @@ -12,17 +12,8 @@ */ import type { OnboardingContextValue } from '../onboarding_context'; -import { - mockReportCardOpen, - mockReportCardComplete, - mockReportCardLinkClicked, -} from './onboarding_context_mocks'; +import { mockOnboardingContext } from './mocks'; export const useOnboardingContext = (): OnboardingContextValue => { - return { - spaceId: 'default', - reportCardOpen: mockReportCardOpen, - reportCardComplete: mockReportCardComplete, - reportCardLinkClicked: mockReportCardLinkClicked, - }; + return mockOnboardingContext(); }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/__snapshots__/onboarding_context.test.tsx.snap b/x-pack/plugins/security_solution/public/onboarding/components/__snapshots__/onboarding_context.test.tsx.snap new file mode 100644 index 000000000000..07275346cda1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/__snapshots__/onboarding_context.test.tsx.snap @@ -0,0 +1,257 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`OnboardingContextProvider config when all requirements are met should return all topics config correctly 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, + "topic1" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "topic1Card1", + }, + ], + "id": "topic1Group1", + }, + ], + "capabilitiesRequired": Array [ + "capability1", + ], + "experimentalFlagRequired": "flag1", + "id": "topic1", + "licenseTypeRequired": "gold", + }, + "topic2" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "experimentalFlagRequired": "flag1", + "id": "topic2Card1", + }, + Object { + "id": "topic2Card2", + "licenseTypeRequired": "gold", + }, + Object { + "capabilitiesRequired": Array [ + "capability1", + ], + "id": "topic2Card3", + }, + ], + "id": "topic2Group1", + }, + ], + "id": "topic2", + }, +} +`; + +exports[`OnboardingContextProvider config when the required capabilities are not met should filter the topics config correctly 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, + "topic2" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "experimentalFlagRequired": "flag1", + "id": "topic2Card1", + }, + Object { + "id": "topic2Card2", + "licenseTypeRequired": "gold", + }, + ], + "id": "topic2Group1", + }, + ], + "id": "topic2", + }, +} +`; + +exports[`OnboardingContextProvider config when the required experimental flag is not met and the required license is not met either and the required capabilities are not met either should return only the default topics config 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, +} +`; + +exports[`OnboardingContextProvider config when the required experimental flag is not met and the required license is not met either should filter the topics config correctly 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, + "topic2" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "capabilitiesRequired": Array [ + "capability1", + ], + "id": "topic2Card3", + }, + ], + "id": "topic2Group1", + }, + ], + "id": "topic2", + }, +} +`; + +exports[`OnboardingContextProvider config when the required experimental flag is not met should filter the topics config correctly 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, + "topic2" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "topic2Card2", + "licenseTypeRequired": "gold", + }, + Object { + "capabilitiesRequired": Array [ + "capability1", + ], + "id": "topic2Card3", + }, + ], + "id": "topic2Group1", + }, + ], + "id": "topic2", + }, +} +`; + +exports[`OnboardingContextProvider config when the required license is not met and the required capabilities are not met either should filter the topics config correctly 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, + "topic2" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "experimentalFlagRequired": "flag1", + "id": "topic2Card1", + }, + ], + "id": "topic2Group1", + }, + ], + "id": "topic2", + }, +} +`; + +exports[`OnboardingContextProvider config when the required license is not met should filter the topics config correctly 1`] = ` +Map { + "default" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "id": "defaultCard1", + }, + ], + "id": "defaultGroup1", + }, + ], + "id": "default", + }, + "topic2" => Object { + "body": Array [ + Object { + "cards": Array [ + Object { + "experimentalFlagRequired": "flag1", + "id": "topic2Card1", + }, + Object { + "capabilitiesRequired": Array [ + "capability1", + ], + "id": "topic2Card3", + }, + ], + "id": "topic2Group1", + }, + ], + "id": "topic2", + }, +} +`; diff --git a/x-pack/plugins/security_solution/public/onboarding/hooks/use_onboarding_service.ts b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_onboarding_service.ts similarity index 82% rename from x-pack/plugins/security_solution/public/onboarding/hooks/use_onboarding_service.ts rename to x-pack/plugins/security_solution/public/onboarding/components/hooks/use_onboarding_service.ts index 55f3ecb8d4ac..3d94d8153028 100644 --- a/x-pack/plugins/security_solution/public/onboarding/hooks/use_onboarding_service.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_onboarding_service.ts @@ -5,6 +5,6 @@ * 2.0. */ -import { useKibana } from '../../common/lib/kibana/kibana_react'; +import { useKibana } from '../../../common/lib/kibana/kibana_react'; export const useOnboardingService = () => useKibana().services.onboarding; diff --git a/x-pack/plugins/security_solution/public/onboarding/hooks/use_stored_state.ts b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_stored_state.ts similarity index 60% rename from x-pack/plugins/security_solution/public/onboarding/hooks/use_stored_state.ts rename to x-pack/plugins/security_solution/public/onboarding/components/hooks/use_stored_state.ts index eac269f3a4a3..87e22de599aa 100644 --- a/x-pack/plugins/security_solution/public/onboarding/hooks/use_stored_state.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_stored_state.ts @@ -6,23 +6,23 @@ */ import useLocalStorage from 'react-use/lib/useLocalStorage'; -import type { OnboardingCardId } from '../constants'; -import type { IntegrationTabId } from '../components/onboarding_body/cards/integrations/types'; +import type { OnboardingCardId } from '../../constants'; +import type { IntegrationTabId } from '../onboarding_body/cards/integrations/types'; const LocalStorageKey = { - avcBannerDismissed: 'ONBOARDING_HUB.AVC_BANNER_DISMISSED', - videoVisited: 'ONBOARDING_HUB.VIDEO_VISITED', - completeCards: 'ONBOARDING_HUB.COMPLETE_CARDS', - expandedCard: 'ONBOARDING_HUB.EXPANDED_CARD', - selectedIntegrationTabId: 'ONBOARDING_HUB.SELECTED_INTEGRATION_TAB_ID', - IntegrationSearchTerm: 'ONBOARDING_HUB.INTEGRATION_SEARCH_TERM', - IntegrationScrollTop: 'ONBOARDING_HUB.INTEGRATION_SCROLL_TOP', + avcBannerDismissed: 'securitySolution.onboarding.avcBannerDismissed', + videoVisited: 'securitySolution.onboarding.videoVisited', + completeCards: 'securitySolution.onboarding.completeCards', + expandedCard: 'securitySolution.onboarding.expandedCard', + urlDetails: 'securitySolution.onboarding.urlDetails', + selectedIntegrationTabId: 'securitySolution.onboarding.selectedIntegrationTabId', + integrationSearchTerm: 'securitySolution.onboarding.integrationSearchTerm', } as const; /** * Wrapper hook for useLocalStorage, but always returns the default value when not defined instead of `undefined`. */ -const useDefinedLocalStorage = <T>(key: string, defaultValue: T) => { +export const useDefinedLocalStorage = <T = undefined>(key: string, defaultValue: T) => { const [value, setValue] = useLocalStorage<T>(key, defaultValue); return [value ?? defaultValue, setValue] as const; }; @@ -40,13 +40,10 @@ export const useStoredCompletedCardIds = (spaceId: string) => useDefinedLocalStorage<OnboardingCardId[]>(`${LocalStorageKey.completeCards}.${spaceId}`, []); /** - * Stores the expanded card ID per space + * Stores the selected topic ID per space */ -export const useStoredExpandedCardId = (spaceId: string) => - useDefinedLocalStorage<OnboardingCardId | null>( - `${LocalStorageKey.expandedCard}.${spaceId}`, - null - ); +export const useStoredUrlDetails = (spaceId: string) => + useDefinedLocalStorage<string | null>(`${LocalStorageKey.urlDetails}.${spaceId}`, null); /** * Stores the selected integration tab ID per space @@ -65,6 +62,6 @@ export const useStoredIntegrationTabId = ( */ export const useStoredIntegrationSearchTerm = (spaceId: string) => useDefinedLocalStorage<string | null>( - `${LocalStorageKey.IntegrationSearchTerm}.${spaceId}`, + `${LocalStorageKey.integrationSearchTerm}.${spaceId}`, null ); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_topic_id.ts b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_topic_id.ts new file mode 100644 index 000000000000..b20e8ae392b6 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_topic_id.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { useParams } from 'react-router-dom'; +import { OnboardingTopicId } from '../../constants'; +import type { OnboardingRouteParams } from '../../types'; +import { useUrlDetail } from './use_url_detail'; + +/** + * Hook that returns the topic id from the URL, or the default topic id if none is present + * This is the Single Source of Truth for the topic id + */ +export const useTopicId = (): OnboardingTopicId => { + const { topicId = OnboardingTopicId.default } = useParams<OnboardingRouteParams>(); + return topicId; +}; + +export const useTopic = (): [OnboardingTopicId, (topicId: OnboardingTopicId) => void] => { + const topicId = useTopicId(); + const { setTopicDetail } = useUrlDetail(); + + const setTopicId = useCallback( + (newTopicId: OnboardingTopicId) => { + setTopicDetail(newTopicId); + }, + [setTopicDetail] + ); + + return [topicId, setTopicId]; +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_url_detail.ts b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_url_detail.ts new file mode 100644 index 000000000000..387e9d66865b --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/hooks/use_url_detail.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useCallback } from 'react'; +import { SecurityPageName, useNavigateTo } from '@kbn/security-solution-navigation'; +import { useStoredUrlDetails } from './use_stored_state'; +import { OnboardingTopicId, type OnboardingCardId } from '../../constants'; +import { useOnboardingContext } from '../onboarding_context'; +import { useTopicId } from './use_topic_id'; + +export const getCardIdFromHash = (hash: string): OnboardingCardId | null => + (hash.split('?')[0].replace('#', '') as OnboardingCardId) || null; + +const setHash = (cardId: OnboardingCardId | null) => { + history.replaceState(null, '', cardId == null ? ' ' : `#${cardId}`); +}; + +const getTopicPath = (topicId: OnboardingTopicId) => + topicId !== OnboardingTopicId.default ? topicId : ''; + +const getCardHash = (cardId: OnboardingCardId | null) => (cardId ? `#${cardId}` : ''); + +/** + * This hook manages the expanded card id state in the LocalStorage and the hash in the URL. + */ +export const useUrlDetail = () => { + const { spaceId, telemetry } = useOnboardingContext(); + const topicId = useTopicId(); + const [storedUrlDetail, setStoredUrlDetail] = useStoredUrlDetails(spaceId); + + const { navigateTo } = useNavigateTo(); + + const setTopicDetail = useCallback( + (newTopicId: OnboardingTopicId) => { + const path = newTopicId === OnboardingTopicId.default ? undefined : newTopicId; + setStoredUrlDetail(path ?? null); + navigateTo({ deepLinkId: SecurityPageName.landing, path }); + }, + [setStoredUrlDetail, navigateTo] + ); + + const setCardDetail = useCallback( + (newCardId: OnboardingCardId | null) => { + setHash(newCardId); + setStoredUrlDetail(`${getTopicPath(topicId)}${getCardHash(newCardId)}` || null); + if (newCardId != null) { + telemetry.reportCardOpen(newCardId); + } + }, + [setStoredUrlDetail, topicId, telemetry] + ); + + const syncUrlDetails = useCallback( + (pathTopicId: OnboardingTopicId | null, hashCardId: OnboardingCardId | null) => { + const urlDetail = `${pathTopicId || ''}${hashCardId ? `#${hashCardId}` : ''}`; + if (urlDetail && urlDetail !== storedUrlDetail) { + if (hashCardId) { + telemetry.reportCardOpen(hashCardId, { auto: true }); + } + setStoredUrlDetail(urlDetail); + } + if (!urlDetail && storedUrlDetail) { + navigateTo({ deepLinkId: SecurityPageName.landing, path: storedUrlDetail }); + } + }, + [navigateTo, setStoredUrlDetail, storedUrlDetail, telemetry] + ); + + return { setTopicDetail, setCardDetail, syncUrlDetails }; +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/common/lib/__mocks__/telemetry.ts b/x-pack/plugins/security_solution/public/onboarding/components/lib/__mocks__/telemetry.ts similarity index 100% rename from x-pack/plugins/security_solution/public/onboarding/common/lib/__mocks__/telemetry.ts rename to x-pack/plugins/security_solution/public/onboarding/components/lib/__mocks__/telemetry.ts diff --git a/x-pack/plugins/security_solution/public/onboarding/common/lib/telemetry.ts b/x-pack/plugins/security_solution/public/onboarding/components/lib/telemetry.ts similarity index 100% rename from x-pack/plugins/security_solution/public/onboarding/common/lib/telemetry.ts rename to x-pack/plugins/security_solution/public/onboarding/components/lib/telemetry.ts diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding.tsx index 17f4840e68dc..caa0d9f9b79d 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding.tsx @@ -7,17 +7,23 @@ import React from 'react'; +import { Routes, Route } from '@kbn/shared-ux-router'; import { EuiSpacer, useEuiTheme } from '@elastic/eui'; import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template'; +import { Redirect } from 'react-router-dom'; +import { ONBOARDING_PATH } from '../../../common/constants'; import { PluginTemplateWrapper } from '../../common/components/plugin_template_wrapper'; import { CenteredLoadingSpinner } from '../../common/components/centered_loading_spinner'; import { useSpaceId } from '../../common/hooks/use_space_id'; +import { OnboardingTopicId, PAGE_CONTENT_WIDTH } from '../constants'; import { OnboardingContextProvider } from './onboarding_context'; import { OnboardingAVCBanner } from './onboarding_banner'; -import { OnboardingHeader } from './onboarding_header'; -import { OnboardingBody } from './onboarding_body'; +import { OnboardingRoute } from './onboarding_route'; import { OnboardingFooter } from './onboarding_footer'; -import { PAGE_CONTENT_WIDTH } from '../constants'; + +const topicPathParam = `:topicId(${Object.values(OnboardingTopicId) // any topics + .filter((val) => val !== OnboardingTopicId.default) // except "default" + .join('|')})?`; // optional parameter export const OnboardingPage = React.memo(() => { const spaceId = useSpaceId(); @@ -42,8 +48,14 @@ export const OnboardingPage = React.memo(() => { bottomBorder="extended" style={{ backgroundColor: euiTheme.colors.body }} > - <OnboardingHeader /> - <OnboardingBody /> + <Routes> + <Route + path={`${ONBOARDING_PATH}/${topicPathParam}`} + exact + component={OnboardingRoute} + /> + <Route path={`${ONBOARDING_PATH}/*`} render={() => <Redirect to={ONBOARDING_PATH} />} /> + </Routes> </KibanaPageTemplate.Section> <EuiSpacer size="l" /> <KibanaPageTemplate.Section grow={true} restrictWidth={PAGE_CONTENT_WIDTH} paddingSize="xl"> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_banner/onboarding_banner.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_banner/onboarding_banner.tsx index 201fae862b43..0976dbc110cc 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_banner/onboarding_banner.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_banner/onboarding_banner.tsx @@ -8,7 +8,7 @@ import React, { useCallback } from 'react'; import { AVCResultsBanner2024, useIsStillYear2024 } from '@kbn/avc-banner'; -import { useStoredIsAVCBannerDismissed } from '../../hooks/use_stored_state'; +import { useStoredIsAVCBannerDismissed } from '../hooks/use_stored_state'; export const OnboardingBanner = React.memo(() => { const [isAVCBannerDismissed, setIsAVCBannerDismissed] = useStoredIsAVCBannerDismissed(); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/body_config.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/body_config.ts index 7f97b5c8eacd..93690f98b48e 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/body_config.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/body_config.ts @@ -12,8 +12,9 @@ import { dashboardsCardConfig } from './cards/dashboards'; import { rulesCardConfig } from './cards/rules'; import { alertsCardConfig } from './cards/alerts'; import { assistantCardConfig } from './cards/assistant'; +import { aiConnectorCardConfig } from './cards/siem_migrations/ai_connector'; -export const bodyConfig: OnboardingGroupConfig[] = [ +export const defaultBodyConfig: OnboardingGroupConfig[] = [ { title: i18n.translate('xpack.securitySolution.onboarding.dataGroup.title', { defaultMessage: 'Ingest your data', @@ -34,3 +35,12 @@ export const bodyConfig: OnboardingGroupConfig[] = [ cards: [assistantCardConfig], }, ]; + +export const siemMigrationsBodyConfig: OnboardingGroupConfig[] = [ + { + title: i18n.translate('xpack.securitySolution.onboarding.configure.title', { + defaultMessage: 'Configure', + }), + cards: [aiConnectorCardConfig], + }, +]; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.test.tsx index 3e83bcb851f8..4fec865e36f2 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.test.tsx @@ -14,6 +14,7 @@ const props = { checkComplete: jest.fn(), isCardComplete: jest.fn(), setExpandedCardId: jest.fn(), + isCardAvailable: jest.fn(), }; describe('AlertsCard', () => { @@ -31,7 +32,8 @@ describe('AlertsCard', () => { expect(getByTestId('alertsCardDescription')).toBeInTheDocument(); }); - it('card callout should be rendered if integrations cards is not complete', () => { + it('card callout should be rendered if integrations card is available but not complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); const { getByText } = render( @@ -43,7 +45,20 @@ describe('AlertsCard', () => { expect(getByText('To view alerts add integrations first.')).toBeInTheDocument(); }); - it('card button should be disabled if integrations cards is not complete', () => { + it('card callout should not be rendered if integrations card is not available', () => { + props.isCardAvailable.mockReturnValueOnce(false); + + const { queryByText } = render( + <TestProviders> + <AlertsCard {...props} /> + </TestProviders> + ); + + expect(queryByText('To view alerts add integrations first.')).not.toBeInTheDocument(); + }); + + it('card button should be disabled if integrations card is available but not complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); const { getByTestId } = render( @@ -54,4 +69,17 @@ describe('AlertsCard', () => { expect(getByTestId('alertsCardButton').querySelector('button')).toBeDisabled(); }); + + it('card button should be enabled if integrations card is complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); + props.isCardComplete.mockReturnValueOnce(true); + + const { getByTestId } = render( + <TestProviders> + <AlertsCard {...props} /> + </TestProviders> + ); + + expect(getByTestId('alertsCardButton').querySelector('button')).not.toBeDisabled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx index 85d3994d4453..bdcf662a5643 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/alerts/alerts_card.tsx @@ -6,22 +6,14 @@ */ import React, { useCallback, useMemo } from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiSpacer, - EuiText, - useEuiTheme, - COLOR_MODES_STANDARD, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiSpacer } from '@elastic/eui'; import { SecurityPageName } from '@kbn/security-solution-navigation'; import { SecuritySolutionLinkButton } from '../../../../../common/components/links'; import { OnboardingCardId } from '../../../../constants'; import type { OnboardingCardComponent } from '../../../../types'; import { OnboardingCardContentImagePanel } from '../common/card_content_image_panel'; import { CardCallOut } from '../common/card_callout'; +import { CardSubduedText } from '../common/card_subdued_text'; import alertsImageSrc from './images/alerts.png'; import * as i18n from './translations'; @@ -29,15 +21,18 @@ export const AlertsCard: OnboardingCardComponent = ({ isCardComplete, setExpandedCardId, setComplete, + isCardAvailable, }) => { - const { colorMode } = useEuiTheme(); - const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; - const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] ); + const isIntegrationsCardAvailable = useMemo( + () => isCardAvailable(OnboardingCardId.integrations), + [isCardAvailable] + ); + const expandIntegrationsCard = useCallback(() => { setExpandedCardId(OnboardingCardId.integrations, { scroll: true }); }, [setExpandedCardId]); @@ -51,14 +46,10 @@ export const AlertsCard: OnboardingCardComponent = ({ alignItems="flexStart" > <EuiFlexItem grow={false}> - <EuiText - data-test-subj="alertsCardDescription" - size="s" - color={isDarkMode ? 'text' : 'subdued'} - > + <CardSubduedText data-test-subj="alertsCardDescription" size="s"> {i18n.ALERTS_CARD_DESCRIPTION} - </EuiText> - {!isIntegrationsCardComplete && ( + </CardSubduedText> + {isIntegrationsCardAvailable && !isIntegrationsCardComplete && ( <> <EuiSpacer size="m" /> <CardCallOut @@ -84,7 +75,7 @@ export const AlertsCard: OnboardingCardComponent = ({ onClick={() => setComplete(true)} deepLinkId={SecurityPageName.alerts} fill - isDisabled={!isIntegrationsCardComplete} + isDisabled={isIntegrationsCardAvailable && !isIntegrationsCardComplete} > {i18n.ALERTS_CARD_VIEW_ALERTS_BUTTON} </SecuritySolutionLinkButton> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx index b72860693702..c971bd2a6f0b 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_card.tsx @@ -6,39 +6,35 @@ */ import React, { useCallback, useMemo } from 'react'; -import { - EuiCallOut, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiText, - useEuiTheme, - COLOR_MODES_STANDARD, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink } from '@elastic/eui'; import { css } from '@emotion/css'; import { OnboardingCardId } from '../../../../constants'; import type { OnboardingCardComponent } from '../../../../types'; import * as i18n from './translations'; import { OnboardingCardContentPanel } from '../common/card_content_panel'; -import { ConnectorCards } from './connectors/connector_cards'; +import { ConnectorCards } from '../common/connectors/connector_cards'; import { CardCallOut } from '../common/card_callout'; +import { CardSubduedText } from '../common/card_subdued_text'; import type { AssistantCardMetadata } from './types'; -import { MissingPrivilegesDescription } from './connectors/missing_privileges_tooltip'; +import { MissingPrivilegesCallOut } from '../common/connectors/missing_privileges'; export const AssistantCard: OnboardingCardComponent<AssistantCardMetadata> = ({ isCardComplete, setExpandedCardId, checkCompleteMetadata, checkComplete, + isCardAvailable, }) => { - const { euiTheme, colorMode } = useEuiTheme(); - const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] ); + const isIntegrationsCardAvailable = useMemo( + () => isCardAvailable(OnboardingCardId.integrations), + [isCardAvailable] + ); + const expandIntegrationsCard = useCallback(() => { setExpandedCardId(OnboardingCardId.integrations, { scroll: true }); }, [setExpandedCardId]); @@ -48,27 +44,14 @@ export const AssistantCard: OnboardingCardComponent<AssistantCardMetadata> = ({ const canCreateConnectors = checkCompleteMetadata?.canCreateConnectors; return ( - <OnboardingCardContentPanel - style={{ - paddingTop: 0, - ...(isDarkMode && { backgroundColor: euiTheme.colors.lightestShade }), - }} - > + <OnboardingCardContentPanel> {canExecuteConnectors ? ( <EuiFlexGroup direction="column"> <EuiFlexItem grow={false}> - <EuiText size="s" color={isDarkMode ? 'text' : 'subdued'}> - {i18n.ASSISTANT_CARD_DESCRIPTION} - </EuiText> + <CardSubduedText size="s">{i18n.ASSISTANT_CARD_DESCRIPTION}</CardSubduedText> </EuiFlexItem> <EuiFlexItem> - {isIntegrationsCardComplete ? ( - <ConnectorCards - canCreateConnectors={canCreateConnectors} - connectors={connectors} - onConnectorSaved={checkComplete} - /> - ) : ( + {isIntegrationsCardAvailable && !isIntegrationsCardComplete ? ( <EuiFlexItem className={css` width: 45%; @@ -90,13 +73,17 @@ export const AssistantCard: OnboardingCardComponent<AssistantCardMetadata> = ({ } /> </EuiFlexItem> + ) : ( + <ConnectorCards + canCreateConnectors={canCreateConnectors} + connectors={connectors} + onConnectorSaved={checkComplete} + /> )} </EuiFlexItem> </EuiFlexGroup> ) : ( - <EuiCallOut title={i18n.PRIVILEGES_MISSING_TITLE} iconType="iInCircle"> - <MissingPrivilegesDescription /> - </EuiCallOut> + <MissingPrivilegesCallOut /> )} </OnboardingCardContentPanel> ); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts index 8c0d029cee58..6242eb02bd54 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/assistant_check_complete.ts @@ -9,7 +9,7 @@ import { loadAllActions as loadConnectors } from '@kbn/triggers-actions-ui-plugi import type { AIConnector } from '@kbn/elastic-assistant/impl/connectorland/connector_selector'; import { i18n } from '@kbn/i18n'; import type { OnboardingCardCheckComplete } from '../../../../types'; -import { AllowedActionTypeIds } from './constants'; +import { AIActionTypeIds } from '../common/connectors/constants'; import type { AssistantCardMetadata } from './types'; export const checkAssistantCardComplete: OnboardingCardCheckComplete< @@ -21,7 +21,7 @@ export const checkAssistantCardComplete: OnboardingCardCheckComplete< } = application; const aiConnectors = allConnectors.reduce((acc: AIConnector[], connector) => { - if (!connector.isMissingSecrets && AllowedActionTypeIds.includes(connector.actionTypeId)) { + if (!connector.isMissingSecrets && AIActionTypeIds.includes(connector.actionTypeId)) { acc.push(connector); } return acc; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx deleted file mode 100644 index 472459b631b0..000000000000 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_cards.tsx +++ /dev/null @@ -1,118 +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 { type AIConnector } from '@kbn/elastic-assistant/impl/connectorland/connector_selector'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiPanel, - EuiLoadingSpinner, - EuiText, - EuiBadge, - EuiSpacer, - EuiCallOut, -} from '@elastic/eui'; -import { css } from '@emotion/css'; -import { useKibana } from '../../../../../../common/lib/kibana'; -import { CreateConnectorPopover } from './create_connector_popover'; -import { ConnectorSetup } from './connector_setup'; -import * as i18n from './translations'; -import { MissingPrivilegesDescription } from './missing_privileges_tooltip'; - -interface ConnectorCardsProps { - connectors?: AIConnector[]; - onConnectorSaved: () => void; - canCreateConnectors?: boolean; -} - -export const ConnectorCards = React.memo<ConnectorCardsProps>( - ({ connectors, onConnectorSaved, canCreateConnectors }) => { - const { - triggersActionsUi: { actionTypeRegistry }, - } = useKibana().services; - - if (!connectors) { - return <EuiLoadingSpinner />; - } - - const hasConnectors = connectors.length > 0; - - // show callout when user is missing actions.save privilege - if (!hasConnectors && !canCreateConnectors) { - return ( - <EuiCallOut title={i18n.PRIVILEGES_MISSING_TITLE} iconType="iInCircle"> - <MissingPrivilegesDescription /> - </EuiCallOut> - ); - } - - return ( - <> - {hasConnectors ? ( - <> - <ConnectorList connectors={connectors} actionTypeRegistry={actionTypeRegistry} /> - <EuiSpacer /> - <CreateConnectorPopover - canCreateConnectors={canCreateConnectors} - onConnectorSaved={onConnectorSaved} - /> - </> - ) : ( - <ConnectorSetup onConnectorSaved={onConnectorSaved} /> - )} - </> - ); - } -); -ConnectorCards.displayName = 'ConnectorCards'; - -interface ConnectorListProps { - connectors: AIConnector[]; - actionTypeRegistry: ReturnType< - typeof useKibana - >['services']['triggersActionsUi']['actionTypeRegistry']; -} - -const ConnectorList = React.memo<ConnectorListProps>(({ connectors, actionTypeRegistry }) => ( - <EuiFlexGroup - wrap - className={css` - max-height: 290px; - overflow-y: auto; - `} - > - {connectors.map((connector) => ( - <EuiFlexItem - key={connector.id} - grow={false} - className={css` - width: 30%; - `} - > - <EuiPanel hasShadow={false} hasBorder paddingSize="m"> - <EuiFlexGroup direction="row" gutterSize="s" wrap> - <EuiFlexItem - className={css` - min-width: 100%; - `} - > - <EuiText size="s">{connector.name}</EuiText> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiBadge color="hollow"> - {actionTypeRegistry.get(connector.actionTypeId).actionTypeTitle} - </EuiBadge> - </EuiFlexItem> - </EuiFlexGroup> - </EuiPanel> - </EuiFlexItem> - ))} - </EuiFlexGroup> -)); - -ConnectorList.displayName = 'ConnectorList'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/constants.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/constants.ts deleted file mode 100644 index 35811c18de47..000000000000 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const AllowedActionTypeIds = ['.bedrock', '.gen-ai', '.gemini']; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts index fedf97505232..4850b1ee2d86 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/index.ts @@ -25,8 +25,6 @@ export const assistantCardConfig: OnboardingCardConfig<AssistantCardMetadata> = ) ), checkComplete: checkAssistantCardComplete, - // Both capabilities are needed for this card, so we should use a double array to create an AND conditional - // (a single array would create an OR conditional between them) - capabilities: [['securitySolutionAssistant.ai-assistant']], - licenseType: 'enterprise', + capabilitiesRequired: ['securitySolutionAssistant.ai-assistant'], + licenseTypeRequired: 'enterprise', }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts index de3c11128043..1c526d4974a9 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/translations.ts @@ -35,17 +35,3 @@ export const ASSISTANT_CARD_CALLOUT_INTEGRATIONS_BUTTON = i18n.translate( defaultMessage: 'Add integrations step', } ); - -export const ASSISTANT_CARD_CREATE_NEW_CONNECTOR_POPOVER = i18n.translate( - 'xpack.securitySolution.onboarding.assistantCard.createNewConnectorPopover', - { - defaultMessage: 'Create new connector', - } -); - -export const PRIVILEGES_MISSING_TITLE = i18n.translate( - 'xpack.securitySolution.onboarding.assistantCard.callout.title', - { - defaultMessage: 'Missing privileges', - } -); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/attack_discover_card.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/attack_discover_card.test.tsx index 19b327f77487..c28ae75b92c7 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/attack_discover_card.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/attack_discover_card.test.tsx @@ -14,6 +14,7 @@ const props = { checkComplete: jest.fn(), isCardComplete: jest.fn(), setExpandedCardId: jest.fn(), + isCardAvailable: jest.fn(), }; describe('RulesCard', () => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/index.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/index.ts index 3e174caa2715..beec64bd9078 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/index.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/attack_discovery/index.ts @@ -22,6 +22,6 @@ export const attackDiscoveryCardConfig: OnboardingCardConfig = { './attack_discovery_card' ) ), - capabilities: 'securitySolutionAttackDiscovery.attack-discovery', - licenseType: 'enterprise', + capabilitiesRequired: 'securitySolutionAttackDiscovery.attack-discovery', + licenseTypeRequired: 'enterprise', }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts index c7998135aa8a..2260b95ab944 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_image_panel.styles.ts @@ -6,15 +6,12 @@ */ import { css } from '@emotion/css'; -import { useEuiTheme, useEuiShadow, COLOR_MODES_STANDARD } from '@elastic/eui'; +import { useEuiTheme, useEuiShadow } from '@elastic/eui'; export const useCardContentImagePanelStyles = () => { - const { euiTheme, colorMode } = useEuiTheme(); + const { euiTheme } = useEuiTheme(); const shadowStyles = useEuiShadow('m'); - const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; return css` - padding-top: 8px; - ${isDarkMode ? `background-color: ${euiTheme.colors.lightestShade}` : ''}; .cardSpacer { width: 8%; } diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.styles.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.styles.ts new file mode 100644 index 000000000000..7d0fcf831e4e --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.styles.ts @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { css } from '@emotion/css'; +import { COLOR_MODES_STANDARD, useEuiTheme } from '@elastic/eui'; +import { useDarkPanelStyles } from '../../onboarding_card_panel.styles'; + +export const NESTED_PANEL_CLASS_NAME = 'onboardingCardContentPanelNested'; + +export const useCardContentPanelStyles = () => { + const { euiTheme, colorMode } = useEuiTheme(); + const darkPanelStyles = useDarkPanelStyles(colorMode === COLOR_MODES_STANDARD.dark); + + return css` + padding-top: 0; + ${darkPanelStyles} + + .${NESTED_PANEL_CLASS_NAME} { + padding-top: ${euiTheme.size.s}; + ${darkPanelStyles} + } + `; +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.tsx index 3d5489b9be1c..be1b01fc7708 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_content_panel.tsx @@ -5,24 +5,19 @@ * 2.0. */ import React, { type PropsWithChildren } from 'react'; -import { COLOR_MODES_STANDARD, EuiPanel, useEuiTheme, type EuiPanelProps } from '@elastic/eui'; -import { css } from '@emotion/react'; +import { EuiPanel, type EuiPanelProps } from '@elastic/eui'; +import classnames from 'classnames'; +import { useCardContentPanelStyles, NESTED_PANEL_CLASS_NAME } from './card_content_panel.styles'; export const OnboardingCardContentPanel = React.memo<PropsWithChildren<EuiPanelProps>>( - ({ children, ...panelProps }) => { - const { euiTheme, colorMode } = useEuiTheme(); - const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + ({ children, className, ...panelProps }) => { + const styles = useCardContentPanelStyles(); + const panelClassName = classnames(styles); + const nestedClassName = classnames(NESTED_PANEL_CLASS_NAME, className); + return ( - <EuiPanel - paddingSize="m" - hasShadow={false} - hasBorder={false} - css={css` - background-color: ${isDarkMode ? euiTheme.colors.lightestShade : ''}; - padding-top: 0; - `} - > - <EuiPanel {...panelProps} hasShadow={false} paddingSize="l"> + <EuiPanel paddingSize="m" hasShadow={false} hasBorder={false} className={panelClassName}> + <EuiPanel {...panelProps} hasShadow={false} paddingSize="l" className={nestedClassName}> {children} </EuiPanel> </EuiPanel> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_link_button.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_link_button.tsx index 96466466ee4a..35254b45968f 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_link_button.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_link_button.tsx @@ -19,13 +19,13 @@ export const withReportCardLinkClick = <T extends { onClick?: React.MouseEventHa WrappedComponent: React.ComponentType<T> ): React.FC<T & CardLinkButtonProps> => React.memo(function WithReportCardLinkClick({ onClick, cardId, linkId, ...rest }) { - const { reportCardLinkClicked } = useOnboardingContext(); + const { telemetry } = useOnboardingContext(); const onClickWithReport = useCallback<React.MouseEventHandler>( (ev) => { - reportCardLinkClicked(cardId, linkId); + telemetry.reportCardLinkClicked(cardId, linkId); onClick?.(ev); }, - [reportCardLinkClicked, cardId, linkId, onClick] + [telemetry, cardId, linkId, onClick] ); return <WrappedComponent {...({ onClick: onClickWithReport, ...rest } as unknown as T)} />; }); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_subdued_text.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_subdued_text.tsx new file mode 100644 index 000000000000..6e022b639204 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/card_subdued_text.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { type PropsWithChildren } from 'react'; +import { EuiText, useEuiTheme, COLOR_MODES_STANDARD, type EuiTextProps } from '@elastic/eui'; + +export type CardSubduedTextProps = PropsWithChildren<EuiTextProps>; +export const CardSubduedText = React.memo<CardSubduedTextProps>(({ children, ...props }) => { + const { colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + return ( + <EuiText {...props} color={isDarkMode ? 'text' : 'subdued'}> + {children} + </EuiText> + ); +}); +CardSubduedText.displayName = 'CardSubduedText'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_cards.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_cards.tsx new file mode 100644 index 000000000000..b8b51198c75f --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_cards.tsx @@ -0,0 +1,153 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { type AIConnector } from '@kbn/elastic-assistant/impl/connectorland/connector_selector'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiPanel, + EuiLoadingSpinner, + EuiText, + EuiBadge, + EuiSpacer, + EuiCallOut, + useEuiTheme, +} from '@elastic/eui'; +import { css } from '@emotion/css'; +import { useKibana } from '../../../../../../common/lib/kibana'; +import { + CreateConnectorPopover, + type CreateConnectorPopoverProps, +} from './create_connector_popover'; +import { ConnectorSetup } from './connector_setup'; +import * as i18n from './translations'; +import { MissingPrivilegesDescription } from './missing_privileges'; + +interface ConnectorCardsProps + extends CreateConnectorPopoverProps, + Omit<ConnectorListProps, 'connectors'> { + connectors?: AIConnector[]; // make connectors optional to handle loading state +} + +export const ConnectorCards = React.memo<ConnectorCardsProps>( + ({ + connectors, + onConnectorSaved, + canCreateConnectors, + selectedConnectorId, + setSelectedConnectorId, + }) => { + if (!connectors) { + return <EuiLoadingSpinner />; + } + + const hasConnectors = connectors.length > 0; + + // show callout when user is missing actions.save privilege + if (!hasConnectors && !canCreateConnectors) { + return ( + <EuiCallOut title={i18n.PRIVILEGES_MISSING_TITLE} iconType="iInCircle"> + <MissingPrivilegesDescription /> + </EuiCallOut> + ); + } + + return ( + <> + {hasConnectors ? ( + <> + <ConnectorList + connectors={connectors} + selectedConnectorId={selectedConnectorId} + setSelectedConnectorId={setSelectedConnectorId} + /> + <EuiSpacer /> + <CreateConnectorPopover + canCreateConnectors={canCreateConnectors} + onConnectorSaved={onConnectorSaved} + /> + </> + ) : ( + <ConnectorSetup onConnectorSaved={onConnectorSaved} /> + )} + </> + ); + } +); +ConnectorCards.displayName = 'ConnectorCards'; + +interface ConnectorListProps { + connectors: AIConnector[]; + selectedConnectorId?: string | null; + setSelectedConnectorId?: (id: string) => void; +} + +const ConnectorList = React.memo<ConnectorListProps>( + ({ connectors, selectedConnectorId, setSelectedConnectorId }) => { + const { euiTheme } = useEuiTheme(); + const { actionTypeRegistry } = useKibana().services.triggersActionsUi; + const onConnectorClick = useCallback( + (id: string) => { + setSelectedConnectorId?.(id); + }, + [setSelectedConnectorId] + ); + + const selectedCss = `border: 2px solid ${euiTheme.colors.primary};`; + + return ( + <EuiFlexGroup + wrap + gutterSize="s" + className={css` + padding: ${euiTheme.size.s} 0; + max-height: 350px; + overflow-y: auto; + `} + > + {connectors.map((connector) => ( + <EuiFlexItem + key={connector.id} + grow={false} + className={css` + width: 30%; + `} + > + <EuiPanel + hasShadow={false} + hasBorder + paddingSize="m" + onClick={setSelectedConnectorId ? () => onConnectorClick(connector.id) : undefined} + css={css` + ${selectedConnectorId === connector.id ? selectedCss : ''} + `} + color={selectedConnectorId === connector.id ? 'primary' : 'plain'} + > + <EuiFlexGroup direction="row" gutterSize="s" wrap> + <EuiFlexItem + className={css` + min-width: 100%; + `} + > + <EuiText size="s">{connector.name}</EuiText> + </EuiFlexItem> + <EuiFlexItem grow={false}> + <EuiBadge color="hollow"> + {actionTypeRegistry.get(connector.actionTypeId).actionTypeTitle} + </EuiBadge> + </EuiFlexItem> + </EuiFlexGroup> + </EuiPanel> + </EuiFlexItem> + ))} + </EuiFlexGroup> + ); + } +); + +ConnectorList.displayName = 'ConnectorList'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_setup.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_setup.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/connector_setup.tsx rename to x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/connector_setup.tsx diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/constants.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/constants.ts new file mode 100644 index 000000000000..5c9c94e36985 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/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 AIActionTypeIds = ['.bedrock', '.gen-ai', '.gemini']; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/create_connector_popover.tsx similarity index 94% rename from x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx rename to x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/create_connector_popover.tsx index 32bcd66f4924..c6c378fc8e29 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/create_connector_popover.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/create_connector_popover.tsx @@ -9,9 +9,9 @@ import { css } from '@emotion/css'; import { EuiPopover, EuiLink, EuiText } from '@elastic/eui'; import { ConnectorSetup } from './connector_setup'; import * as i18n from './translations'; -import { MissingPrivilegesTooltip } from './missing_privileges_tooltip'; +import { MissingPrivilegesTooltip } from './missing_privileges'; -interface CreateConnectorPopoverProps { +export interface CreateConnectorPopoverProps { onConnectorSaved: () => void; canCreateConnectors?: boolean; } diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/hooks/use_load_action_types.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/hooks/use_load_action_types.ts similarity index 81% rename from x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/hooks/use_load_action_types.ts rename to x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/hooks/use_load_action_types.ts index 5bdee57baafc..48b8fdfc20d5 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/hooks/use_load_action_types.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/hooks/use_load_action_types.ts @@ -9,9 +9,9 @@ import { useMemo } from 'react'; import { useLoadActionTypes as loadActionTypes } from '@kbn/elastic-assistant/impl/connectorland/use_load_action_types'; import type { HttpSetup } from '@kbn/core-http-browser'; import type { IToasts } from '@kbn/core-notifications-browser'; -import { AllowedActionTypeIds } from '../../constants'; +import { AIActionTypeIds } from '../constants'; export const useFilteredActionTypes = (http: HttpSetup, toasts: IToasts) => { const { data } = loadActionTypes({ http, toasts }); - return useMemo(() => data?.filter(({ id }) => AllowedActionTypeIds.includes(id)), [data]); + return useMemo(() => data?.filter(({ id }) => AIActionTypeIds.includes(id)), [data]); }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/missing_privileges_tooltip.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/missing_privileges.tsx similarity index 78% rename from x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/missing_privileges_tooltip.tsx rename to x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/missing_privileges.tsx index 811ef72d6763..40e211d85768 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/missing_privileges_tooltip.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/missing_privileges.tsx @@ -5,13 +5,29 @@ * 2.0. */ import React from 'react'; -import { EuiCode, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import { EuiCallOut, EuiCode, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import * as i18n from './translations'; +export const MissingPrivilegesDescription = React.memo(() => { + return ( + <EuiFlexGroup gutterSize="m" direction="column" data-test-subj="missingPrivilegesGroup"> + <EuiFlexItem>{i18n.PRIVILEGES_REQUIRED_TITLE}</EuiFlexItem> + <EuiFlexItem> + <EuiCode> + <ul> + <li>{i18n.REQUIRED_PRIVILEGES_CONNECTORS_ALL}</li> + </ul> + </EuiCode> + </EuiFlexItem> + <EuiFlexItem>{i18n.CONTACT_ADMINISTRATOR}</EuiFlexItem> + </EuiFlexGroup> + ); +}); +MissingPrivilegesDescription.displayName = 'MissingPrivilegesDescription'; + interface MissingPrivilegesTooltip { children: React.ReactElement; // EuiToolTip requires a single ReactElement child } - export const MissingPrivilegesTooltip = React.memo<MissingPrivilegesTooltip>(({ children }) => ( <EuiToolTip anchorProps={{ style: { width: 'fit-content' } }} @@ -23,19 +39,11 @@ export const MissingPrivilegesTooltip = React.memo<MissingPrivilegesTooltip>(({ )); MissingPrivilegesTooltip.displayName = 'MissingPrivilegesTooltip'; -export const MissingPrivilegesDescription = React.memo(() => { +export const MissingPrivilegesCallOut = React.memo(() => { return ( - <EuiFlexGroup gutterSize="m" direction="column" data-test-subj="missingPrivilegesGroup"> - <EuiFlexItem>{i18n.PRIVILEGES_REQUIRED_TITLE}</EuiFlexItem> - <EuiFlexItem> - <EuiCode> - <ul> - <li>{i18n.REQUIRED_PRIVILEGES_CONNECTORS_ALL}</li> - </ul> - </EuiCode> - </EuiFlexItem> - <EuiFlexItem>{i18n.CONTACT_ADMINISTRATOR}</EuiFlexItem> - </EuiFlexGroup> + <EuiCallOut title={i18n.PRIVILEGES_MISSING_TITLE} iconType="iInCircle"> + <MissingPrivilegesDescription /> + </EuiCallOut> ); }); -MissingPrivilegesDescription.displayName = 'MissingPrivilegesDescription'; +MissingPrivilegesCallOut.displayName = 'MissingPrivilegesCallOut'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/translations.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/translations.ts similarity index 100% rename from x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/assistant/connectors/translations.ts rename to x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/common/connectors/translations.ts diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.test.tsx index f7aa198eccab..d654fd9ca5a0 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.test.tsx @@ -17,9 +17,10 @@ const props = { checkComplete: jest.fn(), isCardComplete: jest.fn(), setExpandedCardId: jest.fn(), + isCardAvailable: jest.fn(), }; -describe('RulesCard', () => { +describe('DashboardsCard', () => { beforeEach(() => { jest.clearAllMocks(); }); @@ -34,7 +35,8 @@ describe('RulesCard', () => { expect(getByTestId('dashboardsDescription')).toBeInTheDocument(); }); - it('card callout should be rendered if integrations cards is not complete', () => { + it('card callout should be rendered if integrations card is available but not complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); const { getByText } = render( @@ -46,7 +48,20 @@ describe('RulesCard', () => { expect(getByText('To view dashboards add integrations first.')).toBeInTheDocument(); }); - it('card button should be disabled if integrations cards is not complete', () => { + it('card callout should not be rendered if integrations card is not available', () => { + props.isCardAvailable.mockReturnValueOnce(false); + + const { queryByText } = render( + <TestProviders> + <DashboardsCard {...props} /> + </TestProviders> + ); + + expect(queryByText('To view dashboards add integrations first.')).not.toBeInTheDocument(); + }); + + it('card button should be disabled if integrations card is available but not complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); const { getByTestId } = render( @@ -57,7 +72,22 @@ describe('RulesCard', () => { expect(getByTestId('dashboardsCardButton').querySelector('button')).toBeDisabled(); }); + + it('card button should be enabled if integrations card is complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); + props.isCardComplete.mockReturnValueOnce(true); + + const { getByTestId } = render( + <TestProviders> + <DashboardsCard {...props} /> + </TestProviders> + ); + + expect(getByTestId('dashboardsCardButton').querySelector('button')).not.toBeDisabled(); + }); + it('should expand integrations card when callout link is clicked', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); // To show the callout const { getByTestId } = render( diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx index 201aa4f0d315..db7f6dc9a1f7 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/dashboards_card.tsx @@ -6,22 +6,14 @@ */ import React, { useCallback, useMemo } from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiSpacer, - EuiText, - useEuiTheme, - COLOR_MODES_STANDARD, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiSpacer } from '@elastic/eui'; import { SecurityPageName } from '@kbn/security-solution-navigation'; import { OnboardingCardId } from '../../../../constants'; import type { OnboardingCardComponent } from '../../../../types'; import { OnboardingCardContentImagePanel } from '../common/card_content_image_panel'; import { CardCallOut } from '../common/card_callout'; import { CardLinkButton } from '../common/card_link_button'; +import { CardSubduedText } from '../common/card_subdued_text'; import dashboardsImageSrc from './images/dashboards.png'; import * as i18n from './translations'; @@ -29,15 +21,18 @@ export const DashboardsCard: OnboardingCardComponent = ({ isCardComplete, setComplete, setExpandedCardId, + isCardAvailable, }) => { - const { colorMode } = useEuiTheme(); - const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; - const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] ); + const isIntegrationsCardAvailable = useMemo( + () => isCardAvailable(OnboardingCardId.integrations), + [isCardAvailable] + ); + const expandIntegrationsCard = useCallback(() => { setExpandedCardId(OnboardingCardId.integrations, { scroll: true }); }, [setExpandedCardId]); @@ -54,14 +49,10 @@ export const DashboardsCard: OnboardingCardComponent = ({ alignItems="flexStart" > <EuiFlexItem grow={false}> - <EuiText - data-test-subj="dashboardsDescription" - size="s" - color={isDarkMode ? 'text' : 'subdued'} - > + <CardSubduedText data-test-subj="dashboardsDescription" size="s"> {i18n.DASHBOARDS_CARD_DESCRIPTION} - </EuiText> - {!isIntegrationsCardComplete && ( + </CardSubduedText> + {isIntegrationsCardAvailable && !isIntegrationsCardComplete && ( <> <EuiSpacer size="m" /> <CardCallOut @@ -92,7 +83,7 @@ export const DashboardsCard: OnboardingCardComponent = ({ cardId={OnboardingCardId.dashboards} deepLinkId={SecurityPageName.dashboards} fill - isDisabled={!isIntegrationsCardComplete} + isDisabled={isIntegrationsCardAvailable && !isIntegrationsCardComplete} > {i18n.DASHBOARDS_CARD_GO_TO_DASHBOARDS_BUTTON} </CardLinkButton> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/index.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/index.ts index 356b15f50bf9..6d9bce2e3490 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/index.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/dashboards/index.ts @@ -22,5 +22,5 @@ export const dashboardsCardConfig: OnboardingCardConfig = { './dashboards_card' ) ), - capabilities: ['dashboard.show'], + capabilitiesRequired: ['dashboard.show'], }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.test.tsx index 53e8b6c34e8f..4f5ae2f919d6 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.test.tsx @@ -14,10 +14,10 @@ import React from 'react'; import { render } from '@testing-library/react'; import { AgentRequiredCallout } from './agent_required_callout'; import { TestProviders } from '../../../../../../common/mock/test_providers'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; jest.mock('../../../../../../common/lib/kibana'); -jest.mock('../../../../../common/lib/telemetry'); +jest.mock('../../../../lib/telemetry'); describe('AgentRequiredCallout', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.tsx index b1d18b138487..763dfe749adb 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agent_required_callout.tsx @@ -12,7 +12,7 @@ import { LinkAnchor } from '../../../../../../common/components/links'; import { CardCallOut } from '../../common/card_callout'; import { useNavigation } from '../../../../../../common/lib/kibana'; import { FLEET_APP_ID, ADD_AGENT_PATH, TELEMETRY_AGENT_REQUIRED } from '../constants'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; const fleetAgentLinkProps = { appId: FLEET_APP_ID, path: ADD_AGENT_PATH }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.test.tsx index 7cd3b60c0c6e..e761381747f4 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.test.tsx @@ -10,10 +10,10 @@ import React from 'react'; import { TestProviders } from '../../../../../../common/mock/test_providers'; import { AgentlessAvailableCallout } from './agentless_available_callout'; import { useKibana } from '../../../../../../common/lib/kibana'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; jest.mock('../../../../../../common/lib/kibana'); -jest.mock('../../../../../common/lib/telemetry'); +jest.mock('../../../../lib/telemetry'); describe('AgentlessAvailableCallout', () => { const mockUseKibana = useKibana as jest.Mock; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.tsx index eaf8cbaa3b28..81c4db22f39a 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/agentless_available_callout.tsx @@ -12,7 +12,7 @@ import { css } from '@emotion/react'; import { useKibana } from '../../../../../../common/lib/kibana'; import { LinkAnchor } from '../../../../../../common/components/links'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; import { CardCallOut } from '../../common/card_callout'; import { TELEMETRY_AGENTLESS_LEARN_MORE } from '../constants'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.test.tsx index 50ac060eba24..7d8900335974 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.test.tsx @@ -14,10 +14,10 @@ import React from 'react'; import { render } from '@testing-library/react'; import { EndpointCallout } from './endpoint_callout'; import { TestProviders } from '../../../../../../common/mock/test_providers'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; jest.mock('../../../../../../common/lib/kibana'); -jest.mock('../../../../../common/lib/telemetry'); +jest.mock('../../../../lib/telemetry'); describe('EndpointCallout', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.tsx index d5b0199c9f40..b761a17901a3 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/endpoint_callout.tsx @@ -13,7 +13,7 @@ import { css } from '@emotion/react'; import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; import { LinkAnchor } from '../../../../../../common/components/links'; import { CardCallOut } from '../../common/card_callout'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; import { TELEMETRY_ENDPOINT_LEARN_MORE } from '../constants'; export const EndpointCallout = React.memo(() => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.test.tsx index e0aedafe4559..9cf346aeed90 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.test.tsx @@ -9,10 +9,10 @@ import React from 'react'; import { render, waitFor } from '@testing-library/react'; import { of } from 'rxjs'; import { IntegrationCardTopCallout } from './integration_card_top_callout'; -import { useOnboardingService } from '../../../../../hooks/use_onboarding_service'; +import { useOnboardingService } from '../../../../hooks/use_onboarding_service'; import { IntegrationTabId } from '../types'; -jest.mock('../../../../../hooks/use_onboarding_service', () => ({ +jest.mock('../../../../hooks/use_onboarding_service', () => ({ useOnboardingService: jest.fn(), })); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.tsx index 3a6b5ae3be92..40f4ae95cf08 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/integration_card_top_callout.tsx @@ -8,7 +8,7 @@ import React from 'react'; import useObservable from 'react-use/lib/useObservable'; -import { useOnboardingService } from '../../../../../hooks/use_onboarding_service'; +import { useOnboardingService } from '../../../../hooks/use_onboarding_service'; import { AgentlessAvailableCallout } from './agentless_available_callout'; import { InstalledIntegrationsCallout } from './installed_integrations_callout'; import { IntegrationTabId } from '../types'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/manage_integrations_callout.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/manage_integrations_callout.tsx index 839e5870d4b7..4085f2310d57 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/manage_integrations_callout.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/callouts/manage_integrations_callout.tsx @@ -11,7 +11,7 @@ import { EuiIcon } from '@elastic/eui'; import { LinkAnchor } from '../../../../../../common/components/links'; import { CardCallOut } from '../../common/card_callout'; import { useAddIntegrationsUrl } from '../../../../../../common/hooks/use_add_integrations_url'; -import { trackOnboardingLinkClick } from '../../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../../lib/telemetry'; import { TELEMETRY_MANAGE_INTEGRATIONS } from '../constants'; export const ManageIntegrationsCallout = React.memo( diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/index.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/index.ts index 07e80ab64f52..3568376c192c 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/index.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/index.ts @@ -27,5 +27,5 @@ export const integrationsCardConfig: OnboardingCardConfig<IntegrationCardMetadat ) ), checkComplete: checkIntegrationsCardComplete, - capabilities: 'fleet.read', + capabilitiesRequired: 'fleet.read', }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.test.tsx index c88ffb6a598b..4338fd400e6a 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.test.tsx @@ -13,14 +13,13 @@ import * as module from '@kbn/fleet-plugin/public'; import { useStoredIntegrationSearchTerm, useStoredIntegrationTabId, -} from '../../../../hooks/use_stored_state'; +} from '../../../hooks/use_stored_state'; import { DEFAULT_TAB } from './constants'; -import { trackOnboardingLinkClick } from '../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../lib/telemetry'; jest.mock('../../../onboarding_context'); -jest.mock('../../../../hooks/use_stored_state'); -jest.mock('../../../../common/lib/telemetry'); - +jest.mock('../../../hooks/use_stored_state'); +jest.mock('../../../lib/telemetry'); jest.mock('../../../../../common/lib/kibana', () => ({ ...jest.requireActual('../../../../../common/lib/kibana'), useNavigation: jest.fn().mockReturnValue({ diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx index e1ce7f5cdecf..6b5e3f60a24e 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integration_card_grid_tabs.tsx @@ -14,7 +14,7 @@ import { withLazyHook } from '../../../../../common/components/with_lazy_hook'; import { useStoredIntegrationSearchTerm, useStoredIntegrationTabId, -} from '../../../../hooks/use_stored_state'; +} from '../../../hooks/use_stored_state'; import { useOnboardingContext } from '../../../onboarding_context'; import { DEFAULT_TAB, @@ -29,7 +29,7 @@ import { INTEGRATION_TABS, INTEGRATION_TABS_BY_ID } from './integration_tabs_con import { useIntegrationCardList } from './use_integration_card_list'; import { IntegrationTabId } from './types'; import { IntegrationCardTopCallout } from './callouts/integration_card_top_callout'; -import { trackOnboardingLinkClick } from '../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../lib/telemetry'; export interface IntegrationsCardGridTabsProps { installedIntegrationsCount: number; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integrations_card.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integrations_card.test.tsx index 296d5391fd61..c01fbfa96123 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integrations_card.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/integrations_card.test.tsx @@ -15,6 +15,7 @@ const props = { checkComplete: jest.fn(), isCardComplete: jest.fn(), setExpandedCardId: jest.fn(), + isCardAvailable: jest.fn(), }; describe('IntegrationsCard', () => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.test.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.test.ts index 19ab340276b8..095b2f988e59 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.test.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.test.ts @@ -6,9 +6,9 @@ */ import { renderHook } from '@testing-library/react-hooks'; import { useIntegrationCardList } from './use_integration_card_list'; -import { trackOnboardingLinkClick } from '../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../lib/telemetry'; -jest.mock('../../../../common/lib/telemetry'); +jest.mock('../../../lib/telemetry'); jest.mock('../../../../../common/lib/kibana', () => ({ ...jest.requireActual('../../../../../common/lib/kibana'), useNavigation: jest.fn().mockReturnValue({ diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts index ccea5299551c..660464ba7350 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/integrations/use_integration_card_list.ts @@ -23,7 +23,7 @@ import { TELEMETRY_INTEGRATION_CARD, } from './constants'; import type { GetAppUrl, NavigateTo } from '../../../../../common/lib/kibana'; -import { trackOnboardingLinkClick } from '../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../lib/telemetry'; const addPathParamToUrl = (url: string, onboardingLink: string) => { const encoded = encodeURIComponent(onboardingLink); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.test.tsx index f7156adc34eb..e32d13b787a5 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.test.tsx @@ -13,6 +13,7 @@ const props = { setComplete: jest.fn(), checkComplete: jest.fn(), isCardComplete: jest.fn(), + isCardAvailable: jest.fn(), setExpandedCardId: jest.fn(), }; @@ -31,7 +32,8 @@ describe('RulesCard', () => { expect(getByTestId('rulesCardDescription')).toBeInTheDocument(); }); - it('card callout should be rendered if integrations cards is not complete', () => { + it('card callout should be rendered if integrations card is available but not complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); const { getByText } = render( @@ -43,7 +45,20 @@ describe('RulesCard', () => { expect(getByText('To add Elastic rules add integrations first.')).toBeInTheDocument(); }); - it('card button should be disabled if integrations cards is not complete', () => { + it('card callout should not be rendered if integrations card is not available', () => { + props.isCardAvailable.mockReturnValueOnce(false); + + const { queryByText } = render( + <TestProviders> + <RulesCard {...props} /> + </TestProviders> + ); + + expect(queryByText('To add Elastic rules add integrations first.')).not.toBeInTheDocument(); + }); + + it('card button should be disabled if integrations card is available but not complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); props.isCardComplete.mockReturnValueOnce(false); const { getByTestId } = render( @@ -54,4 +69,17 @@ describe('RulesCard', () => { expect(getByTestId('rulesCardButton').querySelector('button')).toBeDisabled(); }); + + it('card button should be enabled if integrations card is complete', () => { + props.isCardAvailable.mockReturnValueOnce(true); + props.isCardComplete.mockReturnValueOnce(true); + + const { getByTestId } = render( + <TestProviders> + <RulesCard {...props} /> + </TestProviders> + ); + + expect(getByTestId('rulesCardButton').querySelector('button')).not.toBeDisabled(); + }); }); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx index 50c722d49c35..c1eb789d6a46 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/rules/rules_card.tsx @@ -6,34 +6,32 @@ */ import React, { useCallback, useMemo } from 'react'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiLink, - EuiSpacer, - EuiText, - useEuiTheme, - COLOR_MODES_STANDARD, -} from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiSpacer } from '@elastic/eui'; import { SecurityPageName } from '@kbn/security-solution-navigation'; import { SecuritySolutionLinkButton } from '../../../../../common/components/links'; import { OnboardingCardId } from '../../../../constants'; import type { OnboardingCardComponent } from '../../../../types'; import { OnboardingCardContentImagePanel } from '../common/card_content_image_panel'; import { CardCallOut } from '../common/card_callout'; +import { CardSubduedText } from '../common/card_subdued_text'; import rulesImageSrc from './images/rules.png'; import * as i18n from './translations'; -export const RulesCard: OnboardingCardComponent = ({ isCardComplete, setExpandedCardId }) => { - const { colorMode } = useEuiTheme(); - const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; - +export const RulesCard: OnboardingCardComponent = ({ + isCardComplete, + setExpandedCardId, + isCardAvailable, +}) => { const isIntegrationsCardComplete = useMemo( () => isCardComplete(OnboardingCardId.integrations), [isCardComplete] ); + const isIntegrationsCardAvailable = useMemo( + () => isCardAvailable(OnboardingCardId.integrations), + [isCardAvailable] + ); + const expandIntegrationsCard = useCallback(() => { setExpandedCardId(OnboardingCardId.integrations, { scroll: true }); }, [setExpandedCardId]); @@ -47,14 +45,10 @@ export const RulesCard: OnboardingCardComponent = ({ isCardComplete, setExpanded alignItems="flexStart" > <EuiFlexItem grow={false}> - <EuiText - data-test-subj="rulesCardDescription" - size="s" - color={isDarkMode ? 'text' : 'subdued'} - > + <CardSubduedText data-test-subj="rulesCardDescription" size="s"> {i18n.RULES_CARD_DESCRIPTION} - </EuiText> - {!isIntegrationsCardComplete && ( + </CardSubduedText> + {isIntegrationsCardAvailable && !isIntegrationsCardComplete && ( <> <EuiSpacer size="m" /> <CardCallOut @@ -79,7 +73,7 @@ export const RulesCard: OnboardingCardComponent = ({ isCardComplete, setExpanded <SecuritySolutionLinkButton deepLinkId={SecurityPageName.rules} fill - isDisabled={!isIntegrationsCardComplete} + isDisabled={isIntegrationsCardAvailable && !isIntegrationsCardComplete} > {i18n.RULES_CARD_ADD_RULES_BUTTON} </SecuritySolutionLinkButton> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/ai_connector_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/ai_connector_card.tsx new file mode 100644 index 000000000000..127e6b4d57eb --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/ai_connector_card.tsx @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useCallback } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiText, + useEuiTheme, + COLOR_MODES_STANDARD, +} from '@elastic/eui'; +import { useKibana } from '../../../../../../common/lib/kibana/kibana_react'; +import { useDefinedLocalStorage } from '../../../../hooks/use_stored_state'; +import type { OnboardingCardComponent } from '../../../../../types'; +import * as i18n from './translations'; +import { OnboardingCardContentPanel } from '../../common/card_content_panel'; +import { ConnectorCards } from '../../common/connectors/connector_cards'; +import type { AIConnectorCardMetadata } from './types'; +import { MissingPrivilegesCallOut } from '../../common/connectors/missing_privileges'; + +export const AIConnectorCard: OnboardingCardComponent<AIConnectorCardMetadata> = ({ + checkCompleteMetadata, + checkComplete, + setComplete, +}) => { + const { siemMigrations } = useKibana().services; + const { euiTheme, colorMode } = useEuiTheme(); + const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + + const [storedConnectorId, setStoredConnectorId] = useDefinedLocalStorage<string | null>( + siemMigrations.rules.connectorIdStorage.key, + null + ); + const setSelectedConnectorId = useCallback( + (connectorId: string) => { + setStoredConnectorId(connectorId); + setComplete(true); + }, + [setComplete, setStoredConnectorId] + ); + + const connectors = checkCompleteMetadata?.connectors; + const canExecuteConnectors = checkCompleteMetadata?.canExecuteConnectors; + const canCreateConnectors = checkCompleteMetadata?.canCreateConnectors; + + return ( + <OnboardingCardContentPanel + style={{ + paddingTop: 0, + ...(isDarkMode && { backgroundColor: euiTheme.colors.lightestShade }), + }} + > + {canExecuteConnectors ? ( + <EuiFlexGroup direction="column"> + <EuiFlexItem grow={false}> + <EuiText size="s" color={isDarkMode ? 'text' : 'subdued'}> + {i18n.AI_CONNECTOR_CARD_DESCRIPTION} + </EuiText> + </EuiFlexItem> + <EuiFlexItem> + <ConnectorCards + canCreateConnectors={canCreateConnectors} + connectors={connectors} + onConnectorSaved={checkComplete} + selectedConnectorId={storedConnectorId} + setSelectedConnectorId={setSelectedConnectorId} + /> + </EuiFlexItem> + </EuiFlexGroup> + ) : ( + <MissingPrivilegesCallOut /> + )} + </OnboardingCardContentPanel> + ); +}; + +// eslint-disable-next-line import/no-default-export +export default AIConnectorCard; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/connectors_check_complete.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/connectors_check_complete.ts new file mode 100644 index 000000000000..d7121fe97cf7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/connectors_check_complete.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { loadAllActions as loadConnectors } from '@kbn/triggers-actions-ui-plugin/public/common/constants'; +import type { AIConnector } from '@kbn/elastic-assistant/impl/connectorland/connector_selector'; +import type { OnboardingCardCheckComplete } from '../../../../../types'; +import { AIActionTypeIds } from '../../common/connectors/constants'; +import type { AIConnectorCardMetadata } from './types'; + +export const checkAssistantCardComplete: OnboardingCardCheckComplete< + AIConnectorCardMetadata +> = async ({ http, application, siemMigrations }) => { + let isComplete = false; + const allConnectors = await loadConnectors({ http }); + const { capabilities } = application; + + const aiConnectors = allConnectors.reduce((acc: AIConnector[], connector) => { + if (!connector.isMissingSecrets && AIActionTypeIds.includes(connector.actionTypeId)) { + acc.push(connector); + } + return acc; + }, []); + + const storedConnectorId = siemMigrations.rules.connectorIdStorage.get(); + if (storedConnectorId) { + if (aiConnectors.length === 0) { + siemMigrations.rules.connectorIdStorage.remove(); + } else { + isComplete = aiConnectors.some((connector) => connector.id === storedConnectorId); + } + } + + return { + isComplete, + metadata: { + connectors: aiConnectors, + canExecuteConnectors: Boolean(capabilities.actions?.show && capabilities.actions?.execute), + canCreateConnectors: Boolean(capabilities.actions?.save), + }, + }; +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts new file mode 100644 index 000000000000..45080123889d --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/index.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { AssistantAvatar } from '@kbn/elastic-assistant'; +import type { OnboardingCardConfig } from '../../../../../types'; +import { OnboardingCardId } from '../../../../../constants'; +import { AI_CONNECTOR_CARD_TITLE } from './translations'; +import { checkAssistantCardComplete } from './connectors_check_complete'; +import type { AIConnectorCardMetadata } from './types'; + +export const aiConnectorCardConfig: OnboardingCardConfig<AIConnectorCardMetadata> = { + id: OnboardingCardId.siemMigrationsAiConnectors, + title: AI_CONNECTOR_CARD_TITLE, + icon: AssistantAvatar, + Component: React.lazy( + () => + import( + /* webpackChunkName: "onboarding_siem_migrations_ai_connector_card" */ + './ai_connector_card' + ) + ), + checkComplete: checkAssistantCardComplete, + licenseTypeRequired: 'enterprise', +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/translations.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/translations.ts new file mode 100644 index 000000000000..c05951e1ddf2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/translations.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const AI_CONNECTOR_CARD_TITLE = i18n.translate( + 'xpack.securitySolution.onboarding.aiConnector.title', + { + defaultMessage: 'Configure AI Provider', + } +); + +export const AI_CONNECTOR_CARD_DESCRIPTION = i18n.translate( + 'xpack.securitySolution.onboarding.aiConnector.description', + { + defaultMessage: + 'Choose and configure any AI provider available to start a SIEM rules migration.', + } +); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/types.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/types.ts new file mode 100644 index 000000000000..3e0a471da6f5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/cards/siem_migrations/ai_connector/types.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ActionConnector } from '@kbn/alerts-ui-shared'; + +export interface AIConnectorCardMetadata { + connectors: ActionConnector[]; + canExecuteConnectors: boolean; + canCreateConnectors: boolean; +} diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.test.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.test.ts index 775ff09546fe..c2c89594669c 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.test.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.test.ts @@ -6,112 +6,59 @@ */ import { renderHook } from '@testing-library/react-hooks'; import { useBodyConfig } from './use_body_config'; -import { useKibana } from '../../../../common/lib/kibana/kibana_react'; -import useObservable from 'react-use/lib/useObservable'; -import { hasCapabilities } from '../../../../common/lib/capabilities'; +import { mockOnboardingContext, onboardingContext } from '../../__mocks__/mocks'; -const bodyConfig = [ - { - title: 'Group 1', - cards: [ - { - id: 'license_card', - title: 'licensed card', - icon: 'fleetApp', - licenseType: 'platinum', - }, - { - id: 'capabilities_card', - title: 'rbac card', - icon: 'fleetApp', - capabilities: ['siem.crud'], - }, - ], - }, - { - title: 'Group 2', - cards: [ - { - id: 'capabilities_license_card', - title: 'all card', - icon: 'fleetApp', - capabilities: ['siem.crud'], - licenseType: 'platinum', - }, - ], - }, -]; +const topicId = 'topic-id'; +const mockUseTopicId = jest.fn(() => topicId); +jest.mock('../../hooks/use_topic_id', () => ({ + useTopicId: () => mockUseTopicId(), +})); -// Mock dependencies -jest.mock('react-use/lib/useObservable'); -jest.mock('../../../../common/lib/kibana/kibana_react'); -jest.mock('../../../../common/lib/capabilities'); -jest.mock('../body_config', () => ({ bodyConfig })); +const defaultBodyConfig = [{ title: 'Default Group 1', cards: [] }]; +const bodyConfig = [{ title: 'Group 1', cards: [] }]; +const config = new Map([ + ['default', { body: defaultBodyConfig }], + [topicId, { body: bodyConfig }], +]); -const mockLicenseHasAtLeast = jest.fn(); -const mockUseObservable = useObservable as jest.Mock; -const mockHasCapabilities = hasCapabilities as jest.Mock; -mockUseObservable.mockReturnValue({ hasAtLeast: mockLicenseHasAtLeast }); - -(useKibana as jest.Mock).mockReturnValue({ - services: { application: { capabilities: {} }, licensing: {} }, -}); +jest.mock('../../onboarding_context'); describe('useBodyConfig', () => { beforeEach(() => { - mockLicenseHasAtLeast.mockReturnValue(true); - mockHasCapabilities.mockReturnValue(true); jest.clearAllMocks(); }); - it('should return an empty array if license is not defined', () => { - mockUseObservable.mockReturnValueOnce(undefined); - const { result } = renderHook(useBodyConfig); - expect(result.current).toEqual([]); - }); + describe('when the selected topic does not have a body config', () => { + beforeEach(() => { + mockOnboardingContext.mockReturnValue({ ...onboardingContext, config: new Map() }); + }); - it('should return all cards if no capabilities or licenseType are filtered', () => { - const { result } = renderHook(useBodyConfig); - expect(result.current).toEqual(bodyConfig); + it('should return an empty array', () => { + const { result } = renderHook(() => useBodyConfig()); + expect(result.current).toEqual([]); + }); }); - it('should filter out cards based on license', () => { - mockLicenseHasAtLeast.mockReturnValue(false); + describe('when the selected topic has a body config', () => { + beforeEach(() => { + mockOnboardingContext.mockReturnValue({ ...onboardingContext, config }); + }); - const { result } = renderHook(useBodyConfig); - - expect(result.current).toEqual([ - { - title: 'Group 1', - cards: [ - { - id: 'capabilities_card', - title: 'rbac card', - icon: 'fleetApp', - capabilities: ['siem.crud'], - }, - ], - }, - ]); + it('should return the body config for the selected topic', () => { + const { result } = renderHook(() => useBodyConfig()); + expect(result.current).toEqual(bodyConfig); + }); }); - it('should filter out cards based on capabilities', () => { - mockHasCapabilities.mockReturnValue(false); - - const { result } = renderHook(useBodyConfig); + describe('when the selected topic does not exist (not expected)', () => { + beforeEach(() => { + mockUseTopicId.mockReturnValue('non-existent-topic'); + mockOnboardingContext.mockReturnValue({ ...onboardingContext, config }); + }); - expect(result.current).toEqual([ - { - title: 'Group 1', - cards: [ - { - id: 'license_card', - title: 'licensed card', - icon: 'fleetApp', - licenseType: 'platinum', - }, - ], - }, - ]); + it('should return the body config for the selected topic', () => { + const { result } = renderHook(() => useBodyConfig()); + expect(result.current).toEqual([]); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.ts index f7b12e5988c0..0d6a26a3439d 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_body_config.ts @@ -5,51 +5,26 @@ * 2.0. */ -import useObservable from 'react-use/lib/useObservable'; import { useMemo } from 'react'; -import { hasCapabilities } from '../../../../common/lib/capabilities'; -import { useKibana } from '../../../../common/lib/kibana/kibana_react'; -import { bodyConfig } from '../body_config'; +import { useOnboardingContext } from '../../onboarding_context'; +import { useTopicId } from '../../hooks/use_topic_id'; import type { OnboardingGroupConfig } from '../../../types'; /** - * Hook that filters the config based on the user's capabilities and license + * Hook that returns the body config for the selected topic */ -export const useBodyConfig = () => { - const { application, licensing } = useKibana().services; - const license = useObservable(licensing.license$); - - const filteredBodyConfig = useMemo(() => { - // Return empty array when the license is not defined. It should always become defined at some point. - // This exit case prevents code dependant on the cards config (like completion checks) from running multiple times. - if (!license) { - return []; +export const useBodyConfig = (): OnboardingGroupConfig[] => { + const topicId = useTopicId(); + const { config } = useOnboardingContext(); + const topicBodyConfig = useMemo(() => { + let bodyConfig: OnboardingGroupConfig[] = []; + const topicConfig = config.get(topicId); + // The selected topic should always exist in the config, but we check just in case + if (topicConfig) { + bodyConfig = topicConfig.body; } - return bodyConfig.reduce<OnboardingGroupConfig[]>((filteredGroups, group) => { - const filteredCards = group.cards.filter((card) => { - if (card.capabilities) { - const cardHasCapabilities = hasCapabilities(application.capabilities, card.capabilities); - if (!cardHasCapabilities) { - return false; - } - } - - if (card.licenseType) { - const cardHasLicense = license.hasAtLeast(card.licenseType); - if (!cardHasLicense) { - return false; - } - } - - return true; - }); - - if (filteredCards.length > 0) { - filteredGroups.push({ ...group, cards: filteredCards }); - } - return filteredGroups; - }, []); - }, [license, application.capabilities]); + return bodyConfig; + }, [config, topicId]); - return filteredBodyConfig; + return topicBodyConfig; }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.test.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.test.ts index 2c9fcd573f0d..1ace059a5115 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.test.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.test.ts @@ -6,11 +6,10 @@ */ import { renderHook, act, type RenderHookResult } from '@testing-library/react-hooks'; -import { waitFor } from '@testing-library/react'; import { useCompletedCards } from './use_completed_cards'; import type { OnboardingGroupConfig } from '../../../types'; import type { OnboardingCardId } from '../../../constants'; -import { mockReportCardComplete } from '../../__mocks__/onboarding_context_mocks'; +import { mockReportCardComplete } from '../../__mocks__/mocks'; import { useKibana } from '../../../../common/lib/kibana'; const defaultStoredCompletedCardIds: OnboardingCardId[] = []; @@ -20,8 +19,8 @@ const mockUseStoredCompletedCardIds = jest.fn(() => [ defaultStoredCompletedCardIds, mockSetStoredCompletedCardIds, ]); -jest.mock('../../../hooks/use_stored_state', () => ({ - ...jest.requireActual('../../../hooks/use_stored_state'), +jest.mock('../../hooks/use_stored_state', () => ({ + ...jest.requireActual('../../hooks/use_stored_state'), useStoredCompletedCardIds: () => mockUseStoredCompletedCardIds(), })); @@ -99,6 +98,8 @@ const mockFailureCardsGroupConfig = [ }, ] as unknown as OnboardingGroupConfig[]; +const flushPromises = () => new Promise(setImmediate); + describe('useCompletedCards Hook', () => { beforeEach(() => { jest.clearAllMocks(); @@ -114,11 +115,7 @@ describe('useCompletedCards Hook', () => { services: { notifications: { toasts: { addError: mockAddError } } }, }); renderResult = renderHook(useCompletedCards, { initialProps: mockFailureCardsGroupConfig }); - await act(async () => { - await waitFor(() => { - expect(mockSetStoredCompletedCardIds).toHaveBeenCalledTimes(0); // number of completed cards - }); - }); + await act(flushPromises); }); describe('when a the auto check is called', () => { @@ -158,11 +155,7 @@ describe('useCompletedCards Hook', () => { >; beforeEach(async () => { renderResult = renderHook(useCompletedCards, { initialProps: mockCardsGroupConfig }); - await act(async () => { - await waitFor(() => { - expect(mockSetStoredCompletedCardIds).toHaveBeenCalledTimes(4); // number of completed cards - }); - }); + await act(flushPromises); }); it('should set the correct completed card ids', async () => { @@ -258,12 +251,8 @@ describe('useCompletedCards Hook', () => { beforeEach(async () => { jest.clearAllMocks(); cardIncomplete.checkComplete.mockResolvedValueOnce(true); - await act(async () => { - renderResult.result.current.checkCardComplete(cardIncomplete.id); - await waitFor(() => { - expect(mockSetStoredCompletedCardIds).toHaveBeenCalledTimes(1); - }); - }); + renderResult.result.current.checkCardComplete(cardIncomplete.id); + await act(flushPromises); }); it('should set the correct completed card ids', async () => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.ts index 34092bf2d5ee..8f3bcf0b618d 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_completed_cards.ts @@ -5,15 +5,15 @@ * 2.0. */ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useKibana } from '../../../../common/lib/kibana'; -import { useStoredCompletedCardIds } from '../../../hooks/use_stored_state'; +import { useStoredCompletedCardIds } from '../../hooks/use_stored_state'; import type { OnboardingCardId } from '../../../constants'; import type { CheckCompleteResult, CheckCompleteResponse, - OnboardingGroupConfig, OnboardingCardConfig, + OnboardingGroupConfig, } from '../../../types'; import { useOnboardingContext } from '../../onboarding_context'; @@ -32,10 +32,9 @@ export type CardCheckCompleteResult = Partial<Record<OnboardingCardId, CheckComp /** * This hook implements the logic for tracking which onboarding cards have been completed using Local Storage. */ -export const useCompletedCards = (cardsGroupConfig: OnboardingGroupConfig[]) => { - const { spaceId, reportCardComplete } = useOnboardingContext(); +export const useCompletedCards = (bodyConfig: OnboardingGroupConfig[]) => { + const { spaceId, telemetry } = useOnboardingContext(); const services = useKibana().services; - const autoCheckCompletedRef = useRef<boolean>(false); // Use stored state to keep localStorage in sync, and a local state to avoid unnecessary re-renders. const [storedCompleteCardIds, setStoredCompleteCardIds] = useStoredCompletedCardIds(spaceId); @@ -55,7 +54,7 @@ export const useCompletedCards = (cardsGroupConfig: OnboardingGroupConfig[]) => const isCurrentlyComplete = currentCompleteCards.includes(cardId); if (completed && !isCurrentlyComplete) { const newCompleteCardIds = [...currentCompleteCards, cardId]; - reportCardComplete(cardId, options); + telemetry.reportCardComplete(cardId, options); setStoredCompleteCardIds(newCompleteCardIds); // Keep the stored state in sync with the local state return newCompleteCardIds; } else if (!completed && isCurrentlyComplete) { @@ -66,7 +65,7 @@ export const useCompletedCards = (cardsGroupConfig: OnboardingGroupConfig[]) => return currentCompleteCards; // No change }); }, - [reportCardComplete, setStoredCompleteCardIds] // static dependencies, this function needs to be stable + [setStoredCompleteCardIds, telemetry] // static dependencies, this function needs to be stable ); const getCardCheckCompleteResult = useCallback<GetCardCheckCompleteResult>( @@ -88,11 +87,11 @@ export const useCompletedCards = (cardsGroupConfig: OnboardingGroupConfig[]) => // Internal: stores all cards that have a checkComplete function in a flat array const cardsWithAutoCheck = useMemo( () => - cardsGroupConfig.reduce<OnboardingCardConfig[]>((acc, group) => { + bodyConfig.reduce<OnboardingCardConfig[]>((acc, group) => { acc.push(...group.cards.filter((card) => card.checkComplete)); return acc; }, []), - [cardsGroupConfig] + [bodyConfig] ); // Internal: sets the result of a checkComplete function @@ -118,9 +117,7 @@ export const useCompletedCards = (cardsGroupConfig: OnboardingGroupConfig[]) => .checkComplete?.(services) .catch((err: Error) => { services.notifications.toasts.addError(err, { title: cardConfig.title }); - return { - isComplete: false, - }; + return { isComplete: false }; }) .then((checkCompleteResult) => { processCardCheckCompleteResult(cardId, checkCompleteResult); @@ -131,19 +128,13 @@ export const useCompletedCards = (cardsGroupConfig: OnboardingGroupConfig[]) => ); useEffect(() => { - // Initial auto-check for all cards, it should run only once, after cardsGroupConfig is properly populated - if (cardsWithAutoCheck.length === 0 || autoCheckCompletedRef.current) { - return; - } - autoCheckCompletedRef.current = true; + // Initial auto-check for all body cards, it should run once per `bodyConfig` (topic) change. cardsWithAutoCheck.map((card) => card .checkComplete?.(services) .catch((err: Error) => { services.notifications.toasts.addError(err, { title: card.title }); - return { - isComplete: false, - }; + return { isComplete: false }; }) .then((checkCompleteResult) => { processCardCheckCompleteResult(card.id, checkCompleteResult); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.test.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.test.ts index 55f60e591c17..26612d83b565 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.test.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.test.ts @@ -9,16 +9,14 @@ import { renderHook, act } from '@testing-library/react-hooks'; import { useExpandedCard } from './use_expanded_card'; import { HEIGHT_ANIMATION_DURATION } from '../onboarding_card_panel.styles'; import type { OnboardingCardId } from '../../../constants'; -import { mockReportCardOpen } from '../../__mocks__/onboarding_context_mocks'; import { waitFor } from '@testing-library/react'; const scrollTimeout = HEIGHT_ANIMATION_DURATION + 50; -const mockSetStorageExpandedCardId = jest.fn(); -const mockUseStoredExpandedCardId = jest.fn(() => [null, mockSetStorageExpandedCardId]); -jest.mock('../../../hooks/use_stored_state', () => ({ - ...jest.requireActual('../../../hooks/use_stored_state'), - useStoredExpandedCardId: () => mockUseStoredExpandedCardId(), +const mockSetCardDetail = jest.fn(); +jest.mock('../../hooks/use_url_detail', () => ({ + ...jest.requireActual('../../hooks/use_url_detail'), + useUrlDetail: () => ({ setCardDetail: mockSetCardDetail }), })); jest.mock('react-router-dom', () => ({ @@ -26,14 +24,10 @@ jest.mock('react-router-dom', () => ({ useLocation: () => ({ hash: '#card-1', pathname: '/test' }), })); -jest.mock('../../onboarding_context'); - describe('useExpandedCard Hook', () => { const mockCardId = 'card-1' as OnboardingCardId; const mockScrollTo = jest.fn(); global.window.scrollTo = mockScrollTo; - const mockReplaceState = jest.fn(); - global.history.replaceState = mockReplaceState; const mockGetElementById = jest.fn().mockReturnValue({ focus: jest.fn(), @@ -45,40 +39,11 @@ describe('useExpandedCard Hook', () => { jest.clearAllMocks(); }); - describe('when the page is loading', () => { - beforeEach(() => { - Object.defineProperty(document, 'readyState', { - value: 'loading', - configurable: true, - }); - }); - - it('should not scroll if the page is not fully loaded', async () => { - renderHook(useExpandedCard); - - // Ensure that scroll and focus were triggered - await waitFor( - () => { - expect(mockScrollTo).not.toHaveBeenCalled(); - }, - { timeout: scrollTimeout } - ); - }); - }); - describe('when the page is completely loaded', () => { beforeEach(() => { - Object.defineProperty(document, 'readyState', { - value: 'complete', - configurable: true, - }); renderHook(useExpandedCard); }); - it('should set the expanded card id from the hash', () => { - expect(mockSetStorageExpandedCardId).toHaveBeenCalledWith(mockCardId); - }); - it('should scroll to the expanded card id from the hash', async () => { // Ensure that scroll and focus were triggered await waitFor( @@ -89,10 +54,6 @@ describe('useExpandedCard Hook', () => { { timeout: scrollTimeout } ); }); - - it('should report the expanded card id from the hash', () => { - expect(mockReportCardOpen).toHaveBeenCalledWith(mockCardId, { auto: true }); - }); }); describe('when the card is expanded manually', () => { @@ -111,12 +72,8 @@ describe('useExpandedCard Hook', () => { }); }); - it('should set the expanded card id in storage', () => { - expect(mockSetStorageExpandedCardId).toHaveBeenCalledWith(mockCardId); - }); - - it('should set the URL hash', () => { - expect(mockReplaceState).toHaveBeenCalledWith(null, '', `#${mockCardId}`); + it('should set the expanded card id', () => { + expect(mockSetCardDetail).toHaveBeenCalledWith(mockCardId); }); it('should not scroll', async () => { @@ -129,10 +86,6 @@ describe('useExpandedCard Hook', () => { { timeout: scrollTimeout } ); }); - - it('should report the expanded card id', () => { - expect(mockReportCardOpen).toHaveBeenCalledWith(mockCardId); - }); }); describe('when scroll is enabled', () => { @@ -143,12 +96,8 @@ describe('useExpandedCard Hook', () => { }); }); - it('should set the expanded card id in storage', () => { - expect(mockSetStorageExpandedCardId).toHaveBeenCalledWith(mockCardId); - }); - - it('should set the URL hash', () => { - expect(mockReplaceState).toHaveBeenCalledWith(null, '', `#${mockCardId}`); + it('should set the expanded card id', () => { + expect(mockSetCardDetail).toHaveBeenCalledWith(mockCardId); }); it('should scroll', async () => { @@ -161,10 +110,6 @@ describe('useExpandedCard Hook', () => { { timeout: scrollTimeout } ); }); - - it('should report the expanded card id', () => { - expect(mockReportCardOpen).toHaveBeenCalledWith(mockCardId); - }); }); }); }); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.ts index 131953e4b068..514618390695 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/hooks/use_expanded_card.ts @@ -5,13 +5,12 @@ * 2.0. */ -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useLocation } from 'react-router-dom'; -import { useStoredExpandedCardId } from '../../../hooks/use_stored_state'; import { HEIGHT_ANIMATION_DURATION } from '../onboarding_card_panel.styles'; -import type { OnboardingCardId } from '../../../constants'; +import { type OnboardingCardId } from '../../../constants'; import type { SetExpandedCardId } from '../../../types'; -import { useOnboardingContext } from '../../onboarding_context'; +import { getCardIdFromHash, useUrlDetail } from '../../hooks/use_url_detail'; const HEADER_OFFSET = 40; @@ -25,59 +24,36 @@ const scrollToCard = (cardId: OnboardingCardId) => { }, HEIGHT_ANIMATION_DURATION); }; -const setHash = (cardId: OnboardingCardId | null) => { - history.replaceState(null, '', cardId == null ? ' ' : `#${cardId}`); -}; - /** * This hook manages the expanded card id state in the LocalStorage and the hash in the URL. */ export const useExpandedCard = () => { - const { spaceId, reportCardOpen } = useOnboardingContext(); - const [expandedCardId, setStorageExpandedCardId] = useStoredExpandedCardId(spaceId); - const location = useLocation(); - - const [documentReadyState, setReadyState] = useState(document.readyState); + const { setCardDetail } = useUrlDetail(); + const { hash } = useLocation(); + const cardIdFromHash = useMemo(() => getCardIdFromHash(hash), [hash]); - useEffect(() => { - const readyStateListener = () => setReadyState(document.readyState); - document.addEventListener('readystatechange', readyStateListener); - return () => document.removeEventListener('readystatechange', readyStateListener); - }, []); + const [cardId, setCardId] = useState<OnboardingCardId | null>(null); - // This effect implements auto-scroll in the initial render, further changes in the hash should not trigger this effect + // This effect implements auto-scroll in the initial render. useEffect(() => { - if (documentReadyState !== 'complete') return; // Wait for page to finish loading before scrolling - let cardIdFromHash = location.hash.split('?')[0].replace('#', '') as OnboardingCardId | ''; - if (!cardIdFromHash) { - if (expandedCardId == null) return; - // If the hash is empty, but it is defined the storage we use the storage value - cardIdFromHash = expandedCardId; - setHash(cardIdFromHash); - } - - // If the hash is defined and different from the storage, the hash takes precedence - if (expandedCardId !== cardIdFromHash) { - setStorageExpandedCardId(cardIdFromHash); - reportCardOpen(cardIdFromHash, { auto: true }); + if (cardIdFromHash) { + setCardId(cardIdFromHash); + scrollToCard(cardIdFromHash); } - scrollToCard(cardIdFromHash); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [documentReadyState]); + // cardIdFromHash is only defined once on page load + // it does not change with subsequent url hash changes since history.replaceState is used + }, [cardIdFromHash]); const setExpandedCardId = useCallback<SetExpandedCardId>( - (cardId, options) => { - setStorageExpandedCardId(cardId); - setHash(cardId); - if (cardId != null) { - reportCardOpen(cardId); - if (options?.scroll) { - scrollToCard(cardId); - } + (newCardId, options) => { + setCardId(newCardId); + setCardDetail(newCardId); + if (newCardId != null && options?.scroll) { + scrollToCard(newCardId); } }, - [setStorageExpandedCardId, reportCardOpen] + [setCardDetail] ); - return { expandedCardId, setExpandedCardId }; + return { expandedCardId: cardId, setExpandedCardId }; }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_body.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_body.tsx index 3209028e1f0c..947a0dff4634 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_body.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_body.tsx @@ -14,10 +14,10 @@ import { OnboardingCardGroup } from './onboarding_card_group'; import { OnboardingCardPanel } from './onboarding_card_panel'; import { useExpandedCard } from './hooks/use_expanded_card'; import { useCompletedCards } from './hooks/use_completed_cards'; +import type { IsCardAvailable } from '../../types'; export const OnboardingBody = React.memo(() => { const bodyConfig = useBodyConfig(); - const { expandedCardId, setExpandedCardId } = useExpandedCard(); const { isCardComplete, setCardComplete, getCardCheckCompleteResult, checkCardComplete } = useCompletedCards(bodyConfig); @@ -48,6 +48,12 @@ export const OnboardingBody = React.memo(() => { [checkCardComplete] ); + const isCardAvailable = useCallback<IsCardAvailable>( + (cardId: OnboardingCardId) => + bodyConfig.some((group) => group.cards.some((card) => card.id === cardId)), + [bodyConfig] + ); + return ( <EuiFlexGroup direction="column" gutterSize="xl"> {bodyConfig.map((group, index) => ( @@ -73,6 +79,7 @@ export const OnboardingBody = React.memo(() => { setComplete={createSetCardComplete(id)} checkComplete={createCheckCardComplete(id)} isCardComplete={isCardComplete} + isCardAvailable={isCardAvailable} setExpandedCardId={setExpandedCardId} checkCompleteMetadata={cardCheckCompleteResult?.metadata} /> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_card_panel.styles.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_card_panel.styles.ts index a01d80b27488..ca3e3e765b97 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_card_panel.styles.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_body/onboarding_card_panel.styles.ts @@ -14,6 +14,7 @@ export const useCardPanelStyles = () => { const { euiTheme, colorMode } = useEuiTheme(); const successBackgroundColor = useEuiBackgroundColor('success'); const isDarkMode = colorMode === COLOR_MODES_STANDARD.dark; + const darkModeStyles = useDarkPanelStyles(isDarkMode); return css` .onboardingCardHeader { @@ -57,11 +58,15 @@ export const useCardPanelStyles = () => { background-color: ${successBackgroundColor}; } } - ${isDarkMode - ? ` - background-color: ${euiTheme.colors.lightestShade}; - border: 1px solid ${euiTheme.colors.mediumShade}; - ` - : ''} + ${darkModeStyles} `; }; + +export const useDarkPanelStyles = (isDarkMode: boolean) => { + const { euiTheme } = useEuiTheme(); + const darkPanelStyles = css` + background-color: ${euiTheme.colors.lightestShade}; + border-color: ${euiTheme.colors.mediumShade}; + `; + return isDarkMode ? darkPanelStyles : ''; +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.test.tsx new file mode 100644 index 000000000000..cb395996903b --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.test.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { renderHook } from '@testing-library/react'; +import { OnboardingContextProvider, useOnboardingContext } from './onboarding_context'; +import { useLicense } from '../../common/hooks/use_license'; +import { hasCapabilities } from '../../common/lib/capabilities'; +import { ExperimentalFeaturesService } from '../../common/experimental_features_service'; + +jest.mock('../../common/lib/kibana/kibana_react', () => ({ + useKibana: jest.fn().mockReturnValue({ services: { application: { capabilities: {} } } }), +})); +jest.mock('../../common/lib/capabilities', () => ({ hasCapabilities: jest.fn() })); +const mockHasCapabilities = hasCapabilities as jest.Mock; + +jest.mock('../../common/hooks/use_license', () => ({ useLicense: jest.fn() })); +const mockUseLicense = useLicense as jest.Mock; + +jest.mock('../../common/experimental_features_service', () => ({ + ExperimentalFeaturesService: { get: jest.fn() }, +})); +const mockExperimentalFeatures = ExperimentalFeaturesService.get as jest.Mock; + +jest.mock('../config', () => ({ + onboardingConfig: [ + { + id: 'default', + body: [ + { + id: 'defaultGroup1', + cards: [{ id: 'defaultCard1' }], + }, + ], + }, + { + id: 'topic1', + experimentalFlagRequired: 'flag1', + licenseTypeRequired: 'gold', + capabilitiesRequired: ['capability1'], + body: [ + { + id: 'topic1Group1', + cards: [{ id: 'topic1Card1' }], + }, + ], + }, + { + id: 'topic2', + body: [ + { + id: 'topic2Group1', + cards: [ + { id: 'topic2Card1', experimentalFlagRequired: 'flag1' }, + { id: 'topic2Card2', licenseTypeRequired: 'gold' }, + { id: 'topic2Card3', capabilitiesRequired: ['capability1'] }, + ], + }, + ], + }, + ], +})); + +const wrapper: React.FC<React.PropsWithChildren<{}>> = ({ children }) => ( + <OnboardingContextProvider spaceId="space1">{children}</OnboardingContextProvider> +); + +describe('OnboardingContextProvider', () => { + describe('config', () => { + beforeEach(() => { + jest.clearAllMocks(); + mockExperimentalFeatures.mockReturnValue({ flag1: true }); + mockUseLicense.mockReturnValue({ isAtLeast: jest.fn(() => true) }); + mockHasCapabilities.mockReturnValue(true); + }); + + describe('when all requirements are met', () => { + it('should return all topics config correctly', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(3); + expect(result.current.config).toMatchSnapshot(); + }); + }); + + describe('when the required experimental flag is not met', () => { + beforeEach(() => { + mockExperimentalFeatures.mockReturnValue({}); + }); + + it('should filter the topics config correctly', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(2); + expect(result.current.config).toMatchSnapshot(); + }); + + describe('and the required license is not met either', () => { + beforeEach(() => { + mockUseLicense.mockReturnValue({ isAtLeast: jest.fn(() => false) }); + }); + + it('should filter the topics config correctly', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(2); + expect(result.current.config).toMatchSnapshot(); + }); + + describe('and the required capabilities are not met either', () => { + beforeEach(() => { + mockHasCapabilities.mockReturnValue(false); + }); + + it('should return only the default topics config', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(1); + expect(result.current.config).toMatchSnapshot(); + }); + }); + }); + }); + + describe('when the required license is not met', () => { + beforeEach(() => { + mockUseLicense.mockReturnValue({ isAtLeast: jest.fn(() => false) }); + }); + + it('should filter the topics config correctly', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(2); + expect(result.current.config).toMatchSnapshot(); + }); + + describe('and the required capabilities are not met either', () => { + beforeEach(() => { + mockHasCapabilities.mockReturnValue(false); + }); + + it('should filter the topics config correctly', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(2); + expect(result.current.config).toMatchSnapshot(); + }); + }); + }); + + describe('when the required capabilities are not met', () => { + beforeEach(() => { + mockHasCapabilities.mockReturnValue(false); + }); + + it('should filter the topics config correctly', () => { + const { result } = renderHook(useOnboardingContext, { wrapper }); + expect(result.current.config.size).toEqual(2); + expect(result.current.config).toMatchSnapshot(); + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx index 2a6597628a26..17932207c627 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_context.tsx @@ -6,46 +6,43 @@ */ import type { PropsWithChildren } from 'react'; -import React, { createContext, useContext, useMemo } from 'react'; +import React, { createContext, useCallback, useContext, useMemo } from 'react'; import { useKibana } from '../../common/lib/kibana/kibana_react'; -import type { OnboardingCardId } from '../constants'; +import type { OnboardingTopicId, OnboardingCardId } from '../constants'; import { OnboardingHubEventTypes } from '../../common/lib/telemetry'; +import { useLicense } from '../../common/hooks/use_license'; +import { ExperimentalFeaturesService } from '../../common/experimental_features_service'; -export interface OnboardingContextValue { - spaceId: string; +import { hasCapabilities } from '../../common/lib/capabilities'; +import type { + OnboardingConfigAvailabilityProps, + OnboardingGroupConfig, + TopicConfig, +} from '../types'; +import { onboardingConfig } from '../config'; + +export interface OnboardingTelemetry { reportCardOpen: (cardId: OnboardingCardId, options?: { auto?: boolean }) => void; reportCardComplete: (cardId: OnboardingCardId, options?: { auto?: boolean }) => void; reportCardLinkClicked: (cardId: OnboardingCardId, linkId: string) => void; } + +export type OnboardingConfig = Map<OnboardingTopicId, TopicConfig>; +export interface OnboardingContextValue { + spaceId: string; + telemetry: OnboardingTelemetry; + config: OnboardingConfig; +} const OnboardingContext = createContext<OnboardingContextValue | null>(null); export const OnboardingContextProvider: React.FC<PropsWithChildren<{ spaceId: string }>> = React.memo(({ children, spaceId }) => { - const { telemetry } = useKibana().services; + const config = useFilteredConfig(); + const telemetry = useOnboardingTelemetry(); const value = useMemo<OnboardingContextValue>( - () => ({ - spaceId, - reportCardOpen: (cardId, { auto = false } = {}) => { - telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepOpen, { - stepId: cardId, - trigger: auto ? 'navigation' : 'click', - }); - }, - reportCardComplete: (cardId, { auto = false } = {}) => { - telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepFinished, { - stepId: cardId, - trigger: auto ? 'auto_check' : 'click', - }); - }, - reportCardLinkClicked: (cardId, linkId: string) => { - telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepLinkClicked, { - originStepId: cardId, - stepLinkId: linkId, - }); - }, - }), - [spaceId, telemetry] + () => ({ spaceId, telemetry, config }), + [spaceId, telemetry, config] ); return <OnboardingContext.Provider value={value}>{children}</OnboardingContext.Provider>; @@ -61,3 +58,82 @@ export const useOnboardingContext = () => { } return context; }; + +/** + * Hook that filters the config based on the user's capabilities, license and experimental features + */ +const useFilteredConfig = (): OnboardingConfig => { + const { capabilities } = useKibana().services.application; + const experimentalFeatures = ExperimentalFeaturesService.get(); + const license = useLicense(); + + const isAvailable = useCallback( + (item: OnboardingConfigAvailabilityProps) => { + if (item.experimentalFlagRequired && !experimentalFeatures[item.experimentalFlagRequired]) { + return false; + } + if (item.licenseTypeRequired && !license.isAtLeast(item.licenseTypeRequired)) { + return false; + } + if (item.capabilitiesRequired && !hasCapabilities(capabilities, item.capabilitiesRequired)) { + return false; + } + return true; + }, + [license, capabilities, experimentalFeatures] + ); + + const filteredConfig = useMemo( + () => + onboardingConfig.reduce<OnboardingConfig>((filteredTopicConfigs, topicConfig) => { + if (!isAvailable(topicConfig)) { + return filteredTopicConfigs; + } + const filteredBody = topicConfig.body.reduce<OnboardingGroupConfig[]>( + (filteredGroups, group) => { + const filteredCards = group.cards.filter(isAvailable); + + if (filteredCards.length > 0) { + filteredGroups.push({ ...group, cards: filteredCards }); + } + return filteredGroups; + }, + [] + ); + if (filteredBody.length > 0) { + filteredTopicConfigs.set(topicConfig.id, { ...topicConfig, body: filteredBody }); + } + return filteredTopicConfigs; + }, new Map<OnboardingTopicId, TopicConfig>()), + [isAvailable] + ); + + return filteredConfig; +}; + +const useOnboardingTelemetry = (): OnboardingTelemetry => { + const { telemetry } = useKibana().services; + return useMemo( + () => ({ + reportCardOpen: (cardId, { auto = false } = {}) => { + telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepOpen, { + stepId: cardId, + trigger: auto ? 'navigation' : 'click', + }); + }, + reportCardComplete: (cardId, { auto = false } = {}) => { + telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepFinished, { + stepId: cardId, + trigger: auto ? 'auto_check' : 'click', + }); + }, + reportCardLinkClicked: (cardId, linkId: string) => { + telemetry.reportEvent(OnboardingHubEventTypes.OnboardingHubStepLinkClicked, { + originStepId: cardId, + stepLinkId: linkId, + }); + }, + }), + [telemetry] + ); +}; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.test.tsx index ae80d0c9273c..2b663add1224 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.test.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { trackOnboardingLinkClick } from '../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../lib/telemetry'; import { FooterLinkItem } from './onboarding_footer'; import { OnboardingFooterLinkItemId, TELEMETRY_FOOTER_LINK } from './constants'; -jest.mock('../../common/lib/telemetry'); +jest.mock('../lib/telemetry'); describe('OnboardingFooterComponent', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx index 125d2af118d3..9db64386be06 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_footer/onboarding_footer.tsx @@ -9,7 +9,7 @@ import React, { useCallback } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; import { useFooterStyles } from './onboarding_footer.styles'; import { useFooterItems } from './footer_items'; -import { trackOnboardingLinkClick } from '../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../lib/telemetry'; import type { OnboardingFooterLinkItemId } from './constants'; import { TELEMETRY_FOOTER_LINK } from './constants'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.test.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.test.tsx index 83bfa317d8fb..febc8431627b 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.test.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.test.tsx @@ -8,10 +8,10 @@ import React from 'react'; import { render } from '@testing-library/react'; import { LinkCard } from './link_card'; -import { OnboardingHeaderCardId, TELEMETRY_HEADER_CARD } from '../../../constants'; -import { trackOnboardingLinkClick } from '../../../../common/lib/telemetry'; +import { OnboardingHeaderCardId, TELEMETRY_HEADER_CARD } from '../../constants'; +import { trackOnboardingLinkClick } from '../../../lib/telemetry'; -jest.mock('../../../../common/lib/telemetry'); +jest.mock('../../../lib/telemetry'); describe('DataIngestionHubHeaderCardComponent', () => { beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.tsx index 12b3877628db..71ab7b007b35 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/common/link_card.tsx @@ -8,10 +8,10 @@ import React, { useCallback } from 'react'; import { EuiCard, EuiImage, EuiLink, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui'; import classNames from 'classnames'; -import { trackOnboardingLinkClick } from '../../../../common/lib/telemetry'; +import { trackOnboardingLinkClick } from '../../../lib/telemetry'; import { useCardStyles } from './link_card.styles'; -import type { OnboardingHeaderCardId } from '../../../constants'; -import { TELEMETRY_HEADER_CARD } from '../../../constants'; +import type { OnboardingHeaderCardId } from '../../constants'; +import { TELEMETRY_HEADER_CARD } from '../../constants'; interface LinkCardProps { id: OnboardingHeaderCardId; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/demo_card/demo_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/demo_card/demo_card.tsx index b86ae2dcd219..9daf13527108 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/demo_card/demo_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/demo_card/demo_card.tsx @@ -10,7 +10,7 @@ import { LinkCard } from '../common/link_card'; import demoImage from './images/demo_card.png'; import darkDemoImage from './images/demo_card_dark.png'; import * as i18n from './translations'; -import { OnboardingHeaderCardId } from '../../../constants'; +import { OnboardingHeaderCardId } from '../../constants'; export const DemoCard = React.memo<{ isDarkMode: boolean }>(({ isDarkMode }) => { return ( diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/teammates_card/teammates_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/teammates_card/teammates_card.tsx index 81e6ffb3657f..0a425acd0a93 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/teammates_card/teammates_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/teammates_card/teammates_card.tsx @@ -7,8 +7,8 @@ import React from 'react'; import useObservable from 'react-use/lib/useObservable'; -import { OnboardingHeaderCardId } from '../../../constants'; -import { useOnboardingService } from '../../../../hooks/use_onboarding_service'; +import { OnboardingHeaderCardId } from '../../constants'; +import { useOnboardingService } from '../../../hooks/use_onboarding_service'; import { LinkCard } from '../common/link_card'; import teammatesImage from './images/teammates_card.png'; import darkTeammatesImage from './images/teammates_card_dark.png'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/video_card/video_card.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/video_card/video_card.tsx index 2e91b7374c50..15a8950aed27 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/video_card/video_card.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/cards/video_card/video_card.tsx @@ -6,7 +6,7 @@ */ import React, { useCallback, useState } from 'react'; -import { OnboardingHeaderCardId } from '../../../constants'; +import { OnboardingHeaderCardId } from '../../constants'; import { OnboardingHeaderVideoModal } from './video_modal'; import * as i18n from './translations'; import videoImage from './images/video_card.png'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/constants.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/constants.ts similarity index 100% rename from x-pack/plugins/security_solution/public/onboarding/components/constants.ts rename to x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/constants.ts diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.styles.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.styles.ts index 34cc060a9738..40cfd7a5d9e1 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.styles.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.styles.ts @@ -18,5 +18,8 @@ export const useOnboardingHeaderStyles = () => { .onboardingHeaderGreetings { color: ${euiTheme.colors.darkShade}; } + .onboardingHeaderTopicSelector { + width: calc(${PAGE_CONTENT_WIDTH} / 3); + } `; }; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.tsx index 0210c88186a9..1175c125e6a8 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.tsx +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header.tsx @@ -17,6 +17,7 @@ import { useEuiTheme, } from '@elastic/eui'; import { useCurrentUser } from '../../../common/lib/kibana/hooks'; +import { OnboardingHeaderTopicSelector } from './onboarding_header_topic_selector'; import { useOnboardingHeaderStyles } from './onboarding_header.styles'; import rocketImage from './images/header_rocket.png'; import rocketDarkImage from './images/header_rocket_dark.png'; @@ -42,23 +43,25 @@ export const OnboardingHeader = React.memo(() => { <EuiImage src={isDarkMode ? rocketDarkImage : rocketImage} size={128} - alt={i18n.GET_STARTED_DATA_INGESTION_HUB_SUBTITLE} + alt={i18n.ONBOARDING_PAGE_SUBTITLE} /> </EuiFlexItem> <EuiFlexItem grow={false} className="onboardingHeaderTitleWrapper"> {currentUserName && ( <EuiTitle size="xs" className="onboardingHeaderGreetings"> - <span>{i18n.GET_STARTED_PAGE_TITLE(currentUserName)}</span> + <span>{i18n.ONBOARDING_PAGE_TITLE(currentUserName)}</span> </EuiTitle> )} <EuiSpacer size="s" /> <EuiTitle size="l"> - <h1>{i18n.GET_STARTED_DATA_INGESTION_HUB_SUBTITLE}</h1> + <h1>{i18n.ONBOARDING_PAGE_SUBTITLE}</h1> </EuiTitle> <EuiSpacer size="s" /> <EuiText size="m" color="subdued"> - <span>{i18n.GET_STARTED_DATA_INGESTION_HUB_DESCRIPTION}</span> + <span>{i18n.ONBOARDING_PAGE_DESCRIPTION}</span> </EuiText> + <EuiSpacer size="m" /> + <OnboardingHeaderTopicSelector /> </EuiFlexItem> </EuiFlexGroup> <EuiSpacer size="xxl" /> diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx new file mode 100644 index 000000000000..c949f51d23da --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/onboarding_header_topic_selector.tsx @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import { EuiButtonGroup } from '@elastic/eui'; +import type { OnboardingTopicId } from '../../constants'; +import { useOnboardingContext } from '../onboarding_context'; +import { useTopic } from '../hooks/use_topic_id'; + +export const OnboardingHeaderTopicSelector = React.memo(() => { + const { config } = useOnboardingContext(); + const [topicId, setTopicId] = useTopic(); + + const selectorOptions = useMemo( + () => + [...config.values()].map((topicConfig) => ({ + id: topicConfig.id, + label: topicConfig.title, + })), + [config] + ); + + if (selectorOptions.length < 2) { + return null; + } + + return ( + <EuiButtonGroup + className="onboardingHeaderTopicSelector" + buttonSize="compressed" + type="single" + legend="Topic selector" + options={selectorOptions} + idSelected={topicId} + onChange={(id) => setTopicId(id as OnboardingTopicId)} + isFullWidth + /> + ); +}); +OnboardingHeaderTopicSelector.displayName = 'OnboardingHeaderTopicSelector'; diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/translations.ts b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/translations.ts index c1f8ca8695bb..62eadcdcd83a 100644 --- a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/translations.ts +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_header/translations.ts @@ -7,22 +7,36 @@ import { i18n } from '@kbn/i18n'; -export const GET_STARTED_PAGE_TITLE = (userName: string) => +export const ONBOARDING_PAGE_TITLE = (userName: string) => i18n.translate('xpack.securitySolution.onboarding.Title', { defaultMessage: `Hi {userName}!`, values: { userName }, }); -export const GET_STARTED_DATA_INGESTION_HUB_SUBTITLE = i18n.translate( +export const ONBOARDING_PAGE_SUBTITLE = i18n.translate( 'xpack.securitySolution.onboarding.subTitle', { defaultMessage: `Welcome to Elastic Security`, } ); -export const GET_STARTED_DATA_INGESTION_HUB_DESCRIPTION = i18n.translate( +export const ONBOARDING_PAGE_DESCRIPTION = i18n.translate( 'xpack.securitySolution.onboarding.description', { defaultMessage: `A SIEM with AI-driven security analytics, XDR and Cloud Security.`, } ); + +export const ONBOARDING_PAGE_DEFAULT_TOPIC = i18n.translate( + 'xpack.securitySolution.onboarding.topic.default', + { + defaultMessage: 'Set up security', + } +); + +export const ONBOARDING_PAGE_SIEM_MIGRATIONS_TOPIC = i18n.translate( + 'xpack.securitySolution.onboarding.topic.siemMigrations', + { + defaultMessage: 'SIEM Rule migration', + } +); diff --git a/x-pack/plugins/security_solution/public/onboarding/components/onboarding_route.tsx b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_route.tsx new file mode 100644 index 000000000000..6e7dca524ce8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/components/onboarding_route.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useEffect } from 'react'; + +import type { RouteComponentProps } from 'react-router-dom'; +import { OnboardingHeader } from './onboarding_header'; +import { OnboardingBody } from './onboarding_body'; +import type { OnboardingRouteParams } from '../types'; +import { getCardIdFromHash, useUrlDetail } from './hooks/use_url_detail'; + +type OnboardingRouteProps = RouteComponentProps<OnboardingRouteParams>; + +export const OnboardingRoute = React.memo<OnboardingRouteProps>(({ match, location }) => { + const { syncUrlDetails } = useUrlDetail(); + + /** + * This effect syncs the URL details with the stored state, it only needs to be executed once per page load. + */ + useEffect(() => { + const pathTopicId = match.params.topicId || null; + const hashCardId = getCardIdFromHash(location.hash); + syncUrlDetails(pathTopicId, hashCardId); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return ( + <> + <OnboardingHeader /> + <OnboardingBody /> + </> + ); +}); +OnboardingRoute.displayName = 'OnboardingContent'; diff --git a/x-pack/plugins/security_solution/public/onboarding/config.ts b/x-pack/plugins/security_solution/public/onboarding/config.ts new file mode 100644 index 000000000000..a8f5909f9b05 --- /dev/null +++ b/x-pack/plugins/security_solution/public/onboarding/config.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { OnboardingTopicId } from './constants'; +import { + defaultBodyConfig, + siemMigrationsBodyConfig, +} from './components/onboarding_body/body_config'; +import type { TopicConfig } from './types'; + +export const onboardingConfig: TopicConfig[] = [ + { + id: OnboardingTopicId.default, + title: i18n.translate('xpack.securitySolution.onboarding.topic.default', { + defaultMessage: 'Set up security', + }), + body: defaultBodyConfig, + }, + { + id: OnboardingTopicId.siemMigrations, + title: i18n.translate('xpack.securitySolution.onboarding.topic.siemMigrations', { + defaultMessage: 'SIEM Rule migration', + }), + body: siemMigrationsBodyConfig, + licenseTypeRequired: 'enterprise', + experimentalFlagRequired: 'siemMigrationsEnabled', + }, +]; diff --git a/x-pack/plugins/security_solution/public/onboarding/constants.ts b/x-pack/plugins/security_solution/public/onboarding/constants.ts index 0eb277bd6187..e360e4591bb3 100644 --- a/x-pack/plugins/security_solution/public/onboarding/constants.ts +++ b/x-pack/plugins/security_solution/public/onboarding/constants.ts @@ -6,6 +6,11 @@ */ export const PAGE_CONTENT_WIDTH = '1150px'; +export enum OnboardingTopicId { + default = 'default', + siemMigrations = 'siem_migrations', +} + export enum OnboardingCardId { integrations = 'integrations', dashboards = 'dashboards', @@ -13,4 +18,7 @@ export enum OnboardingCardId { alerts = 'alerts', assistant = 'assistant', attackDiscovery = 'attack_discovery', + + // siem_migrations topic cards + siemMigrationsAiConnectors = 'ai_connectors', } diff --git a/x-pack/plugins/security_solution/public/onboarding/types.ts b/x-pack/plugins/security_solution/public/onboarding/types.ts index 9dfe1e75596d..d9c5aa2c9bc2 100644 --- a/x-pack/plugins/security_solution/public/onboarding/types.ts +++ b/x-pack/plugins/security_solution/public/onboarding/types.ts @@ -9,7 +9,8 @@ import type React from 'react'; import type { IconType } from '@elastic/eui'; import type { LicenseType } from '@kbn/licensing-plugin/public'; -import type { OnboardingCardId } from './constants'; +import type { ExperimentalFeatures } from '../../common'; +import type { OnboardingTopicId, OnboardingCardId } from './constants'; import type { RequiredCapabilities } from '../common/lib/capabilities'; import type { StartServices } from '../types'; @@ -41,6 +42,7 @@ export type CheckCompleteResponse<TMetadata extends {} = {}> = export type SetComplete = (isComplete: boolean) => void; export type IsCardComplete = (cardId: OnboardingCardId) => boolean; +export type IsCardAvailable = (cardId: OnboardingCardId) => boolean; export type SetExpandedCardId = ( cardId: OnboardingCardId | null, options?: { scroll?: boolean } @@ -59,6 +61,10 @@ export type OnboardingCardComponent<TMetadata extends {} = {}> = React.Component * Function to check if a specific card is complete. */ isCardComplete: IsCardComplete; + /** + * Function to check if a specific card is rendered. + */ + isCardAvailable: IsCardAvailable; /** * Function to expand a specific card ID and scroll to it. */ @@ -74,31 +80,17 @@ export type OnboardingCardCheckComplete<TMetadata extends {} = {}> = ( services: StartServices ) => Promise<CheckCompleteResponse<TMetadata>>; -export interface OnboardingCardConfig<TMetadata extends {} = {}> { - id: OnboardingCardId; - title: string; - icon: IconType; - /** - * Component that renders the card content when expanded. - * It receives a `setComplete` function to allow the card to mark itself as complete if needed. - * Please use React.lazy() to load the component. - */ - Component: React.LazyExoticComponent<OnboardingCardComponent<TMetadata>>; +export interface OnboardingConfigAvailabilityProps { /** - * Function for auto-checking completion for the card - * @returns Promise for the complete status - */ - checkComplete?: OnboardingCardCheckComplete<TMetadata>; - /** - * The RBAC capability strings required to enable the card. It uses object dot notation. e.g. `'siem.crud'`. + * The RBAC capability strings required to enable the item. It uses object dot notation. e.g. `'siem.crud'`. * * The format of the capabilities property supports OR and AND mechanism: * * To specify capabilities in an OR fashion, they can be defined in a single level array like: `capabilities: [cap1, cap2]`. - * If either of "cap1 || cap2" is granted the card will be included. + * If either of "cap1 || cap2" is granted the item will be included. * * To specify capabilities with AND conditional, use a second level array: `capabilities: [['cap1', 'cap2']]`. - * This would result in the boolean expression "cap1 && cap2", both capabilities must be granted to include the card. + * This would result in the boolean expression "cap1 && cap2", both capabilities must be granted to include the item. * * They can also be combined like: `capabilities: ['cap1', ['cap2', 'cap3']]` which would result in the boolean expression "cap1 || (cap2 && cap3)". * @@ -106,12 +98,34 @@ export interface OnboardingCardConfig<TMetadata extends {} = {}> { * * Default is `undefined` (no capabilities required) */ - capabilities?: RequiredCapabilities; + capabilitiesRequired?: RequiredCapabilities; /** - * Minimum license required to enable the card. + * Minimum license required to enable the item. * Default is `basic` */ - licenseType?: LicenseType; + licenseTypeRequired?: LicenseType; + /** + * The experimental features required to enable the item. + */ + experimentalFlagRequired?: keyof ExperimentalFeatures; +} + +export interface OnboardingCardConfig<TMetadata extends {} = {}> + extends OnboardingConfigAvailabilityProps { + id: OnboardingCardId; + title: string; + icon: IconType; + /** + * Component that renders the card content when expanded. + * It receives a `setComplete` function to allow the card to mark itself as complete if needed. + * Please use React.lazy() to load the component. + */ + Component: React.LazyExoticComponent<OnboardingCardComponent<TMetadata>>; + /** + * Function for auto-checking completion for the card + * @returns Promise for the complete status + */ + checkComplete?: OnboardingCardCheckComplete<TMetadata>; } export interface OnboardingGroupConfig { @@ -120,3 +134,19 @@ export interface OnboardingGroupConfig { // eslint-disable-next-line @typescript-eslint/no-explicit-any cards: Array<OnboardingCardConfig<any>>; } + +export interface TopicConfig extends OnboardingConfigAvailabilityProps { + id: OnboardingTopicId; + /** + * The onboarding topic title. + */ + title: string; + /** + * The onboarding body configuration. + */ + body: OnboardingGroupConfig[]; +} + +export interface OnboardingRouteParams { + topicId?: OnboardingTopicId; +} diff --git a/x-pack/plugins/security_solution/public/one_discover/app_wrapper/index.tsx b/x-pack/plugins/security_solution/public/one_discover/app_wrapper/index.tsx new file mode 100644 index 000000000000..eb5c325475f2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/one_discover/app_wrapper/index.tsx @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useMemo } from 'react'; +import { ExpandableFlyoutProvider } from '@kbn/expandable-flyout'; +import { Provider as ReduxStoreProvider } from 'react-redux'; +import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; +import { KibanaContextProvider, useKibana } from '@kbn/kibana-react-plugin/public'; +import { NavigationProvider } from '@kbn/security-solution-navigation'; +import type { CoreStart } from '@kbn/core/public'; +import type { SecuritySolutionAppWrapperFeature } from '@kbn/discover-shared-plugin/public'; +import type { DiscoverServices } from '@kbn/discover-plugin/public'; +import { CellActionsProvider } from '@kbn/cell-actions'; +import { APP_ID } from '../../../common'; +import { SecuritySolutionFlyout } from '../../flyout'; +import { StatefulEventContext } from '../../common/components/events_viewer/stateful_event_context'; +import type { SecurityAppStore } from '../../common/store'; +import { ReactQueryClientProvider } from '../../common/containers/query_client/query_client_provider'; +import type { StartPluginsDependencies, StartServices } from '../../types'; +import { MlCapabilitiesProvider } from '../../common/components/ml/permissions/ml_capabilities_provider'; +import { UserPrivilegesProvider } from '../../common/components/user_privileges/user_privileges_context'; +import { DiscoverInTimelineContextProvider } from '../../common/components/discover_in_timeline/provider'; +import { UpsellingProvider } from '../../common/components/upselling_provider'; +import { ConsoleManager } from '../../management/components/console'; +import { AssistantProvider } from '../../assistant/provider'; +import { ONE_DISCOVER_SCOPE_ID } from '../constants'; + +export const createSecuritySolutionDiscoverAppWrapperGetter = ({ + core, + services, + plugins, + store, +}: { + core: CoreStart; + services: StartServices; + plugins: StartPluginsDependencies; + /** + * instance of Security App store that should be used in Discover + */ + store: SecurityAppStore; +}) => { + const getSecuritySolutionDiscoverAppWrapper: Awaited< + ReturnType<SecuritySolutionAppWrapperFeature['getWrapper']> + > = () => { + return function SecuritySolutionDiscoverAppWrapper({ children }) { + const { services: discoverServices } = useKibana<DiscoverServices>(); + const CasesContext = useMemo(() => plugins.cases.ui.getCasesContext(), []); + + const userCasesPermissions = useMemo(() => plugins.cases.helpers.canUseCases([APP_ID]), []); + + /** + * + * Since this component is meant to be used only in the context of Discover, + * these services are appended/overwritten to the existing services object + * provided by the Discover plugin. + * + */ + const securitySolutionServices: StartServices = useMemo( + () => ({ + ...services, + /* Helps with getting correct instance of query, timeFilter and filterManager instances from discover */ + data: discoverServices.data, + }), + [discoverServices] + ); + + const statefulEventContextValue = useMemo( + () => ({ + // timelineId acts as scopeId + timelineID: ONE_DISCOVER_SCOPE_ID, + enableHostDetailsFlyout: true, + /* behaviour similar to query tab */ + tabType: 'query', + enableIpDetailsFlyout: true, + }), + [] + ); + + return ( + <KibanaContextProvider services={securitySolutionServices}> + <EuiThemeProvider> + <MlCapabilitiesProvider> + <CasesContext owner={[APP_ID]} permissions={userCasesPermissions}> + <UserPrivilegesProvider kibanaCapabilities={services.application.capabilities}> + {/* ^_^ Needed for notes addition */} + <NavigationProvider core={core}> + <CellActionsProvider + getTriggerCompatibleActions={services.uiActions.getTriggerCompatibleActions} + > + {/* ^_^ Needed for Cell Actions since it gives errors when CellActionsContext is used */} + <UpsellingProvider upsellingService={services.upselling}> + {/* ^_^ Needed for Alert Preview from Expanded Section of Entity Flyout */} + <ReduxStoreProvider store={store}> + <ReactQueryClientProvider> + <ConsoleManager> + {/* ^_^ Needed for AlertPreview -> Alert Details Flyout Action */} + <AssistantProvider> + {/* ^_^ Needed for AlertPreview -> Alert Details Flyout Action */} + <DiscoverInTimelineContextProvider> + {/* ^_^ Needed for Add to Timeline action by `useRiskInputActions`*/} + <ExpandableFlyoutProvider> + <SecuritySolutionFlyout /> + {/* vv below context should not be here and should be removed */} + <StatefulEventContext.Provider + value={statefulEventContextValue} + > + {children} + </StatefulEventContext.Provider> + </ExpandableFlyoutProvider> + </DiscoverInTimelineContextProvider> + </AssistantProvider> + </ConsoleManager> + </ReactQueryClientProvider> + </ReduxStoreProvider> + </UpsellingProvider> + </CellActionsProvider> + </NavigationProvider> + </UserPrivilegesProvider> + </CasesContext> + </MlCapabilitiesProvider> + </EuiThemeProvider> + </KibanaContextProvider> + ); + }; + }; + + return getSecuritySolutionDiscoverAppWrapper; +}; diff --git a/x-pack/plugins/security_solution/public/one_discover/cell_renderers/cell_renderer.test.tsx b/x-pack/plugins/security_solution/public/one_discover/cell_renderers/cell_renderer.test.tsx new file mode 100644 index 000000000000..4bb1eec75cc2 --- /dev/null +++ b/x-pack/plugins/security_solution/public/one_discover/cell_renderers/cell_renderer.test.tsx @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license 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 { DefaultCellRenderer } from '../../timelines/components/timeline/cell_rendering/default_cell_renderer'; +import { render } from '@testing-library/react'; +import { getCellRendererForGivenRecord } from './cell_renderers'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import type { DataViewField } from '@kbn/data-views-plugin/common'; +import { dataViewMock } from '@kbn/discover-utils/src/__mocks__'; +import { fieldFormatsMock } from '@kbn/field-formats-plugin/common/mocks'; + +jest.mock('../../timelines/components/timeline/cell_rendering/default_cell_renderer'); + +const DefaultCellRendererMock = DefaultCellRenderer as unknown as jest.Mock<React.ReactElement>; + +/** + * Mocking DefaultCellRenderer here because it will be renderered + * in Discover's environment and context and we cannot test that here in jest. + * + * Actual working of Cell Renderer will be tested in Discover's functional tests + * + * */ +const mockDefaultCellRenderer = jest.fn((props) => { + return <div data-test-subj="mocked-default-cell-render" />; +}); + +const mockDataView = dataViewMock; +mockDataView.getFieldByName = jest.fn().mockReturnValue({ type: 'string' } as DataViewField); + +describe('getCellRendererForGivenRecord', () => { + beforeEach(() => { + DefaultCellRendererMock.mockImplementation(mockDefaultCellRenderer); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should return cell renderer correctly for allowed fields with correct data format', () => { + const cellRenderer = getCellRendererForGivenRecord('host.name'); + expect(cellRenderer).toBeDefined(); + const props: DataGridCellValueElementProps = { + columnId: 'host.name', + isDetails: false, + isExpanded: false, + row: { + id: '1', + raw: {}, + flattened: { + 'host.name': 'host1', + 'user.name': 'user1', + }, + }, + dataView: mockDataView, + setCellProps: jest.fn(), + isExpandable: false, + rowIndex: 0, + colIndex: 0, + fieldFormats: fieldFormatsMock, + closePopover: jest.fn(), + }; + const CellRenderer = cellRenderer as React.FC<DataGridCellValueElementProps>; + const { getByTestId } = render(<CellRenderer {...props} />); + expect(getByTestId('mocked-default-cell-render')).toBeVisible(); + expect(mockDefaultCellRenderer).toHaveBeenCalledWith( + { + isDraggable: false, + isTimeline: false, + isDetails: false, + data: [ + { field: 'host.name', value: ['host1'] }, + { field: 'user.name', value: ['user1'] }, + ], + eventId: '1', + scopeId: 'one-discover', + linkValues: undefined, + header: { + id: 'host.name', + columnHeaderType: 'not-filtered', + type: 'string', + }, + asPlainText: false, + context: undefined, + rowRenderers: undefined, + ecsData: undefined, + colIndex: 0, + rowIndex: 0, + isExpandable: false, + isExpanded: false, + setCellProps: props.setCellProps, + columnId: 'host.name', + }, + {} + ); + }); + it('should return undefined for non-allowedFields', () => { + const cellRenderer = getCellRendererForGivenRecord('non-allowed-field'); + expect(cellRenderer).toBeUndefined(); + }); +}); diff --git a/x-pack/plugins/security_solution/public/one_discover/cell_renderers/cell_renderers.tsx b/x-pack/plugins/security_solution/public/one_discover/cell_renderers/cell_renderers.tsx new file mode 100644 index 000000000000..7ecc73e40416 --- /dev/null +++ b/x-pack/plugins/security_solution/public/one_discover/cell_renderers/cell_renderers.tsx @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { useMemo } from 'react'; +import type { DataGridCellValueElementProps } from '@kbn/unified-data-table'; +import type { TimelineNonEcsData } from '@kbn/timelines-plugin/common'; +import type { SecuritySolutionCellRendererFeature } from '@kbn/discover-shared-plugin/public'; +import type { ColumnHeaderType } from '../../../common/types'; +import type { Maybe } from '../../../common/search_strategy'; +import { DefaultCellRenderer } from '../../timelines/components/timeline/cell_rendering/default_cell_renderer'; +import { ONE_DISCOVER_SCOPE_ID } from '../constants'; + +export type SecuritySolutionRowCellRendererGetter = Awaited< + ReturnType<SecuritySolutionCellRendererFeature['getRenderer']> +>; + +const ALLOWED_DISCOVER_RENDERED_FIELDS = ['host.name', 'user.name', 'source.ip', 'destination.ip']; + +export const getCellRendererForGivenRecord: SecuritySolutionRowCellRendererGetter = ( + fieldName: string +) => { + if (!ALLOWED_DISCOVER_RENDERED_FIELDS.includes(fieldName)) return undefined; + return function UnifiedFieldRenderBySecuritySolution(props: DataGridCellValueElementProps) { + // convert discover data format to timeline data format + const data: TimelineNonEcsData[] = useMemo( + () => + Object.keys(props.row.flattened).map((field) => ({ + field, + value: Array.isArray(props.row.flattened[field]) + ? (props.row.flattened[field] as Maybe<string[]>) + : ([props.row.flattened[field]] as Maybe<string[]>), + })), + [props.row.flattened] + ); + + const header = useMemo(() => { + return { + id: props.columnId, + columnHeaderType: 'not-filtered' as ColumnHeaderType, + type: props.dataView.getFieldByName(props.columnId)?.type, + }; + }, [props.columnId, props.dataView]); + + return ( + <DefaultCellRenderer + data={data} + ecsData={undefined} + eventId={props.row.id} + header={header} + isDetails={props.isDetails} + isDraggable={false} + isTimeline={false} + linkValues={undefined} + rowRenderers={undefined} + scopeId={ONE_DISCOVER_SCOPE_ID} + asPlainText={false} + context={undefined} + isExpandable={props.isExpandable} + rowIndex={props.rowIndex} + colIndex={props.colIndex} + setCellProps={props.setCellProps} + isExpanded={props.isExpanded} + columnId={props.columnId} + /> + ); + }; +}; diff --git a/x-pack/plugins/security_solution/public/one_discover/cell_renderers/index.ts b/x-pack/plugins/security_solution/public/one_discover/cell_renderers/index.ts new file mode 100644 index 000000000000..2ec3ff99073d --- /dev/null +++ b/x-pack/plugins/security_solution/public/one_discover/cell_renderers/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getCellRendererForGivenRecord } from './cell_renderers'; diff --git a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/index.ts b/x-pack/plugins/security_solution/public/one_discover/constants.ts similarity index 82% rename from x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/index.ts rename to x-pack/plugins/security_solution/public/one_discover/constants.ts index 59ac4e0e37ef..f4e779c62cc3 100644 --- a/x-pack/plugins/enterprise_search/public/applications/app_search/components/error_connecting/index.ts +++ b/x-pack/plugins/security_solution/public/one_discover/constants.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ErrorConnecting } from './error_connecting'; +export const ONE_DISCOVER_SCOPE_ID = 'one-discover'; diff --git a/x-pack/plugins/index_management/public/application/components/enrich_policies/index.ts b/x-pack/plugins/security_solution/public/one_discover/index.tsx similarity index 64% rename from x-pack/plugins/index_management/public/application/components/enrich_policies/index.ts rename to x-pack/plugins/security_solution/public/one_discover/index.tsx index de8fa4ebf5ac..a7aefd28551b 100644 --- a/x-pack/plugins/index_management/public/application/components/enrich_policies/index.ts +++ b/x-pack/plugins/security_solution/public/one_discover/index.tsx @@ -5,5 +5,5 @@ * 2.0. */ -export { EnrichPoliciesWithPrivileges } from './with_privileges'; -export { EnrichPoliciesAuthProvider } from './auth_provider'; +export { getCellRendererForGivenRecord } from './cell_renderers'; +export { createSecuritySolutionDiscoverAppWrapperGetter } from './app_wrapper'; diff --git a/x-pack/plugins/security_solution/public/one_discover/jest.config.js b/x-pack/plugins/security_solution/public/one_discover/jest.config.js new file mode 100644 index 000000000000..7e4552f72e98 --- /dev/null +++ b/x-pack/plugins/security_solution/public/one_discover/jest.config.js @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../../../..', + roots: ['<rootDir>/x-pack/plugins/security_solution/public/one_discover'], + coverageDirectory: + '<rootDir>/target/kibana-coverage/jest/x-pack/plugins/security_solution/public/one_discover', + coverageReporters: ['text', 'html'], + collectCoverageFrom: [ + '<rootDir>/x-pack/plugins/security_solution/public/one_discover/**/*.{ts,tsx}', + ], + moduleNameMapper: require('../../server/__mocks__/module_name_map'), +}; diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.test.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.test.tsx index 5821dd349749..4c0796dacd3b 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.test.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.test.tsx @@ -31,17 +31,21 @@ jest.mock('../../../../common/containers/use_global_time', () => { }); jest.mock('../../../../common/lib/kibana'); -const mockGetCasesStatus = jest.fn(); -mockGetCasesStatus.mockResolvedValue({ - countOpenCases: 1, - countInProgressCases: 2, - countClosedCases: 3, +const mockGetCasesMetrics = jest.fn(); +mockGetCasesMetrics.mockResolvedValue({ + status: { + open: 1, + inProgress: 2, + closed: 3, + }, }); -mockGetCasesStatus.mockResolvedValueOnce({ - countOpenCases: 0, - countInProgressCases: 0, - countClosedCases: 0, +mockGetCasesMetrics.mockResolvedValueOnce({ + status: { + open: 0, + inProgress: 0, + closed: 0, + }, }); const mockUseKibana = { @@ -50,7 +54,7 @@ const mockUseKibana = { ...mockCasesContract(), api: { cases: { - getCasesStatus: mockGetCasesStatus, + getCasesMetrics: mockGetCasesMetrics, }, }, }, diff --git a/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.tsx b/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.tsx index 93b755f71087..55ac6ce45abd 100644 --- a/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.tsx +++ b/x-pack/plugins/security_solution/public/overview/components/detection_response/cases_by_status/use_cases_by_status.tsx @@ -5,7 +5,8 @@ * 2.0. */ -import type { CasesStatus } from '@kbn/cases-plugin/common'; +import type { CasesMetricsResponse } from '@kbn/cases-plugin/common'; +import { CaseMetricsFeature } from '@kbn/cases-plugin/common'; import { useState, useEffect, useMemo } from 'react'; import { v4 as uuidv4 } from 'uuid'; import { APP_ID } from '../../../../../common/constants'; @@ -34,15 +35,18 @@ export const useCasesByStatus = ({ skip = false }) => { const uniqueQueryId = useMemo(() => `useCaseItems-${uuidv4()}`, []); const [updatedAt, setUpdatedAt] = useState(Date.now()); const [isLoading, setIsLoading] = useState(true); - const [casesCounts, setCasesCounts] = useState<CasesStatus | null>(null); + const [casesCounts, setCasesCounts] = useState<CasesMetricsResponse['status'] | null | undefined>( + null + ); useEffect(() => { let isSubscribed = true; const abortCtrl = new AbortController(); const fetchCases = async () => { try { - const casesResponse = await cases.api.cases.getCasesStatus( + const casesResponse = await cases.api.cases.getCasesMetrics( { + features: [CaseMetricsFeature.STATUS], from, to, owner: APP_ID, @@ -51,7 +55,7 @@ export const useCasesByStatus = ({ skip = false }) => { ); if (isSubscribed) { - setCasesCounts(casesResponse); + setCasesCounts(casesResponse.status); } } catch (error) { if (isSubscribed) { @@ -88,14 +92,12 @@ export const useCasesByStatus = ({ skip = false }) => { }, [cases.api.cases, from, skip, to, setQuery, deleteQuery, uniqueQueryId]); return { - closed: casesCounts?.countClosedCases ?? 0, - inProgress: casesCounts?.countInProgressCases ?? 0, + closed: casesCounts?.closed ?? 0, + inProgress: casesCounts?.inProgress ?? 0, isLoading, - open: casesCounts?.countOpenCases ?? 0, + open: casesCounts?.open ?? 0, totalCounts: - (casesCounts?.countClosedCases ?? 0) + - (casesCounts?.countInProgressCases ?? 0) + - (casesCounts?.countOpenCases ?? 0), + (casesCounts?.closed ?? 0) + (casesCounts?.inProgress ?? 0) + (casesCounts?.open ?? 0), updatedAt, }; }; diff --git a/x-pack/plugins/security_solution/public/plugin.tsx b/x-pack/plugins/security_solution/public/plugin.tsx index f93383226424..497b92637dad 100644 --- a/x-pack/plugins/security_solution/public/plugin.tsx +++ b/x-pack/plugins/security_solution/public/plugin.tsx @@ -21,6 +21,10 @@ import { AppStatus, DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import type { TriggersAndActionsUIPublicPluginSetup } from '@kbn/triggers-actions-ui-plugin/public'; import { uiMetricService } from '@kbn/cloud-security-posture-common/utils/ui_metrics'; +import type { + SecuritySolutionAppWrapperFeature, + SecuritySolutionCellRendererFeature, +} from '@kbn/discover-shared-plugin/public/services/discover_features'; import { getLazyCloudSecurityPosturePliAuthBlockExtension } from './cloud_security_posture/lazy_cloud_security_posture_pli_auth_block_extension'; import { getLazyEndpointAgentTamperProtectionExtension } from './management/pages/policy/view/ingest_manager_integration/lazy_endpoint_agent_tamper_protection_extension'; import type { @@ -70,6 +74,7 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S // Lazily instantiated dependencies private _subPlugins?: SubPlugins; private _store?: SecurityAppStore; + private _securityStoreForDiscover?: SecurityAppStore; private _actionsRegistered?: boolean = false; private _alertsTableRegistered?: boolean = false; @@ -203,6 +208,8 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S getExternalReferenceAttachmentEndpointRegular() ); + this.registerDiscoverSharedFeatures(core, plugins); + return this.contract.getSetupContract(); } @@ -217,6 +224,60 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S this.services.stop(); } + public async registerDiscoverSharedFeatures( + core: CoreSetup<StartPluginsDependencies, PluginStart>, + plugins: SetupPlugins + ) { + const { discoverShared } = plugins; + const discoverFeatureRegistry = discoverShared.features.registry; + const cellRendererFeature: SecuritySolutionCellRendererFeature = { + id: 'security-solution-cell-renderer', + getRenderer: async () => { + const { getCellRendererForGivenRecord } = await this.getLazyDiscoverSharedDeps(); + return getCellRendererForGivenRecord; + }, + }; + + const appWrapperFeature: SecuritySolutionAppWrapperFeature = { + id: 'security-solution-app-wrapper', + getWrapper: async () => { + const [coreStart, startPlugins] = await core.getStartServices(); + + const services = await this.services.generateServices(coreStart, startPlugins); + const subPlugins = await this.startSubPlugins(this.storage, coreStart, startPlugins); + const securityStoreForDiscover = await this.getStoreForDiscover( + coreStart, + startPlugins, + subPlugins + ); + + const { createSecuritySolutionDiscoverAppWrapperGetter } = + await this.getLazyDiscoverSharedDeps(); + + return createSecuritySolutionDiscoverAppWrapperGetter({ + core: coreStart, + services, + plugins: startPlugins, + store: securityStoreForDiscover, + }); + }, + }; + + discoverFeatureRegistry.register(cellRendererFeature); + discoverFeatureRegistry.register(appWrapperFeature); + } + + public async getLazyDiscoverSharedDeps() { + /** + * The specially formatted comment in the `import` expression causes the corresponding webpack chunk to be named. This aids us in debugging chunk size issues. + * See https://webpack.js.org/api/module-methods/#magic-comments + */ + return import( + /* webpackChunkName: "one_discover_shared_deps" */ + './one_discover' + ); + } + /** * SubPlugins are the individual building blocks of the Security Solution plugin. * They are lazily instantiated to improve startup time. @@ -311,6 +372,31 @@ export class Plugin implements IPlugin<PluginSetup, PluginStart, SetupPlugins, S return this._store; } + /** + * Lazily instantiate a `SecurityAppStore` for discover. + */ + private async getStoreForDiscover( + coreStart: CoreStart, + startPlugins: StartPlugins, + subPlugins: StartedSubPlugins + ): Promise<SecurityAppStore> { + if (!this._securityStoreForDiscover) { + const { createStoreFactory } = await this.lazyApplicationDependencies(); + + this._securityStoreForDiscover = await createStoreFactory( + coreStart, + startPlugins, + subPlugins, + this.storage, + this.experimentalFeatures + ); + } + if (startPlugins.timelines) { + startPlugins.timelines.setTimelineEmbeddedStore(this._securityStoreForDiscover); + } + return this._securityStoreForDiscover; + } + private async registerActions( store: SecurityAppStore, history: H.History, diff --git a/x-pack/plugins/security_solution/public/plugin_services.ts b/x-pack/plugins/security_solution/public/plugin_services.ts index 97b9a163b9f8..cd066da31f54 100644 --- a/x-pack/plugins/security_solution/public/plugin_services.ts +++ b/x-pack/plugins/security_solution/public/plugin_services.ts @@ -19,6 +19,7 @@ import type { ConfigSettings } from '../common/config_settings'; import { parseConfigSettings } from '../common/config_settings'; import { APP_UI_ID } from '../common/constants'; import { TopValuesPopoverService } from './app/components/top_values_popover/top_values_popover_service'; +import { createSiemMigrationsService } from './siem_migrations/service'; import type { SecuritySolutionUiConfigType } from './common/types'; import type { PluginStart, @@ -152,6 +153,7 @@ export class PluginServices { customDataService, timelineDataService, topValuesPopover: new TopValuesPopoverService(), + siemMigrations: await createSiemMigrationsService(coreStart, startPlugins), ...(params && { onAppLeave: params.onAppLeave, setHeaderActionMenu: params.setHeaderActionMenu, diff --git a/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx b/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx index 610eb7e2a72d..cc2b9fbad345 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/routes.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import { Routes, Route } from '@kbn/shared-ux-router'; import type { SecuritySubPluginRoutes } from '../app/types'; import { SIEM_MIGRATIONS_RULES_PATH, SecurityPageName } from '../../common/constants'; @@ -17,7 +18,9 @@ export const RulesRoutes = () => { return ( <PluginTemplateWrapper> <SecurityRoutePageWrapper pageName={SecurityPageName.siemMigrationsRules}> - <RulesPage /> + <Routes> + <Route path={`${SIEM_MIGRATIONS_RULES_PATH}/:migrationId?`} component={RulesPage} /> + </Routes> </SecurityRoutePageWrapper> </PluginTemplateWrapper> ); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts index 7232cb722bd1..3b7605e03225 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/api.ts @@ -11,12 +11,19 @@ import { KibanaServices } from '../../../common/lib/kibana'; import { SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, + SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH, + SIEM_RULE_MIGRATION_INSTALL_PATH, SIEM_RULE_MIGRATION_PATH, + SIEM_RULE_MIGRATION_START_PATH, } from '../../../../common/siem_migrations/constants'; import type { GetAllStatsRuleMigrationResponse, GetRuleMigrationResponse, + InstallTranslatedMigrationRulesResponse, + InstallMigrationRulesResponse, + StartRuleMigrationRequestBody, } from '../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import type { InstallTranslatedRulesProps, InstallRulesProps } from '../types'; /** * Retrieves the stats for all the existing migrations, aggregated by `migration_id`. @@ -32,11 +39,31 @@ export const getRuleMigrationsStatsAll = async ({ }): Promise<GetAllStatsRuleMigrationResponse> => { return KibanaServices.get().http.fetch<GetAllStatsRuleMigrationResponse>( SIEM_RULE_MIGRATIONS_ALL_STATS_PATH, - { - method: 'GET', - version: '1', - signal, - } + { method: 'GET', version: '1', signal } + ); +}; + +/** + * Starts a new migration with the provided rules. + * + * @param migrationId `id` of the migration to start + * @param body The body containing the `connectorId` to use for the migration + * @param signal AbortSignal for cancelling request + * + * @throws An error if response is not OK + */ +export const startRuleMigration = async ({ + migrationId, + body, + signal, +}: { + migrationId: string; + body: StartRuleMigrationRequestBody; + signal: AbortSignal | undefined; +}): Promise<GetAllStatsRuleMigrationResponse> => { + return KibanaServices.get().http.put<GetAllStatsRuleMigrationResponse>( + replaceParams(SIEM_RULE_MIGRATION_START_PATH, { migration_id: migrationId }), + { body: JSON.stringify(body), version: '1', signal } ); }; @@ -57,8 +84,34 @@ export const getRuleMigrations = async ({ }): Promise<GetRuleMigrationResponse> => { return KibanaServices.get().http.fetch<GetRuleMigrationResponse>( replaceParams(SIEM_RULE_MIGRATION_PATH, { migration_id: migrationId }), + { method: 'GET', version: '1', signal } + ); +}; + +export const installMigrationRules = async ({ + migrationId, + ids, + signal, +}: InstallRulesProps): Promise<InstallMigrationRulesResponse> => { + return KibanaServices.get().http.fetch<InstallMigrationRulesResponse>( + replaceParams(SIEM_RULE_MIGRATION_INSTALL_PATH, { migration_id: migrationId }), + { + method: 'POST', + version: '1', + body: JSON.stringify(ids), + signal, + } + ); +}; + +export const installTranslatedMigrationRules = async ({ + migrationId, + signal, +}: InstallTranslatedRulesProps): Promise<InstallTranslatedMigrationRulesResponse> => { + return KibanaServices.get().http.fetch<InstallTranslatedMigrationRulesResponse>( + replaceParams(SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH, { migration_id: migrationId }), { - method: 'GET', + method: 'POST', version: '1', signal, } diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_rules_query.ts similarity index 58% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_rules_query.ts index 76cf01c6c35d..fece8f8c3ca0 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_migration_rules_query.ts @@ -6,14 +6,15 @@ */ import type { UseQueryOptions } from '@tanstack/react-query'; -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; import { replaceParams } from '@kbn/openapi-common/shared'; +import { useCallback } from 'react'; import { DEFAULT_QUERY_OPTIONS } from './constants'; import { getRuleMigrations } from '../api'; import type { GetRuleMigrationResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import { SIEM_RULE_MIGRATION_PATH } from '../../../../../common/siem_migrations/constants'; -export const useGetRuleMigrationsQuery = ( +export const useGetMigrationRulesQuery = ( migrationId: string, options?: UseQueryOptions<GetRuleMigrationResponse> ) => { @@ -31,3 +32,23 @@ export const useGetRuleMigrationsQuery = ( } ); }; + +/** + * We should use this hook to invalidate the rule migrations cache. For + * example, rule migrations mutations, like installing a rule, should lead to cache invalidation. + * + * @returns A rule migrations cache invalidation callback + */ +export const useInvalidateGetMigrationRulesQuery = (migrationId: string) => { + const queryClient = useQueryClient(); + + const SPECIFIC_MIGRATION_PATH = replaceParams(SIEM_RULE_MIGRATION_PATH, { + migration_id: migrationId, + }); + + return useCallback(() => { + queryClient.invalidateQueries(['GET', SPECIFIC_MIGRATION_PATH], { + refetchType: 'active', + }); + }, [SPECIFIC_MIGRATION_PATH, queryClient]); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations_stats_all.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations_stats_all.ts deleted file mode 100644 index 026e407050e9..000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_get_rule_migrations_stats_all.ts +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { UseQueryOptions } from '@tanstack/react-query'; -import { useQuery } from '@tanstack/react-query'; -import { DEFAULT_QUERY_OPTIONS } from './constants'; -import { getRuleMigrationsStatsAll } from '../api'; -import type { GetAllStatsRuleMigrationResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; -import { SIEM_RULE_MIGRATIONS_ALL_STATS_PATH } from '../../../../../common/siem_migrations/constants'; - -export const GET_RULE_MIGRATIONS_STATS_ALL_QUERY_KEY = ['GET', SIEM_RULE_MIGRATIONS_ALL_STATS_PATH]; - -export const useGetRuleMigrationsStatsAllQuery = ( - options?: UseQueryOptions<GetAllStatsRuleMigrationResponse> -) => { - return useQuery<GetAllStatsRuleMigrationResponse>( - GET_RULE_MIGRATIONS_STATS_ALL_QUERY_KEY, - async ({ signal }) => { - return getRuleMigrationsStatsAll({ signal }); - }, - { - ...DEFAULT_QUERY_OPTIONS, - ...options, - } - ); -}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_all_migration_rules_mutation.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_all_migration_rules_mutation.ts new file mode 100644 index 000000000000..f946dc165450 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_all_migration_rules_mutation.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import type { InstallTranslatedMigrationRulesResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH } from '../../../../../common/siem_migrations/constants'; +import { installTranslatedMigrationRules } from '../api'; +import { useInvalidateGetMigrationRulesQuery } from './use_get_migration_rules_query'; + +export const INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY = [ + 'POST', + SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH, +]; + +export const useInstallAllMigrationRulesMutation = ( + migrationId: string, + options?: UseMutationOptions<InstallTranslatedMigrationRulesResponse, Error> +) => { + const invalidateGetRuleMigrationsQuery = useInvalidateGetMigrationRulesQuery(migrationId); + + return useMutation<InstallTranslatedMigrationRulesResponse, Error>( + () => installTranslatedMigrationRules({ migrationId }), + { + ...options, + mutationKey: INSTALL_ALL_MIGRATION_RULES_MUTATION_KEY, + onSettled: (...args) => { + invalidateGetRuleMigrationsQuery(); + + if (options?.onSettled) { + options.onSettled(...args); + } + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_migration_rules_mutation.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_migration_rules_mutation.ts new file mode 100644 index 000000000000..6aaff55e2451 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/api/hooks/use_install_migration_rules_mutation.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { UseMutationOptions } from '@tanstack/react-query'; +import { useMutation } from '@tanstack/react-query'; +import type { InstallMigrationRulesResponse } from '../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { SIEM_RULE_MIGRATION_INSTALL_PATH } from '../../../../../common/siem_migrations/constants'; +import { installMigrationRules } from '../api'; +import { useInvalidateGetMigrationRulesQuery } from './use_get_migration_rules_query'; + +export const INSTALL_MIGRATION_RULES_MUTATION_KEY = ['POST', SIEM_RULE_MIGRATION_INSTALL_PATH]; + +export const useInstallMigrationRulesMutation = ( + migrationId: string, + options?: UseMutationOptions<InstallMigrationRulesResponse, Error, string[]> +) => { + const invalidateGetRuleMigrationsQuery = useInvalidateGetMigrationRulesQuery(migrationId); + + return useMutation<InstallMigrationRulesResponse, Error, string[]>( + (ids: string[]) => installMigrationRules({ migrationId, ids }), + { + ...options, + mutationKey: INSTALL_MIGRATION_RULES_MUTATION_KEY, + onSettled: (...args) => { + invalidateGetRuleMigrationsQuery(); + + if (options?.onSettled) { + options.onSettled(...args); + } + }, + } + ); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx deleted file mode 100644 index e4b3701d94c7..000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { EuiButton, EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import React from 'react'; -import { SecurityPageName } from '../../../../../common'; -import { useGetSecuritySolutionLinkProps } from '../../../../common/components/links'; -import * as i18n from './translations'; - -const NoMigrationsComponent = () => { - const getSecuritySolutionLinkProps = useGetSecuritySolutionLinkProps(); - const { onClick: onClickLink } = getSecuritySolutionLinkProps({ - deepLinkId: SecurityPageName.landing, - path: 'siem_migrations', - }); - - return ( - <EuiFlexGroup - alignItems="center" - gutterSize="s" - responsive={false} - direction="column" - wrap={true} - > - <EuiFlexItem grow={false}> - <EuiEmptyPrompt - title={<h2>{i18n.NO_MIGRATIONS_AVAILABLE}</h2>} - titleSize="s" - body={i18n.NO_MIGRATIONS_AVAILABLE_BODY} - data-test-subj="noMigrationsAvailable" - /> - </EuiFlexItem> - <EuiFlexItem grow={false}> - <EuiButton - fill - iconType="arrowLeft" - color={'primary'} - onClick={onClickLink} - data-test-subj="goToSiemMigrationsButton" - > - {i18n.GO_BACK_TO_RULES_TABLE_BUTTON} - </EuiButton> - </EuiFlexItem> - </EuiFlexGroup> - ); -}; - -export const NoMigrations = React.memo(NoMigrationsComponent); -NoMigrations.displayName = 'NoMigrations'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts deleted file mode 100644 index 77ec0454fb5a..000000000000 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/no_migrations/translations.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { i18n } from '@kbn/i18n'; - -export const NO_MIGRATIONS_AVAILABLE = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.noMigrationsTitle', - { - defaultMessage: 'No migrations', - } -); - -export const NO_MIGRATIONS_AVAILABLE_BODY = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.noMigrationsBodyTitle', - { - defaultMessage: 'There are no migrations available', - } -); - -export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( - 'xpack.securitySolution.siemMigrations.rules.table.goToMigrationsPageButton', - { - defaultMessage: 'Go back to SIEM Migrations', - } -); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/bulk_actions.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/bulk_actions.tsx new file mode 100644 index 000000000000..df6d01d876fc --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/bulk_actions.tsx @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLoadingSpinner } from '@elastic/eui'; +import * as i18n from './translations'; + +export interface BulkActionsProps { + isTableLoading: boolean; + numberOfTranslatedRules: number; + numberOfSelectedRules: number; + installTranslatedRule?: () => void; + installSelectedRule?: () => void; +} + +/** + * Collection of buttons to perform bulk actions on migration rules within the SIEM Rules Migrations table. + */ +export const BulkActions: React.FC<BulkActionsProps> = React.memo( + ({ + isTableLoading, + numberOfTranslatedRules, + numberOfSelectedRules, + installTranslatedRule, + installSelectedRule, + }) => { + const showInstallTranslatedRulesButton = numberOfTranslatedRules > 0; + const showInstallSelectedRulesButton = + showInstallTranslatedRulesButton && numberOfSelectedRules > 0; + return ( + <EuiFlexGroup alignItems="center" gutterSize="s" responsive={false} wrap={true}> + {showInstallSelectedRulesButton ? ( + <EuiFlexItem grow={false}> + <EuiButton + onClick={installSelectedRule} + disabled={isTableLoading} + data-test-subj="installSelectedRulesButton" + aria-label={i18n.INSTALL_SELECTED_ARIA_LABEL} + > + {i18n.INSTALL_SELECTED_RULES(numberOfSelectedRules)} + {isTableLoading && <EuiLoadingSpinner size="s" />} + </EuiButton> + </EuiFlexItem> + ) : null} + {showInstallTranslatedRulesButton ? ( + <EuiFlexItem grow={false}> + <EuiButton + fill + iconType="plusInCircle" + data-test-subj="installTranslatedRulesButton" + onClick={installTranslatedRule} + disabled={isTableLoading} + aria-label={i18n.INSTALL_ALL_ARIA_LABEL} + > + {i18n.INSTALL_ALL_RULES(numberOfTranslatedRules)} + {isTableLoading && <EuiLoadingSpinner size="s" />} + </EuiButton> + </EuiFlexItem> + ) : null} + </EuiFlexGroup> + ); + } +); +BulkActions.displayName = 'BulkActions'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx index 5f4ae3098b6a..25dffc64cccc 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/filters.tsx @@ -8,15 +8,10 @@ import { EuiFlexGroup } from '@elastic/eui'; import type { Dispatch, SetStateAction } from 'react'; import React, { useCallback } from 'react'; -import styled from 'styled-components'; import * as i18n from './translations'; import { RuleSearchField } from '../../../../detection_engine/rule_management_ui/components/rules_table/rules_table_filters/rule_search_field'; import type { TableFilterOptions } from '../../hooks/use_filter_rules_to_install'; -const FilterWrapper = styled(EuiFlexGroup)` - margin-bottom: ${({ theme }) => theme.eui.euiSizeM}; -`; - export interface FiltersComponentProps { /** * Currently selected table filter @@ -45,13 +40,13 @@ const FiltersComponent: React.FC<FiltersComponentProps> = ({ filterOptions, setF ); return ( - <FilterWrapper gutterSize="m" justifyContent="flexEnd" wrap> + <EuiFlexGroup gutterSize="m" justifyContent="flexEnd" wrap> <RuleSearchField initialValue={filterOptions.filter} onSearch={handleOnSearch} placeholder={i18n.SEARCH_PLACEHOLDER} /> - </FilterWrapper> + </EuiFlexGroup> ); }; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx index 0cd3e07ea11a..16f93a1cdeba 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/index.tsx @@ -13,8 +13,9 @@ import { EuiSkeletonText, EuiFlexGroup, EuiFlexItem, + EuiSpacer, } from '@elastic/eui'; -import React, { useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import { @@ -24,32 +25,26 @@ import { import { NoItemsMessage } from './no_items_message'; import { Filters } from './filters'; import { useRulesTableColumns } from '../../hooks/use_rules_table_columns'; -import { useGetRuleMigrationsQuery } from '../../api/hooks/use_get_rule_migrations'; import type { TableFilterOptions } from '../../hooks/use_filter_rules_to_install'; import { useFilterRulesToInstall } from '../../hooks/use_filter_rules_to_install'; +import { useRulePreviewFlyout } from '../../hooks/use_rule_preview_flyout'; +import { useInstallMigrationRules } from '../../logic/use_install_migration_rules'; +import { useGetMigrationRules } from '../../logic/use_get_migration_rules'; +import { useInstallAllMigrationRules } from '../../logic/use_install_all_migration_rules'; +import { BulkActions } from './bulk_actions'; export interface RulesTableComponentProps { /** * Selected rule migration id */ migrationId: string; - - /** - * Opens the flyout with the details of the rule migration - * @param rule Rule migration - * @returns - */ - openRulePreview: (rule: RuleMigration) => void; } /** * Table Component for displaying SIEM rules migrations */ -const RulesTableComponent: React.FC<RulesTableComponentProps> = ({ - migrationId, - openRulePreview, -}) => { - const { data: ruleMigrations, isLoading } = useGetRuleMigrationsQuery(migrationId); +const RulesTableComponent: React.FC<RulesTableComponentProps> = ({ migrationId }) => { + const { data: ruleMigrations, isLoading: isDataLoading } = useGetMigrationRules(migrationId); const [selectedRuleMigrations, setSelectedRuleMigrations] = useState<RuleMigration[]>([]); @@ -62,10 +57,60 @@ const RulesTableComponent: React.FC<RulesTableComponentProps> = ({ ruleMigrations: ruleMigrations ?? [], }); - const shouldShowProgress = isLoading; + const { mutateAsync: installMigrationRules } = useInstallMigrationRules(migrationId); + const { mutateAsync: installAllMigrationRules } = useInstallAllMigrationRules(migrationId); + + const numberOfTranslatedRules = useMemo(() => { + return filteredRuleMigrations.filter( + (rule) => + !rule.elastic_rule?.id && + (rule.elastic_rule?.prebuilt_rule_id || rule.translation_result === 'full') + ).length; + }, [filteredRuleMigrations]); + + const [isTableLoading, setTableLoading] = useState(false); + const installSingleRule = useCallback( + async (migrationRule: RuleMigration, enable?: boolean) => { + setTableLoading(true); + try { + await installMigrationRules([migrationRule.id]); + } finally { + setTableLoading(false); + } + }, + [installMigrationRules] + ); + + const installTranslatedRules = useCallback( + async (enable?: boolean) => { + setTableLoading(true); + try { + await installAllMigrationRules(); + } finally { + setTableLoading(false); + } + }, + [installAllMigrationRules] + ); + + const ruleActionsFactory = useCallback( + (ruleMigration: RuleMigration, closeRulePreview: () => void) => { + // TODO: Add flyout action buttons + return null; + }, + [] + ); + + const { rulePreviewFlyout, openRulePreview } = useRulePreviewFlyout({ + ruleActionsFactory, + }); + + const shouldShowProgress = isDataLoading; const rulesColumns = useRulesTableColumns({ - openRulePreview, + disableActions: isTableLoading, + openMigrationRulePreview: openRulePreview, + installMigrationRule: installSingleRule, }); return ( @@ -79,7 +124,7 @@ const RulesTableComponent: React.FC<RulesTableComponentProps> = ({ /> )} <EuiSkeletonLoading - isLoading={isLoading} + isLoading={isDataLoading} loadingContent={ <> <EuiSkeletonTitle /> @@ -91,13 +136,22 @@ const RulesTableComponent: React.FC<RulesTableComponentProps> = ({ <NoItemsMessage /> ) : ( <> - <EuiFlexGroup direction="column"> - <EuiFlexItem grow={false}> + <EuiFlexGroup gutterSize="m" justifyContent="flexEnd" wrap> + <EuiFlexItem> <Filters filterOptions={filterOptions} setFilterOptions={setFilterOptions} /> </EuiFlexItem> + <EuiFlexItem grow={false}> + <BulkActions + isTableLoading={isDataLoading || isTableLoading} + numberOfTranslatedRules={numberOfTranslatedRules} + numberOfSelectedRules={0} + installTranslatedRule={installTranslatedRules} + /> + </EuiFlexItem> </EuiFlexGroup> - + <EuiSpacer size="m" /> <EuiInMemoryTable + loading={isTableLoading} items={filteredRuleMigrations} sorting pagination={{ @@ -117,6 +171,7 @@ const RulesTableComponent: React.FC<RulesTableComponentProps> = ({ ) } /> + {rulePreviewFlyout} </> ); }; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts index 812f26f628e4..3da988665991 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table/translations.ts @@ -34,3 +34,32 @@ export const GO_BACK_TO_RULES_TABLE_BUTTON = i18n.translate( defaultMessage: 'Go back to SIEM Migrations', } ); + +export const INSTALL_SELECTED_RULES = (numberOfSelectedRules: number) => { + return i18n.translate('xpack.securitySolution.siemMigrations.rules.table.installSelectedRules', { + defaultMessage: 'Install selected ({numberOfSelectedRules})', + values: { numberOfSelectedRules }, + }); +}; + +export const INSTALL_ALL_RULES = (numberOfAllRules: number) => { + return i18n.translate('xpack.securitySolution.siemMigrations.rules.table.installAllRules', { + defaultMessage: + 'Install translated {numberOfAllRules, plural, one {rule} other {rules}} ({numberOfAllRules})', + values: { numberOfAllRules }, + }); +}; + +export const INSTALL_SELECTED_ARIA_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.installSelectedButtonAriaLabel', + { + defaultMessage: 'Install selected translated rules', + } +); + +export const INSTALL_ALL_ARIA_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.table.installAllButtonAriaLabel', + { + defaultMessage: 'Install all translated rules', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx new file mode 100644 index 000000000000..7122949dee90 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/actions.tsx @@ -0,0 +1,111 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiLink } from '@elastic/eui'; +import { getRuleDetailsUrl } from '../../../../common/components/link_to'; +import { useKibana } from '../../../../common/lib/kibana'; +import { APP_UI_ID, SecurityPageName } from '../../../../../common'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import * as i18n from './translations'; +import type { TableColumn } from './constants'; + +interface ActionNameProps { + disableActions?: boolean; + migrationRule: RuleMigration; + openMigrationRulePreview: (migrationRule: RuleMigration) => void; + installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void; +} + +const ActionName = ({ + disableActions, + migrationRule, + openMigrationRulePreview, + installMigrationRule, +}: ActionNameProps) => { + const { navigateToApp } = useKibana().services.application; + if (migrationRule.elastic_rule?.id) { + const ruleId = migrationRule.elastic_rule.id; + return ( + <EuiLink + disabled={disableActions} + onClick={() => { + navigateToApp(APP_UI_ID, { + deepLinkId: SecurityPageName.rules, + path: getRuleDetailsUrl(ruleId), + }); + }} + data-test-subj="viewRule" + > + {i18n.ACTIONS_VIEW_LABEL} + </EuiLink> + ); + } + + if (migrationRule.status === 'failed') { + return ( + <EuiLink disabled={disableActions} onClick={() => {}} data-test-subj="restartRule"> + {i18n.ACTIONS_RESTART_LABEL} + </EuiLink> + ); + } + + if (migrationRule.translation_result === 'full') { + return ( + <EuiLink + disabled={disableActions} + onClick={() => { + installMigrationRule(migrationRule); + }} + data-test-subj="installRule" + > + {i18n.ACTIONS_INSTALL_LABEL} + </EuiLink> + ); + } + + return ( + <EuiLink + disabled={disableActions} + onClick={() => { + openMigrationRulePreview(migrationRule); + }} + data-test-subj="editRule" + > + {i18n.ACTIONS_EDIT_LABEL} + </EuiLink> + ); +}; + +interface CreateActionsColumnProps { + disableActions?: boolean; + openMigrationRulePreview: (migrationRule: RuleMigration) => void; + installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void; +} + +export const createActionsColumn = ({ + disableActions, + openMigrationRulePreview, + installMigrationRule, +}: CreateActionsColumnProps): TableColumn => { + return { + field: 'elastic_rule', + name: i18n.COLUMN_ACTIONS, + render: (value: RuleMigration['elastic_rule'], migrationRule: RuleMigration) => { + return ( + <ActionName + disableActions={disableActions} + migrationRule={migrationRule} + openMigrationRulePreview={openMigrationRulePreview} + installMigrationRule={installMigrationRule} + /> + ); + }, + width: '10%', + align: 'center', + }; +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/constants.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/constants.tsx new file mode 100644 index 000000000000..724e4dcb101a --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/constants.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EuiBasicTableColumn } from '@elastic/eui'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; + +export type TableColumn = EuiBasicTableColumn<RuleMigration>; diff --git a/x-pack/plugins/lens/public/embeddable/index.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/index.tsx similarity index 60% rename from x-pack/plugins/lens/public/embeddable/index.ts rename to x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/index.tsx index 50ee0f582a2f..a402e61a444a 100644 --- a/x-pack/plugins/lens/public/embeddable/index.ts +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/index.tsx @@ -5,6 +5,10 @@ * 2.0. */ -export * from './embeddable'; +export * from './constants'; -export { type LensApi, isLensApi } from './interfaces/lens_api'; +export * from './actions'; +export * from './name'; +export * from './risk_score'; +export * from './severity'; +export * from './status'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx new file mode 100644 index 000000000000..7b7cf228895f --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/name.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiLink } from '@elastic/eui'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import * as i18n from './translations'; +import type { TableColumn } from './constants'; + +interface NameProps { + name: string; + rule: RuleMigration; + openMigrationRulePreview: (rule: RuleMigration) => void; +} + +const Name = ({ name, rule, openMigrationRulePreview }: NameProps) => { + return ( + <EuiLink + onClick={() => { + openMigrationRulePreview(rule); + }} + data-test-subj="ruleName" + > + {name} + </EuiLink> + ); +}; + +export const createNameColumn = ({ + openMigrationRulePreview, +}: { + openMigrationRulePreview: (rule: RuleMigration) => void; +}): TableColumn => { + return { + field: 'original_rule.title', + name: i18n.COLUMN_NAME, + render: (value: RuleMigration['original_rule']['title'], rule: RuleMigration) => ( + <Name name={value} rule={rule} openMigrationRulePreview={openMigrationRulePreview} /> + ), + sortable: true, + truncateText: true, + width: '40%', + align: 'left', + }; +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/risk_score.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/risk_score.tsx new file mode 100644 index 000000000000..e9eca65736a5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/risk_score.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiText } from '@elastic/eui'; +import { DEFAULT_TRANSLATION_RISK_SCORE } from '../../../../../common/siem_migrations/constants'; +import * as i18n from './translations'; +import type { TableColumn } from './constants'; + +export const createRiskScoreColumn = (): TableColumn => { + return { + field: 'risk_score', + name: i18n.COLUMN_RISK_SCORE, + render: () => ( + <EuiText data-test-subj="riskScore" size="s"> + {DEFAULT_TRANSLATION_RISK_SCORE} + </EuiText> + ), + sortable: true, + truncateText: true, + width: '75px', + }; +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/severity.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/severity.tsx new file mode 100644 index 000000000000..4ea737844ad5 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/severity.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; +import { DEFAULT_TRANSLATION_SEVERITY } from '../../../../../common/siem_migrations/constants'; +import { getNormalizedSeverity } from '../../../../detection_engine/rule_management_ui/components/rules_table/helpers'; +import { SeverityBadge } from '../../../../common/components/severity_badge'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import type { TableColumn } from './constants'; +import * as i18n from './translations'; + +export const createSeverityColumn = (): TableColumn => { + return { + field: 'elastic_rule.severity', + name: i18n.COLUMN_SEVERITY, + render: (value?: Severity) => <SeverityBadge value={value ?? DEFAULT_TRANSLATION_SEVERITY} />, + sortable: ({ elastic_rule: elasticRule }: RuleMigration) => + getNormalizedSeverity((elasticRule?.severity as Severity) ?? DEFAULT_TRANSLATION_SEVERITY), + truncateText: true, + width: '12%', + }; +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/status.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/status.tsx new file mode 100644 index 000000000000..982f6ba7580b --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/status.tsx @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import * as i18n from './translations'; +import type { TableColumn } from './constants'; +import { StatusBadge } from '../status_badge'; + +export const createStatusColumn = (): TableColumn => { + return { + field: 'translation_result', + name: i18n.COLUMN_STATUS, + render: (value: RuleMigration['translation_result'], rule: RuleMigration) => ( + <StatusBadge value={value} installedRuleId={rule.elastic_rule?.id} /> + ), + sortable: false, + truncateText: true, + width: '12%', + }; +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts new file mode 100644 index 000000000000..906e752d79aa --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/rules_table_columns/translations.ts @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const COLUMN_ACTIONS = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.actionsLabel', + { + defaultMessage: 'Actions', + } +); + +export const ACTIONS_VIEW_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.actionsViewLabel', + { + defaultMessage: 'View', + } +); + +export const ACTIONS_EDIT_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.actionsEditLabel', + { + defaultMessage: 'Edit', + } +); + +export const ACTIONS_INSTALL_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.actionsInstallLabel', + { + defaultMessage: 'Install', + } +); + +export const ACTIONS_RESTART_LABEL = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.actionsRestartLabel', + { + defaultMessage: 'Restart', + } +); + +export const COLUMN_NAME = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.nameLabel', + { + defaultMessage: 'Name', + } +); + +export const COLUMN_STATUS = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.statusLabel', + { + defaultMessage: 'Status', + } +); + +export const COLUMN_RISK_SCORE = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.riskScoreLabel', + { + defaultMessage: 'Risk score', + } +); + +export const COLUMN_SEVERITY = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.tableColumn.severityLabel', + { + defaultMessage: 'Severity', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx index 4aaff21281d6..b6dce09c311e 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/translation_details_flyout/index.tsx @@ -25,6 +25,10 @@ import { } from '@elastic/eui'; import type { EuiTabbedContentTab, EuiTabbedContentProps, EuiFlyoutProps } from '@elastic/eui'; +import { + DEFAULT_TRANSLATION_RISK_SCORE, + DEFAULT_TRANSLATION_SEVERITY, +} from '../../../../../common/siem_migrations/constants'; import type { RuleMigration } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import { RuleOverviewTab, @@ -41,10 +45,6 @@ import { LARGE_DESCRIPTION_LIST_COLUMN_WIDTHS, } from './constants'; import { TranslationTab } from './translation_tab'; -import { - DEFAULT_TRANSLATION_RISK_SCORE, - DEFAULT_TRANSLATION_SEVERITY, -} from '../../utils/constants'; const StyledEuiFlyoutBody = styled(EuiFlyoutBody)` .euiFlyoutBody__overflow { diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/index.tsx new file mode 100644 index 000000000000..0a33869eff41 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/index.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiEmptyPrompt, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import * as i18n from './translations'; + +const UnknownMigrationComponent = () => { + return ( + <EuiFlexGroup + alignItems="center" + gutterSize="s" + responsive={false} + direction="column" + wrap={true} + > + <EuiFlexItem grow={false}> + <EuiEmptyPrompt + title={<h2>{i18n.UNKNOWN_MIGRATION}</h2>} + titleSize="s" + body={i18n.UNKNOWN_MIGRATION_BODY} + data-test-subj="noMigrationsAvailable" + /> + </EuiFlexItem> + </EuiFlexGroup> + ); +}; + +export const UnknownMigration = React.memo(UnknownMigrationComponent); +UnknownMigration.displayName = 'UnknownMigration'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/translations.ts new file mode 100644 index 000000000000..8720640858b9 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/components/unknown_migration/translations.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const UNKNOWN_MIGRATION = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.unknownMigrationTitle', + { + defaultMessage: 'Unknown migration', + } +); + +export const UNKNOWN_MIGRATION_BODY = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.unknownMigrationBodyTitle', + { + defaultMessage: + 'Selected migration does not exist. Please select one of the available migraitons', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_latest_stats.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_latest_stats.ts new file mode 100644 index 000000000000..c681af0d2a21 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_latest_stats.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import useObservable from 'react-use/lib/useObservable'; +import { useEffect, useMemo } from 'react'; +import { useKibana } from '../../../common/lib/kibana'; + +export const useLatestStats = () => { + const { siemMigrations } = useKibana().services; + + useEffect(() => { + siemMigrations.rules.startPolling(); + }, [siemMigrations.rules]); + + const latestStats$ = useMemo(() => siemMigrations.rules.getLatestStats$(), [siemMigrations]); + const latestStats = useObservable(latestStats$, null); + + return { data: latestStats ?? [], isLoading: latestStats === null }; +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx index 3b13b9e631cc..b7e06b4ea938 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/hooks/use_rules_table_columns.tsx @@ -5,103 +5,38 @@ * 2.0. */ -import type { EuiBasicTableColumn } from '@elastic/eui'; -import { EuiText, EuiLink } from '@elastic/eui'; -import React, { useMemo } from 'react'; -import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; +import { useMemo } from 'react'; import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; -import { SeverityBadge } from '../../../common/components/severity_badge'; -import * as rulesI18n from '../../../detections/pages/detection_engine/rules/translations'; -import * as i18n from './translations'; -import { getNormalizedSeverity } from '../../../detection_engine/rule_management_ui/components/rules_table/helpers'; -import { StatusBadge } from '../components/status_badge'; -import { DEFAULT_TRANSLATION_RISK_SCORE, DEFAULT_TRANSLATION_SEVERITY } from '../utils/constants'; - -export type TableColumn = EuiBasicTableColumn<RuleMigration>; - -interface RuleNameProps { - name: string; - rule: RuleMigration; - openRulePreview: (rule: RuleMigration) => void; -} - -const RuleName = ({ name, rule, openRulePreview }: RuleNameProps) => { - return ( - <EuiLink - onClick={() => { - openRulePreview(rule); - }} - data-test-subj="ruleName" - > - {name} - </EuiLink> - ); -}; - -const createRuleNameColumn = ({ - openRulePreview, -}: { - openRulePreview: (rule: RuleMigration) => void; -}): TableColumn => { - return { - field: 'original_rule.title', - name: rulesI18n.COLUMN_RULE, - render: (value: RuleMigration['original_rule']['title'], rule: RuleMigration) => ( - <RuleName name={value} rule={rule} openRulePreview={openRulePreview} /> - ), - sortable: true, - truncateText: true, - width: '40%', - align: 'left', - }; -}; - -const STATUS_COLUMN: TableColumn = { - field: 'translation_result', - name: i18n.COLUMN_STATUS, - render: (value: RuleMigration['translation_result'], rule: RuleMigration) => ( - <StatusBadge value={value} installedRuleId={rule.elastic_rule?.id} /> - ), - sortable: false, - truncateText: true, - width: '12%', -}; +import type { TableColumn } from '../components/rules_table_columns'; +import { + createActionsColumn, + createNameColumn, + createRiskScoreColumn, + createSeverityColumn, + createStatusColumn, +} from '../components/rules_table_columns'; export const useRulesTableColumns = ({ - openRulePreview, + disableActions, + openMigrationRulePreview, + installMigrationRule, }: { - openRulePreview: (rule: RuleMigration) => void; + disableActions?: boolean; + openMigrationRulePreview: (rule: RuleMigration) => void; + installMigrationRule: (migrationRule: RuleMigration, enable?: boolean) => void; }): TableColumn[] => { return useMemo( () => [ - createRuleNameColumn({ openRulePreview }), - STATUS_COLUMN, - { - field: 'risk_score', - name: rulesI18n.COLUMN_RISK_SCORE, - render: () => ( - <EuiText data-test-subj="riskScore" size="s"> - {DEFAULT_TRANSLATION_RISK_SCORE} - </EuiText> - ), - sortable: true, - truncateText: true, - width: '75px', - }, - { - field: 'elastic_rule.severity', - name: rulesI18n.COLUMN_SEVERITY, - render: (value?: Severity) => ( - <SeverityBadge value={value ?? DEFAULT_TRANSLATION_SEVERITY} /> - ), - sortable: ({ elastic_rule: elasticRule }: RuleMigration) => - getNormalizedSeverity( - (elasticRule?.severity as Severity) ?? DEFAULT_TRANSLATION_SEVERITY - ), - truncateText: true, - width: '12%', - }, + createNameColumn({ openMigrationRulePreview }), + createStatusColumn(), + createRiskScoreColumn(), + createSeverityColumn(), + createActionsColumn({ + disableActions, + openMigrationRulePreview, + installMigrationRule, + }), ], - [openRulePreview] + [disableActions, installMigrationRule, openMigrationRulePreview] ); }; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/translations.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/translations.ts new file mode 100644 index 000000000000..23f5a6e3849a --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/translations.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; + +export const GET_MIGRATION_RULES_FAILURE = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.getMigrationRulesFailDescription', + { + defaultMessage: 'Failed to fetch migration rules', + } +); + +export const INSTALL_MIGRATION_RULES_FAILURE = i18n.translate( + 'xpack.securitySolution.siemMigrations.rules.installMigrationRulesFailDescription', + { + defaultMessage: 'Failed to install migration rules', + } +); diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.ts new file mode 100644 index 000000000000..27637daf142f --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_get_migration_rules.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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useGetMigrationRulesQuery } from '../api/hooks/use_get_migration_rules_query'; +import * as i18n from './translations'; + +export const useGetMigrationRules = (migrationId: string) => { + const { addError } = useAppToasts(); + + return useGetMigrationRulesQuery(migrationId, { + onError: (error) => { + addError(error, { title: i18n.GET_MIGRATION_RULES_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_all_migration_rules.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_all_migration_rules.ts new file mode 100644 index 000000000000..105ea651d0a8 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_all_migration_rules.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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useInstallAllMigrationRulesMutation } from '../api/hooks/use_install_all_migration_rules_mutation'; +import * as i18n from './translations'; + +export const useInstallAllMigrationRules = (migrationId: string) => { + const { addError } = useAppToasts(); + + return useInstallAllMigrationRulesMutation(migrationId, { + onError: (error) => { + addError(error, { title: i18n.INSTALL_MIGRATION_RULES_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.ts new file mode 100644 index 000000000000..dcc19f290f87 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/logic/use_install_migration_rules.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 { useAppToasts } from '../../../common/hooks/use_app_toasts'; +import { useInstallMigrationRulesMutation } from '../api/hooks/use_install_migration_rules_mutation'; +import * as i18n from './translations'; + +export const useInstallMigrationRules = (migrationId: string) => { + const { addError } = useAppToasts(); + + return useInstallMigrationRulesMutation(migrationId, { + onError: (error) => { + addError(error, { title: i18n.INSTALL_MIGRATION_RULES_FAILURE }); + }, + }); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx index 616c85e7e7de..dabdb83cccba 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/pages/index.tsx @@ -5,100 +5,98 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useEffect, useMemo } from 'react'; import { EuiSkeletonLoading, EuiSkeletonText, EuiSkeletonTitle } from '@elastic/eui'; -import type { RuleMigration } from '../../../../common/siem_migrations/model/rule_migration.gen'; -import { SecurityPageName } from '../../../app/types'; +import type { RouteComponentProps } from 'react-router-dom'; +import { useNavigation } from '../../../common/lib/kibana'; import { HeaderPage } from '../../../common/components/header_page'; import { SecuritySolutionPageWrapper } from '../../../common/components/page_wrapper'; -import { SpyRoute } from '../../../common/utils/route/spy_routes'; +import { SecurityPageName } from '../../../app/types'; import * as i18n from './translations'; import { RulesTable } from '../components/rules_table'; import { NeedAdminForUpdateRulesCallOut } from '../../../detections/components/callouts/need_admin_for_update_callout'; import { MissingPrivilegesCallOut } from '../../../detections/components/callouts/missing_privileges_callout'; import { HeaderButtons } from '../components/header_buttons'; -import { useGetRuleMigrationsStatsAllQuery } from '../api/hooks/use_get_rule_migrations_stats_all'; -import { useRulePreviewFlyout } from '../hooks/use_rule_preview_flyout'; -import { NoMigrations } from '../components/no_migrations'; +import { UnknownMigration } from '../components/unknown_migration'; +import { useLatestStats } from '../hooks/use_latest_stats'; -const RulesPageComponent: React.FC = () => { - const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = - useGetRuleMigrationsStatsAllQuery(); +type RulesMigrationPageProps = RouteComponentProps<{ migrationId?: string }>; - const migrationsIds = useMemo(() => { - if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { - return []; - } - return ruleMigrationsStatsAll - .filter((migration) => migration.status === 'finished') - .map((migration) => migration.migration_id); - }, [isLoadingMigrationsStats, ruleMigrationsStatsAll]); +export const RulesPage: React.FC<RulesMigrationPageProps> = React.memo( + ({ + match: { + params: { migrationId }, + }, + }) => { + const { navigateTo } = useNavigation(); - const [selectedMigrationId, setSelectedMigrationId] = useState<string | undefined>(); - const onMigrationIdChange = (selectedId?: string) => { - setSelectedMigrationId(selectedId); - }; + const { data: ruleMigrationsStatsAll, isLoading: isLoadingMigrationsStats } = useLatestStats(); - useEffect(() => { - if (!migrationsIds.length) { - return; - } - const index = migrationsIds.findIndex((id) => id === selectedMigrationId); - if (index === -1) { - setSelectedMigrationId(migrationsIds[0]); - } - }, [migrationsIds, selectedMigrationId]); + const migrationsIds = useMemo(() => { + if (isLoadingMigrationsStats || !ruleMigrationsStatsAll?.length) { + return []; + } + return ruleMigrationsStatsAll + .filter((migration) => migration.status === 'finished') + .map((migration) => migration.id); + }, [isLoadingMigrationsStats, ruleMigrationsStatsAll]); - const ruleActionsFactory = useCallback( - (ruleMigration: RuleMigration, closeRulePreview: () => void) => { - // TODO: Add flyout action buttons - return null; - }, - [] - ); + useEffect(() => { + if (isLoadingMigrationsStats) { + return; + } - const { rulePreviewFlyout, openRulePreview } = useRulePreviewFlyout({ - ruleActionsFactory, - }); + // Navigate to landing page if there are no migrations + if (!migrationsIds.length) { + navigateTo({ deepLinkId: SecurityPageName.landing, path: 'siem_migrations' }); + return; + } - return ( - <> - <NeedAdminForUpdateRulesCallOut /> - <MissingPrivilegesCallOut /> + // Navigate to the most recent migration if none is selected + if (!migrationId) { + navigateTo({ deepLinkId: SecurityPageName.siemMigrationsRules, path: migrationsIds[0] }); + } + }, [isLoadingMigrationsStats, migrationId, migrationsIds, navigateTo]); - <SecuritySolutionPageWrapper> - <HeaderPage title={i18n.PAGE_TITLE}> - <HeaderButtons - migrationsIds={migrationsIds} - selectedMigrationId={selectedMigrationId} - onMigrationIdChange={onMigrationIdChange} - /> - </HeaderPage> - <EuiSkeletonLoading - isLoading={isLoadingMigrationsStats} - loadingContent={ - <> - <EuiSkeletonTitle /> - <EuiSkeletonText /> - </> - } - loadedContent={ - selectedMigrationId ? ( - <RulesTable migrationId={selectedMigrationId} openRulePreview={openRulePreview} /> - ) : ( - <NoMigrations /> - ) - } - /> - {rulePreviewFlyout} - </SecuritySolutionPageWrapper> + const onMigrationIdChange = (selectedId?: string) => { + navigateTo({ deepLinkId: SecurityPageName.siemMigrationsRules, path: selectedId }); + }; + + const content = useMemo(() => { + if (!migrationId || !migrationsIds.includes(migrationId)) { + return <UnknownMigration />; + } + return <RulesTable migrationId={migrationId} />; + }, [migrationId, migrationsIds]); - <SpyRoute pageName={SecurityPageName.siemMigrationsRules} /> - </> - ); -}; + return ( + <> + <NeedAdminForUpdateRulesCallOut /> + <MissingPrivilegesCallOut /> -export const RulesPage = React.memo(RulesPageComponent); + <SecuritySolutionPageWrapper> + <HeaderPage title={i18n.PAGE_TITLE}> + <HeaderButtons + migrationsIds={migrationsIds} + selectedMigrationId={migrationId} + onMigrationIdChange={onMigrationIdChange} + /> + </HeaderPage> + <EuiSkeletonLoading + isLoading={isLoadingMigrationsStats} + loadingContent={ + <> + <EuiSkeletonTitle /> + <EuiSkeletonText /> + </> + } + loadedContent={content} + /> + </SecuritySolutionPageWrapper> + </> + ); + } +); RulesPage.displayName = 'RulesPage'; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts new file mode 100644 index 000000000000..a872d79a4602 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/rule_migrations_service.ts @@ -0,0 +1,112 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { BehaviorSubject, type Observable } from 'rxjs'; +import type { CoreStart } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; +import { SiemMigrationTaskStatus } from '../../../../common/siem_migrations/constants'; +import type { StartPluginsDependencies } from '../../../types'; +import { ExperimentalFeaturesService } from '../../../common/experimental_features_service'; +import { licenseService } from '../../../common/hooks/use_license'; +import { getRuleMigrationsStatsAll, startRuleMigration } from '../api/api'; +import type { RuleMigrationTask } from '../types'; +import { getSuccessToast } from './success_notification'; +import { RuleMigrationsStorage } from './storage'; + +export class SiemRulesMigrationsService { + private readonly pollingInterval = 5000; + private readonly latestStats$: BehaviorSubject<RuleMigrationTask[]>; + private readonly signal = new AbortController().signal; + private isPolling = false; + public connectorIdStorage = new RuleMigrationsStorage('connectorId'); + + constructor( + private readonly core: CoreStart, + private readonly plugins: StartPluginsDependencies + ) { + this.latestStats$ = new BehaviorSubject<RuleMigrationTask[]>([]); + + this.plugins.spaces.getActiveSpace().then((space) => { + this.connectorIdStorage.setSpaceId(space.id); + this.startPolling(); + }); + } + + public getLatestStats$(): Observable<RuleMigrationTask[]> { + return this.latestStats$.asObservable(); + } + + public isAvailable() { + return ExperimentalFeaturesService.get().siemMigrationsEnabled && licenseService.isEnterprise(); + } + + public startPolling() { + if (this.isPolling || !this.isAvailable()) { + return; + } + + this.isPolling = true; + this.startStatsPolling() + .catch((e) => { + this.core.notifications.toasts.addError(e, { + title: i18n.translate( + 'xpack.securitySolution.siemMigrations.rulesService.polling.errorTitle', + { defaultMessage: 'Error fetching rule migrations' } + ), + }); + }) + .finally(() => { + this.isPolling = false; + }); + } + + private async startStatsPolling(): Promise<void> { + let pendingMigrationIds: string[] = []; + do { + const results = await this.fetchRuleMigrationTasksStats(); + this.latestStats$.next(results); + + if (pendingMigrationIds.length > 0) { + // send notifications for finished migrations + pendingMigrationIds.forEach((pendingMigrationId) => { + const migration = results.find((item) => item.id === pendingMigrationId); + if (migration?.status === SiemMigrationTaskStatus.FINISHED) { + this.core.notifications.toasts.addSuccess(getSuccessToast(migration, this.core)); + } + }); + } + + // reprocess pending migrations + pendingMigrationIds = []; + for (const result of results) { + if (result.status === SiemMigrationTaskStatus.RUNNING) { + pendingMigrationIds.push(result.id); + } + + if (result.status === SiemMigrationTaskStatus.STOPPED) { + const connectorId = this.connectorIdStorage.get(); + if (connectorId) { + // automatically resume stopped migrations when connector is available + await startRuleMigration({ + migrationId: result.id, + body: { connector_id: connectorId }, + signal: this.signal, + }); + pendingMigrationIds.push(result.id); + } + } + } + + await new Promise((resolve) => setTimeout(resolve, this.pollingInterval)); + } while (pendingMigrationIds.length > 0); + } + + private async fetchRuleMigrationTasksStats(): Promise<RuleMigrationTask[]> { + const stats = await getRuleMigrationsStatsAll({ signal: this.signal }); + return stats.map((stat, index) => ({ ...stat, number: index + 1 })); // the array order (by creation) is guaranteed by the API + } +} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/service/storage.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/storage.ts new file mode 100644 index 000000000000..bbf53ec3a540 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/storage.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Storage } from '@kbn/kibana-utils-plugin/public'; + +export class RuleMigrationsStorage { + private readonly storage = new Storage(localStorage); + public key: string; + + constructor(private readonly objectName: string, spaceId?: string) { + this.key = this.getStorageKey(spaceId); + } + + private getStorageKey(spaceId: string = 'default') { + return `siem_migrations.rules.${this.objectName}.${spaceId}`; + } + + public setSpaceId(spaceId: string) { + this.key = this.getStorageKey(spaceId); + } + + public get = () => this.storage.get(this.key); + public set = (value: string) => this.storage.set(this.key, value); + public remove = () => this.storage.remove(this.key); +} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/service/success_notification.tsx b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/success_notification.tsx new file mode 100644 index 000000000000..830e3c5f4a53 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/service/success_notification.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 from 'react'; +import type { CoreStart } from '@kbn/core-lifecycle-browser'; +import { i18n } from '@kbn/i18n'; +import { + SecurityPageName, + useNavigation, + NavigationProvider, +} from '@kbn/security-solution-navigation'; +import type { ToastInput } from '@kbn/core-notifications-browser'; +import { toMountPoint } from '@kbn/react-kibana-mount'; +import { FormattedMessage } from '@kbn/i18n-react'; +import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import type { RuleMigrationTask } from '../types'; + +export const getSuccessToast = (migration: RuleMigrationTask, core: CoreStart): ToastInput => ({ + color: 'success', + iconType: 'check', + toastLifeTimeMs: 1000 * 60 * 30, // 30 minutes + title: i18n.translate('xpack.securitySolution.siemMigrations.rulesService.polling.successTitle', { + defaultMessage: 'Rules translation complete.', + }), + text: toMountPoint( + <NavigationProvider core={core}> + <SuccessToastContent migration={migration} /> + </NavigationProvider>, + core + ), +}); + +const SuccessToastContent: React.FC<{ migration: RuleMigrationTask }> = ({ migration }) => { + const navigation = { deepLinkId: SecurityPageName.siemMigrationsRules, path: migration.id }; + + const { navigateTo, getAppUrl } = useNavigation(); + const onClick: React.MouseEventHandler = (ev) => { + ev.preventDefault(); + navigateTo(navigation); + }; + const url = getAppUrl(navigation); + + return ( + <EuiFlexGroup direction="column" alignItems="flexEnd" gutterSize="s"> + <EuiFlexItem> + <FormattedMessage + id="xpack.securitySolution.siemMigrations.rulesService.polling.successText" + defaultMessage="SIEM rules migration #{number} has finished translating. Results have been added to a dedicated page." + values={{ number: migration.number }} + /> + </EuiFlexItem> + <EuiFlexItem> + {/* eslint-disable-next-line @elastic/eui/href-or-on-click */} + <EuiButton onClick={onClick} href={url} color="success"> + {i18n.translate( + 'xpack.securitySolution.siemMigrations.rulesService.polling.successLinkText', + { defaultMessage: 'Go to translated rules' } + )} + </EuiButton> + </EuiFlexItem> + </EuiFlexGroup> + ); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/types.ts b/x-pack/plugins/security_solution/public/siem_migrations/rules/types.ts new file mode 100644 index 000000000000..b395fa0199de --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/rules/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { RuleMigrationTaskStats } from '../../../common/siem_migrations/model/rule_migration.gen'; + +export interface RuleMigrationTask extends RuleMigrationTaskStats { + /** The sequential number of the migration */ + number: number; +} + +export interface InstallRulesProps { + migrationId: string; + ids: string[]; + signal?: AbortSignal; +} + +export interface InstallTranslatedRulesProps { + migrationId: string; + signal?: AbortSignal; +} diff --git a/x-pack/plugins/security_solution/public/siem_migrations/service/index.ts b/x-pack/plugins/security_solution/public/siem_migrations/service/index.ts new file mode 100644 index 000000000000..dbea3624c7c1 --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/service/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreStart } from '@kbn/core-lifecycle-browser'; +import type { StartPluginsDependencies } from '../../types'; + +export type { SiemMigrationsService } from './siem_migrations_service'; + +export const createSiemMigrationsService = async ( + coreStart: CoreStart, + plugins: StartPluginsDependencies +) => { + const { SiemMigrationsService } = await import( + /* webpackChunkName: "lazySiemMigrationsService" */ + './siem_migrations_service' + ); + return new SiemMigrationsService(coreStart, plugins); +}; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/service/siem_migrations_service.ts b/x-pack/plugins/security_solution/public/siem_migrations/service/siem_migrations_service.ts new file mode 100644 index 000000000000..da733bf5926e --- /dev/null +++ b/x-pack/plugins/security_solution/public/siem_migrations/service/siem_migrations_service.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreStart } from '@kbn/core/public'; +import type { StartPluginsDependencies } from '../../types'; +import { SiemRulesMigrationsService } from '../rules/service/rule_migrations_service'; + +export class SiemMigrationsService { + public rules: SiemRulesMigrationsService; + + constructor(coreStart: CoreStart, plugins: StartPluginsDependencies) { + this.rules = new SiemRulesMigrationsService(coreStart, plugins); + } +} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx index 52344857a07c..a7769069ff19 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.test.tsx @@ -12,30 +12,14 @@ import { HostName } from './host_name'; import { TestProviders } from '../../../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; import { TableId } from '@kbn/securitysolution-data-table'; import { createExpandableFlyoutApiMock } from '../../../../../common/mock/expandable_flyout'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; -const mockedTelemetry = createTelemetryServiceMock(); const mockOpenRightPanel = jest.fn(); jest.mock('@kbn/expandable-flyout'); -jest.mock('../../../../../common/lib/kibana/kibana_react', () => { - return { - useKibana: () => ({ - services: { - application: { - getUrlForApp: jest.fn(), - navigateToApp: jest.fn(), - }, - telemetry: mockedTelemetry, - }, - }), - }; -}); - jest.mock('../../../../../common/components/draggables', () => ({ DefaultDraggable: () => <div data-test-subj="DefaultDraggable" />, })); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx index 845b826e5866..41d403b3f2c5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/host_name.tsx @@ -15,6 +15,7 @@ import { HostDetailsLink } from '../../../../../common/components/links'; import { DefaultDraggable } from '../../../../../common/components/draggables'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; import { TruncatableText } from '../../../../../common/components/truncatable_text'; +import { useIsInSecurityApp } from '../../../../../common/hooks/is_in_security_app'; interface Props { contextId: string; @@ -45,6 +46,8 @@ const HostNameComponent: React.FC<Props> = ({ }) => { const { openRightPanel } = useExpandableFlyoutApi(); + const isInSecurityApp = useIsInSecurityApp(); + const eventContext = useContext(StatefulEventContext); const hostName = `${value}`; const isInTimelineContext = @@ -58,6 +61,10 @@ const HostNameComponent: React.FC<Props> = ({ onClick(); } + /* + * if and only if renderer is running inside security solution app + * we check for event and timeline context + * */ if (!eventContext || !isInTimelineContext) { return; } @@ -85,13 +92,21 @@ const HostNameComponent: React.FC<Props> = ({ Component={Component} hostName={hostName} isButton={isButton} - onClick={isInTimelineContext ? openHostDetailsSidePanel : undefined} + onClick={isInTimelineContext || !isInSecurityApp ? openHostDetailsSidePanel : undefined} title={title} > <TruncatableText data-test-subj="draggable-truncatable-content">{hostName}</TruncatableText> </HostDetailsLink> ), - [Component, hostName, isButton, isInTimelineContext, openHostDetailsSidePanel, title] + [ + Component, + hostName, + isButton, + isInTimelineContext, + openHostDetailsSidePanel, + title, + isInSecurityApp, + ] ); return isString(value) && hostName.length > 0 ? ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx index 6c3dffc58ce2..bdb53f5850ec 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.test.tsx @@ -12,30 +12,14 @@ import { TestProviders } from '../../../../../common/mock'; import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; import { UserName } from './user_name'; import { StatefulEventContext } from '../../../../../common/components/events_viewer/stateful_event_context'; -import { createTelemetryServiceMock } from '../../../../../common/lib/telemetry/telemetry_service.mock'; import { TableId } from '@kbn/securitysolution-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { createExpandableFlyoutApiMock } from '../../../../../common/mock/expandable_flyout'; -const mockedTelemetry = createTelemetryServiceMock(); const mockOpenRightPanel = jest.fn(); jest.mock('@kbn/expandable-flyout'); -jest.mock('../../../../../common/lib/kibana/kibana_react', () => { - return { - useKibana: () => ({ - services: { - application: { - getUrlForApp: jest.fn(), - navigateToApp: jest.fn(), - }, - telemetry: mockedTelemetry, - }, - }), - }; -}); - jest.mock('../../../../../common/components/draggables', () => ({ DefaultDraggable: () => <div data-test-subj="DefaultDraggable" />, })); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx index 1f070d52a8de..31a8424e5ea0 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/renderers/user_name.tsx @@ -15,6 +15,7 @@ import { DefaultDraggable } from '../../../../../common/components/draggables'; import { getEmptyTagValue } from '../../../../../common/components/empty_value'; import { UserDetailsLink } from '../../../../../common/components/links'; import { TruncatableText } from '../../../../../common/components/truncatable_text'; +import { useIsInSecurityApp } from '../../../../../common/hooks/is_in_security_app'; interface Props { contextId: string; @@ -48,6 +49,8 @@ const UserNameComponent: React.FC<Props> = ({ const isInTimelineContext = userName && eventContext?.timelineID; const { openRightPanel } = useExpandableFlyoutApi(); + const isInSecurityApp = useIsInSecurityApp(); + const openUserDetailsSidePanel = useCallback( (e: React.SyntheticEvent) => { e.preventDefault(); @@ -83,13 +86,21 @@ const UserNameComponent: React.FC<Props> = ({ Component={Component} userName={userName} isButton={isButton} - onClick={isInTimelineContext ? openUserDetailsSidePanel : undefined} + onClick={isInTimelineContext || !isInSecurityApp ? openUserDetailsSidePanel : undefined} title={title} > <TruncatableText data-test-subj="draggable-truncatable-content">{userName}</TruncatableText> </UserDetailsLink> ), - [userName, isButton, isInTimelineContext, openUserDetailsSidePanel, Component, title] + [ + userName, + isButton, + isInTimelineContext, + openUserDetailsSidePanel, + Component, + title, + isInSecurityApp, + ] ); return isString(value) && userName.length > 0 ? ( diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx index 41cdec6d6d4b..77f26075581e 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.test.tsx @@ -12,7 +12,7 @@ import { UnifiedTimeline } from '../unified_components'; import { defaultUdtHeaders } from './column_headers/default_headers'; import type { UnifiedTimelineBodyProps } from './unified_timeline_body'; import { UnifiedTimelineBody } from './unified_timeline_body'; -import { render, screen } from '@testing-library/react'; +import { render } from '@testing-library/react'; import { defaultHeaders, mockTimelineData, TestProviders } from '../../../../common/mock'; jest.mock('../unified_components', () => { @@ -32,17 +32,14 @@ const defaultProps: UnifiedTimelineBodyProps = { isTextBasedQuery: false, itemsPerPage: 25, itemsPerPageOptions: [10, 25, 50], - onChangePage: jest.fn(), + onFetchMoreRecords: jest.fn(), refetch: jest.fn(), rowRenderers: [], sort: [], timelineId: 'timeline-1', totalCount: 0, updatedAt: 0, - pageInfo: { - activePage: 0, - querySize: 0, - }, + onUpdatePageIndex: jest.fn(), }; const renderTestComponents = (props?: UnifiedTimelineBodyProps) => { @@ -57,39 +54,6 @@ describe('UnifiedTimelineBody', () => { beforeEach(() => { (UnifiedTimeline as unknown as jest.Mock).mockImplementation(MockUnifiedTimelineComponent); }); - it('should pass correct page rows', () => { - const { rerender } = renderTestComponents(); - - expect(screen.getByTestId('unifiedTimelineBody')).toBeVisible(); - expect(MockUnifiedTimelineComponent).toHaveBeenCalledTimes(2); - - expect(MockUnifiedTimelineComponent).toHaveBeenLastCalledWith( - expect.objectContaining({ - events: mockEventsData.flat(), - }), - {} - ); - - const newEventsData = structuredClone([mockEventsData[0]]); - - const newProps = { - ...defaultProps, - pageInfo: { - activePage: 1, - querySize: 0, - }, - events: newEventsData, - }; - - MockUnifiedTimelineComponent.mockClear(); - rerender(<UnifiedTimelineBody {...newProps} />); - expect(MockUnifiedTimelineComponent).toHaveBeenLastCalledWith( - expect.objectContaining({ - events: [...mockEventsData, ...newEventsData].flat(), - }), - {} - ); - }); it('should pass default columns when empty column list is supplied', () => { const newProps = { ...defaultProps, columns: [] }; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx index 95feab854361..b705717fc437 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/body/unified_timeline_body.tsx @@ -6,23 +6,20 @@ */ import type { ComponentProps, ReactElement } from 'react'; -import React, { useEffect, useState, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { RootDragDropProvider } from '@kbn/dom-drag-drop'; import { StyledTableFlexGroup, StyledUnifiedTableFlexItem } from '../unified_components/styles'; import { UnifiedTimeline } from '../unified_components'; import { defaultUdtHeaders } from './column_headers/default_headers'; -import type { PaginationInputPaginated, TimelineItem } from '../../../../../common/search_strategy'; export interface UnifiedTimelineBodyProps extends ComponentProps<typeof UnifiedTimeline> { header: ReactElement; - pageInfo: Pick<PaginationInputPaginated, 'activePage' | 'querySize'>; } export const UnifiedTimelineBody = (props: UnifiedTimelineBodyProps) => { const { header, isSortEnabled, - pageInfo, columns, rowRenderers, timelineId, @@ -33,28 +30,14 @@ export const UnifiedTimelineBody = (props: UnifiedTimelineBodyProps) => { refetch, dataLoadingState, totalCount, - onChangePage, + onFetchMoreRecords, activeTab, updatedAt, trailingControlColumns, leadingControlColumns, + onUpdatePageIndex, } = props; - const [pageRows, setPageRows] = useState<TimelineItem[][]>([]); - - const rows = useMemo(() => pageRows.flat(), [pageRows]); - - useEffect(() => { - setPageRows((currentPageRows) => { - if (pageInfo.activePage !== 0 && currentPageRows[pageInfo.activePage]?.length) { - return currentPageRows; - } - const newPageRows = pageInfo.activePage === 0 ? [] : [...currentPageRows]; - newPageRows[pageInfo.activePage] = events; - return newPageRows; - }); - }, [events, pageInfo.activePage]); - const columnsHeader = useMemo(() => columns ?? defaultUdtHeaders, [columns]); return ( @@ -73,16 +56,17 @@ export const UnifiedTimelineBody = (props: UnifiedTimelineBodyProps) => { itemsPerPage={itemsPerPage} itemsPerPageOptions={itemsPerPageOptions} sort={sort} - events={rows} + events={events} refetch={refetch} dataLoadingState={dataLoadingState} totalCount={totalCount} - onChangePage={onChangePage} + onFetchMoreRecords={onFetchMoreRecords} activeTab={activeTab} updatedAt={updatedAt} isTextBasedQuery={false} trailingControlColumns={trailingControlColumns} leadingControlColumns={leadingControlColumns} + onUpdatePageIndex={onUpdatePageIndex} /> </RootDragDropProvider> </StyledUnifiedTableFlexItem> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts b/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts index 14046b853a23..c48e38ba69a2 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/events.ts @@ -13,7 +13,7 @@ export type { OnColumnsSorted, OnColumnRemoved, OnColumnResized, - OnChangePage, + OnFetchMoreRecords as OnChangePage, OnPinEvent, OnRowSelected, OnSelectAll, diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx index f925a1d83d13..c378f5290cde 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/query_bar/eql/index.tsx @@ -16,7 +16,7 @@ import { useSourcererDataView } from '../../../../../sourcerer/containers'; import { useDeepEqualSelector } from '../../../../../common/hooks/use_selector'; import { SourcererScopeName } from '../../../../../sourcerer/store/model'; import { EqlQueryEdit } from '../../../../../detection_engine/rule_creation/components/eql_query_edit'; -import type { FieldValueQueryBar } from '../../../../../detection_engine/rule_creation_ui/components/query_bar'; +import type { FieldValueQueryBar } from '../../../../../detection_engine/rule_creation_ui/components/query_bar_field'; import type { FormSchema, FormSubmitHandler } from '../../../../../shared_imports'; import { Form, UseField, useForm } from '../../../../../shared_imports'; diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx index 23fb44d04910..a71f99715131 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.test.tsx @@ -5,18 +5,16 @@ * 2.0. */ -import React from 'react'; +import type { ComponentProps } from 'react'; +import React, { useEffect } from 'react'; import useResizeObserver from 'use-resize-observer/polyfilled'; -import type { Dispatch } from 'redux'; -import { defaultRowRenderers } from '../../body/renderers'; -import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer'; -import { defaultHeaders, mockTimelineData } from '../../../../../common/mock'; +import { createMockStore, mockGlobalState, mockTimelineData } from '../../../../../common/mock'; import { TestProviders } from '../../../../../common/mock/test_providers'; import type { Props as EqlTabContentComponentProps } from '.'; -import { EqlTabContentComponent } from '.'; -import { TimelineId, TimelineTabs } from '../../../../../../common/types/timeline'; +import EqlTabContentComponent from '.'; +import { TimelineId } from '../../../../../../common/types/timeline'; import { useTimelineEvents } from '../../../../containers'; import { useTimelineEventsDetails } from '../../../../containers/details'; import { useSourcererDataView } from '../../../../../sourcerer/containers'; @@ -24,7 +22,15 @@ import { mockSourcererScope } from '../../../../../sourcerer/containers/mocks'; import { useIsExperimentalFeatureEnabled } from '../../../../../common/hooks/use_experimental_features'; import type { ExperimentalFeatures } from '../../../../../../common'; import { allowedExperimentalValues } from '../../../../../../common'; -import { render, screen } from '@testing-library/react'; +import { fireEvent, render, screen, waitFor } from '@testing-library/react'; +import * as notesApi from '../../../../../notes/api/api'; +import { timelineActions } from '../../../../store'; +import { DefaultCellRenderer } from '../../cell_rendering/default_cell_renderer'; +import { defaultRowRenderers } from '../../body/renderers'; +import { useDispatch } from 'react-redux'; +import { TimelineTabs } from '@kbn/securitysolution-data-table'; + +const SPECIAL_TEST_TIMEOUT = 30000; jest.mock('../../../../containers', () => ({ useTimelineEvents: jest.fn(), @@ -50,10 +56,43 @@ mockUseResizeObserver.mockImplementation(() => ({})); jest.mock('../../../../../common/lib/kibana'); +let useTimelineEventsMock = jest.fn(); + +const loadPageMock = jest.fn(); + +const mockState = { + ...structuredClone(mockGlobalState), +}; +mockState.timeline.timelineById[TimelineId.test].activeTab = TimelineTabs.eql; + +const TestComponent = (props: Partial<ComponentProps<typeof EqlTabContentComponent>>) => { + const testComponentDefaultProps: ComponentProps<typeof EqlTabContentComponent> = { + timelineId: TimelineId.test, + renderCellValue: DefaultCellRenderer, + rowRenderers: defaultRowRenderers, + }; + + const dispatch = useDispatch(); + + useEffect(() => { + // Unified field list can be a culprit for long load times, so we wait for the timeline to be interacted with to load + dispatch(timelineActions.showTimeline({ id: TimelineId.test, show: true })); + + // populating timeline so that it is not blank + dispatch( + timelineActions.updateEqlOptions({ + id: TimelineId.test, + field: 'query', + value: 'any where true', + }) + ); + }, [dispatch]); + + return <EqlTabContentComponent {...testComponentDefaultProps} {...props} />; +}; + describe('EQL Tab', () => { - let props = {} as EqlTabContentComponentProps; - const startDate = '2018-03-23T18:49:23.132Z'; - const endDate = '2018-03-24T03:33:52.253Z'; + const props = {} as EqlTabContentComponentProps; beforeAll(() => { // https://github.com/atlassian/react-beautiful-dnd/blob/4721a518356f72f1dac45b5fd4ee9d466aa2996b/docs/guides/setup-problem-detection-and-error-recovery.md#disable-logging @@ -65,7 +104,7 @@ describe('EQL Tab', () => { }); beforeEach(() => { - (useTimelineEvents as jest.Mock).mockReturnValue([ + useTimelineEventsMock = jest.fn(() => [ false, { events: mockTimelineData.slice(0, 1), @@ -75,6 +114,7 @@ describe('EQL Tab', () => { }, }, ]); + (useTimelineEvents as jest.Mock).mockImplementation(useTimelineEventsMock); (useTimelineEventsDetails as jest.Mock).mockReturnValue([false, {}]); (useSourcererDataView as jest.Mock).mockReturnValue(mockSourcererScope); @@ -85,30 +125,23 @@ describe('EQL Tab', () => { } ); - props = { - dispatch: {} as Dispatch, - activeTab: TimelineTabs.eql, - columns: defaultHeaders, - end: endDate, - eqlOptions: {}, - isLive: false, - itemsPerPage: 5, - itemsPerPageOptions: [5, 10, 20], - renderCellValue: DefaultCellRenderer, - rowRenderers: defaultRowRenderers, - start: startDate, - timelineId: TimelineId.test, - timerangeKind: 'absolute', - pinnedEventIds: {}, - eventIdToNoteIds: {}, - }; + HTMLElement.prototype.getBoundingClientRect = jest.fn(() => { + return { + width: 1000, + height: 1000, + x: 0, + y: 0, + } as DOMRect; + }); }); describe('rendering', () => { + const fetchNotesMock = jest.spyOn(notesApi, 'fetchNotesByDocumentIds'); test('should render the timeline table', async () => { + fetchNotesMock.mockImplementation(jest.fn()); render( - <TestProviders> - <EqlTabContentComponent {...props} /> + <TestProviders store={createMockStore(mockState)}> + <TestComponent /> </TestProviders> ); @@ -117,8 +150,8 @@ describe('EQL Tab', () => { test('it renders the timeline column headers', async () => { render( - <TestProviders> - <EqlTabContentComponent {...props} /> + <TestProviders store={createMockStore(mockState)}> + <TestComponent /> </TestProviders> ); @@ -138,12 +171,175 @@ describe('EQL Tab', () => { ]); render( - <TestProviders> - <EqlTabContentComponent {...props} /> + <TestProviders store={createMockStore(mockState)}> + <TestComponent /> </TestProviders> ); expect(await screen.findByText('No results found')).toBeVisible(); }); + + describe('pagination', () => { + beforeEach(() => { + // pagination tests need more than 1 record so here + // we return 5 records instead of just 1. + useTimelineEventsMock = jest.fn(() => [ + false, + { + events: structuredClone(mockTimelineData.slice(0, 5)), + pageInfo: { + activePage: 0, + totalPages: 5, + }, + refreshedAt: Date.now(), + /* + * `totalCount` could be any number w.r.t this test + * and actually means total hits on elastic search + * and not the fecthed number of records. + * + * This helps in testing `sampleSize` and `loadMore` + */ + totalCount: 50, + loadPage: loadPageMock, + }, + ]); + + (useTimelineEvents as jest.Mock).mockImplementation(useTimelineEventsMock); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it( + 'should load notes for current page only', + async () => { + const mockStateWithNoteInTimeline = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], + /* 1 record for each page */ + activeTab: TimelineTabs.eql, + itemsPerPage: 1, + itemsPerPageOptions: [1, 2, 3, 4, 5], + savedObjectId: 'timeline-1', // match timelineId in mocked notes data + pinnedEventIds: { '1': true }, + }, + }, + }, + }; + + render( + <TestProviders + store={createMockStore({ + ...structuredClone(mockStateWithNoteInTimeline), + })} + > + <TestComponent {...props} /> + </TestProviders> + ); + + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-previous')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-0')).toHaveAttribute('aria-current', 'true'); + expect(fetchNotesMock).toHaveBeenCalledWith(['1']); + + // Page : 2 + + fetchNotesMock.mockClear(); + expect(screen.getByTestId('pagination-button-1')).toBeVisible(); + + fireEvent.click(screen.getByTestId('pagination-button-1')); + + await waitFor(() => { + expect(screen.getByTestId('pagination-button-1')).toHaveAttribute( + 'aria-current', + 'true' + ); + + expect(fetchNotesMock).toHaveBeenNthCalledWith(1, [mockTimelineData[1]._id]); + }); + + // Page : 3 + + fetchNotesMock.mockClear(); + expect(screen.getByTestId('pagination-button-2')).toBeVisible(); + fireEvent.click(screen.getByTestId('pagination-button-2')); + + await waitFor(() => { + expect(screen.getByTestId('pagination-button-2')).toHaveAttribute( + 'aria-current', + 'true' + ); + + expect(fetchNotesMock).toHaveBeenNthCalledWith(1, [mockTimelineData[2]._id]); + }); + }, + SPECIAL_TEST_TIMEOUT + ); + + it( + 'should load notes for correct page size', + async () => { + const mockStateWithNoteInTimeline = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], + /* 1 record for each page */ + itemsPerPage: 1, + pageIndex: 0, + itemsPerPageOptions: [1, 2, 3, 4, 5], + savedObjectId: 'timeline-1', // match timelineId in mocked notes data + pinnedEventIds: { '1': true }, + }, + }, + }, + }; + + render( + <TestProviders + store={createMockStore({ + ...structuredClone(mockStateWithNoteInTimeline), + })} + > + <TestComponent {...props} /> + </TestProviders> + ); + + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-previous')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-0')).toHaveAttribute('aria-current', 'true'); + expect(screen.getByTestId('tablePaginationPopoverButton')).toHaveTextContent( + 'Rows per page: 1' + ); + fireEvent.click(screen.getByTestId('tablePaginationPopoverButton')); + + await waitFor(() => { + expect(screen.getByTestId('tablePagination-2-rows')).toBeVisible(); + }); + + fetchNotesMock.mockClear(); + fireEvent.click(screen.getByTestId('tablePagination-2-rows')); + + await waitFor(() => { + expect(fetchNotesMock).toHaveBeenNthCalledWith(1, [ + mockTimelineData[0]._id, + mockTimelineData[1]._id, + ]); + }); + }, + SPECIAL_TEST_TIMEOUT + ); + }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx index 22289d090ab3..0b2de48e8969 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/eql/index.tsx @@ -7,7 +7,7 @@ import { EuiFlexGroup } from '@elastic/eui'; import { isEmpty } from 'lodash/fp'; -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect } from 'react-redux'; import deepEqual from 'fast-deep-equal'; @@ -17,6 +17,7 @@ import type { EuiDataGridControlColumn } from '@elastic/eui'; import { DataLoadingState } from '@kbn/unified-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; +import { useFetchNotes } from '../../../../../notes/hooks/use_fetch_notes'; import { InputsModelId } from '../../../../../common/store/inputs/constants'; import { useKibana } from '../../../../../common/lib/kibana'; import { @@ -65,6 +66,13 @@ export const EqlTabContentComponent: React.FC<Props> = ({ pinnedEventIds, eventIdToNoteIds, }) => { + /* + * Needs to be maintained for each table in each tab independently + * and consequently it cannot be the part of common redux state + * of the timeline. + * + */ + const [pageIndex, setPageIndex] = useState(0); const { telemetry } = useKibana().services; const { query: eqlQuery = '', ...restEqlOption } = eqlOptions; const { portalNode: eqlEventsCountPortalNode } = useEqlEventsCountPortal(); @@ -97,24 +105,42 @@ export const EqlTabContentComponent: React.FC<Props> = ({ [end, isBlankTimeline, loadingSourcerer, start] ); - const [ - dataLoadingState, - { events, inspect, totalCount, pageInfo, loadPage, refreshedAt, refetch }, - ] = useTimelineEvents({ - dataViewId, - endDate: end, - eqlOptions: restEqlOption, - fields: timelineQueryFieldsFromColumns, - filterQuery: eqlQuery ?? '', - id: timelineId, - indexNames: selectedPatterns, - language: 'eql', - limit: sampleSize, - runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, - skip: !canQueryTimeline(), - startDate: start, - timerangeKind, - }); + const [dataLoadingState, { events, inspect, totalCount, loadPage, refreshedAt, refetch }] = + useTimelineEvents({ + dataViewId, + endDate: end, + eqlOptions: restEqlOption, + fields: timelineQueryFieldsFromColumns, + filterQuery: eqlQuery ?? '', + id: timelineId, + indexNames: selectedPatterns, + language: 'eql', + limit: sampleSize, + runtimeMappings: sourcererDataView.runtimeFieldMap as RunTimeMappings, + skip: !canQueryTimeline(), + startDate: start, + timerangeKind, + }); + + const { onLoad: loadNotesOnEventsLoad } = useFetchNotes(); + + useEffect(() => { + // This useEffect loads the notes only for the events on the current + // page. + const eventsOnCurrentPage = events.slice( + itemsPerPage * pageIndex, + itemsPerPage * (pageIndex + 1) + ); + + loadNotesOnEventsLoad(eventsOnCurrentPage); + }, [events, pageIndex, itemsPerPage, loadNotesOnEventsLoad]); + + /** + * + * Triggers on Datagrid page change + * + */ + const onUpdatePageIndex = useCallback((newPageIndex: number) => setPageIndex(newPageIndex), []); const { openFlyout } = useExpandableFlyoutApi(); const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( @@ -263,12 +289,12 @@ export const EqlTabContentComponent: React.FC<Props> = ({ refetch={refetch} dataLoadingState={dataLoadingState} totalCount={isBlankTimeline ? 0 : totalCount} - onChangePage={loadPage} + onFetchMoreRecords={loadPage} activeTab={activeTab} updatedAt={refreshedAt} isTextBasedQuery={false} - pageInfo={pageInfo} leadingControlColumns={leadingControlColumns as EuiDataGridControlColumn[]} + onUpdatePageIndex={onUpdatePageIndex} /> </FullWidthFlexGroup> </> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx index 0b2553d23ac5..8c0ecbeecfdc 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/pinned/index.tsx @@ -6,13 +6,14 @@ */ import { isEmpty } from 'lodash/fp'; -import React, { useMemo, useCallback, memo } from 'react'; +import React, { useMemo, useCallback, memo, useState, useEffect } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect } from 'react-redux'; import deepEqual from 'fast-deep-equal'; import type { EuiDataGridControlColumn } from '@elastic/eui'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; +import { useFetchNotes } from '../../../../../notes/hooks/use_fetch_notes'; import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey, @@ -68,6 +69,14 @@ export const PinnedTabContentComponent: React.FC<Props> = ({ sort, eventIdToNoteIds, }) => { + /* + * Needs to be maintained for each table in each tab independently + * and consequently it cannot be the part of common redux state + * of the timeline. + * + */ + const [pageIndex, setPageIndex] = useState(0); + const { telemetry } = useKibana().services; const { dataViewId, sourcererDataView, selectedPatterns } = useSourcererDataView( SourcererScopeName.timeline @@ -130,7 +139,7 @@ export const PinnedTabContentComponent: React.FC<Props> = ({ ); const { augmentedColumnHeaders } = useTimelineColumns(columns); - const [queryLoadingState, { events, totalCount, pageInfo, loadPage, refreshedAt, refetch }] = + const [queryLoadingState, { events, totalCount, loadPage, refreshedAt, refetch }] = useTimelineEvents({ endDate: '', id: `pinned-${timelineId}`, @@ -146,6 +155,26 @@ export const PinnedTabContentComponent: React.FC<Props> = ({ timerangeKind: undefined, }); + const { onLoad: loadNotesOnEventsLoad } = useFetchNotes(); + + useEffect(() => { + // This useEffect loads the notes only for the events on the current + // page. + const eventsOnCurrentPage = events.slice( + itemsPerPage * pageIndex, + itemsPerPage * (pageIndex + 1) + ); + + loadNotesOnEventsLoad(eventsOnCurrentPage); + }, [events, pageIndex, itemsPerPage, loadNotesOnEventsLoad]); + + /** + * + * Triggers on Datagrid page change + * + */ + const onUpdatePageIndex = useCallback((newPageIndex: number) => setPageIndex(newPageIndex), []); + const { openFlyout } = useExpandableFlyoutApi(); const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesDisabled' @@ -257,13 +286,13 @@ export const PinnedTabContentComponent: React.FC<Props> = ({ refetch={refetch} dataLoadingState={queryLoadingState} totalCount={totalCount} - onChangePage={loadPage} + onFetchMoreRecords={loadPage} activeTab={TimelineTabs.pinned} updatedAt={refreshedAt} isTextBasedQuery={false} - pageInfo={pageInfo} leadingControlColumns={leadingControlColumns as EuiDataGridControlColumn[]} trailingControlColumns={rowDetailColumn} + onUpdatePageIndex={onUpdatePageIndex} /> </> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx index f0a2c06bbffb..cfd8f86af9da 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.test.tsx @@ -41,6 +41,7 @@ import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import { createExpandableFlyoutApiMock } from '../../../../../common/mock/expandable_flyout'; import { OPEN_FLYOUT_BUTTON_TEST_ID } from '../../../../../notes/components/test_ids'; import { userEvent } from '@testing-library/user-event'; +import * as notesApi from '../../../../../notes/api/api'; jest.mock('../../../../../common/components/user_privileges'); @@ -154,7 +155,9 @@ const { storage: storageMock } = createSecuritySolutionStorageMock(); let useTimelineEventsMock = jest.fn(); describe('query tab with unified timeline', () => { + const fetchNotesMock = jest.spyOn(notesApi, 'fetchNotesByDocumentIds'); beforeAll(() => { + fetchNotesMock.mockImplementation(jest.fn()); jest.mocked(useExpandableFlyoutApi).mockImplementation(() => ({ ...createExpandableFlyoutApiMock(), openFlyout: mockOpenFlyout, @@ -176,6 +179,7 @@ describe('query tab with unified timeline', () => { afterEach(() => { jest.clearAllMocks(); storageMock.clear(); + fetchNotesMock.mockClear(); cleanup(); localStorage.clear(); }); @@ -424,6 +428,130 @@ describe('query tab with unified timeline', () => { }, SPECIAL_TEST_TIMEOUT ); + + it( + 'should load notes for current page only', + async () => { + const mockStateWithNoteInTimeline = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], + /* 1 record for each page */ + itemsPerPage: 1, + pageIndex: 0, + itemsPerPageOptions: [1, 2, 3, 4, 5], + savedObjectId: 'timeline-1', // match timelineId in mocked notes data + pinnedEventIds: { '1': true }, + }, + }, + }, + }; + + render( + <TestProviders + store={createMockStore({ + ...structuredClone(mockStateWithNoteInTimeline), + })} + > + <TestComponent /> + </TestProviders> + ); + + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-previous')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-0')).toHaveAttribute('aria-current', 'true'); + expect(fetchNotesMock).toHaveBeenCalledWith(['1']); + + // Page : 2 + + fetchNotesMock.mockClear(); + expect(screen.getByTestId('pagination-button-1')).toBeVisible(); + + fireEvent.click(screen.getByTestId('pagination-button-1')); + + await waitFor(() => { + expect(screen.getByTestId('pagination-button-1')).toHaveAttribute('aria-current', 'true'); + + expect(fetchNotesMock).toHaveBeenNthCalledWith(1, [mockTimelineData[1]._id]); + }); + + // Page : 3 + + fetchNotesMock.mockClear(); + expect(screen.getByTestId('pagination-button-2')).toBeVisible(); + fireEvent.click(screen.getByTestId('pagination-button-2')); + + await waitFor(() => { + expect(screen.getByTestId('pagination-button-2')).toHaveAttribute('aria-current', 'true'); + + expect(fetchNotesMock).toHaveBeenNthCalledWith(1, [mockTimelineData[2]._id]); + }); + }, + SPECIAL_TEST_TIMEOUT + ); + + it( + 'should load notes for correct page size', + async () => { + const mockStateWithNoteInTimeline = { + ...mockGlobalState, + timeline: { + ...mockGlobalState.timeline, + timelineById: { + [TimelineId.test]: { + ...mockGlobalState.timeline.timelineById[TimelineId.test], + /* 1 record for each page */ + itemsPerPage: 1, + pageIndex: 0, + itemsPerPageOptions: [1, 2, 3, 4, 5], + savedObjectId: 'timeline-1', // match timelineId in mocked notes data + pinnedEventIds: { '1': true }, + }, + }, + }, + }; + + render( + <TestProviders + store={createMockStore({ + ...structuredClone(mockStateWithNoteInTimeline), + })} + > + <TestComponent /> + </TestProviders> + ); + + expect(await screen.findByTestId('discoverDocTable')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-previous')).toBeVisible(); + + expect(screen.getByTestId('pagination-button-0')).toHaveAttribute('aria-current', 'true'); + expect(screen.getByTestId('tablePaginationPopoverButton')).toHaveTextContent( + 'Rows per page: 1' + ); + fireEvent.click(screen.getByTestId('tablePaginationPopoverButton')); + + await waitFor(() => { + expect(screen.getByTestId('tablePagination-2-rows')).toBeVisible(); + }); + + fetchNotesMock.mockClear(); + fireEvent.click(screen.getByTestId('tablePagination-2-rows')); + + await waitFor(() => { + expect(fetchNotesMock).toHaveBeenNthCalledWith(1, [ + mockTimelineData[0]._id, + mockTimelineData[1]._id, + ]); + }); + }, + SPECIAL_TEST_TIMEOUT + ); }); describe('columns', () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx index 967253a34a71..f614290fd6a5 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/tabs/query/index.tsx @@ -6,7 +6,7 @@ */ import { isEmpty } from 'lodash/fp'; -import React, { useMemo, useEffect, useCallback } from 'react'; +import React, { useMemo, useEffect, useCallback, useState } from 'react'; import type { ConnectedProps } from 'react-redux'; import { connect, useDispatch } from 'react-redux'; import deepEqual from 'fast-deep-equal'; @@ -15,6 +15,7 @@ import { getEsQueryConfig } from '@kbn/data-plugin/common'; import { DataLoadingState } from '@kbn/unified-data-table'; import { useExpandableFlyoutApi } from '@kbn/expandable-flyout'; import type { RunTimeMappings } from '@kbn/timelines-plugin/common/search_strategy'; +import { useFetchNotes } from '../../../../../notes/hooks/use_fetch_notes'; import { DocumentDetailsLeftPanelKey, DocumentDetailsRightPanelKey, @@ -92,6 +93,13 @@ export const QueryTabContentComponent: React.FC<Props> = ({ selectedPatterns, sourcererDataView, } = useSourcererDataView(SourcererScopeName.timeline); + /* + * `pageIndex` needs to be maintained for each table in each tab independently + * and consequently it cannot be the part of common redux state + * of the timeline. + * + */ + const [pageIndex, setPageIndex] = useState(0); const { uiSettings, telemetry, timelineDataService } = useKibana().services; const { @@ -167,7 +175,7 @@ export const QueryTabContentComponent: React.FC<Props> = ({ const [ dataLoadingState, - { events, inspect, totalCount, pageInfo, loadPage, refreshedAt, refetch }, + { events, inspect, totalCount, loadPage: loadNextEventBatch, refreshedAt, refetch }, ] = useTimelineEvents({ dataViewId, endDate: end, @@ -184,6 +192,26 @@ export const QueryTabContentComponent: React.FC<Props> = ({ timerangeKind, }); + const { onLoad: loadNotesOnEventsLoad } = useFetchNotes(); + + useEffect(() => { + // This useEffect loads the notes only for the events on the current + // page. + const eventsOnCurrentPage = events.slice( + itemsPerPage * pageIndex, + itemsPerPage * (pageIndex + 1) + ); + + loadNotesOnEventsLoad(eventsOnCurrentPage); + }, [events, pageIndex, itemsPerPage, loadNotesOnEventsLoad]); + + /** + * + * Triggers on Datagrid page change + * + */ + const onUpdatePageIndex = useCallback((newPageIndex: number) => setPageIndex(newPageIndex), []); + const { openFlyout } = useExpandableFlyoutApi(); const securitySolutionNotesDisabled = useIsExperimentalFeatureEnabled( 'securitySolutionNotesDisabled' @@ -355,11 +383,11 @@ export const QueryTabContentComponent: React.FC<Props> = ({ dataLoadingState={dataLoadingState} totalCount={isBlankTimeline ? 0 : totalCount} leadingControlColumns={leadingControlColumns as EuiDataGridControlColumn[]} - onChangePage={loadPage} + onFetchMoreRecords={loadNextEventBatch} activeTab={activeTab} updatedAt={refreshedAt} isTextBasedQuery={false} - pageInfo={pageInfo} + onUpdatePageIndex={onUpdatePageIndex} /> </> ); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx index 649817d5f8ef..3f24fc8df4aa 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.test.tsx @@ -72,7 +72,7 @@ const TestComponent = (props: TestComponentProps) => { refetch={refetchMock} dataLoadingState={DataLoadingState.loaded} totalCount={mockTimelineData.length} - onChangePage={onChangePageMock} + onFetchMoreRecords={onChangePageMock} updatedAt={Date.now()} onSetColumns={jest.fn()} onFilter={jest.fn()} diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx index fa5b83f23576..99e00547f1c3 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/data_table/index.tsx @@ -30,7 +30,7 @@ import type { TimelineItem } from '../../../../../../common/search_strategy'; import { useKibana } from '../../../../../common/lib/kibana'; import type { ColumnHeaderOptions, - OnChangePage, + OnFetchMoreRecords, RowRenderer, TimelineTabs, } from '../../../../../../common/types/timeline'; @@ -64,7 +64,7 @@ type CommonDataTableProps = { refetch: inputsModel.Refetch; onFieldEdited: () => void; totalCount: number; - onChangePage: OnChangePage; + onFetchMoreRecords: OnFetchMoreRecords; activeTab: TimelineTabs; dataLoadingState: DataLoadingState; updatedAt: number; @@ -79,6 +79,7 @@ type CommonDataTableProps = { | 'renderCustomGridBody' | 'trailingControlColumns' | 'isSortEnabled' + | 'onUpdatePageIndex' >; interface DataTableProps extends CommonDataTableProps { @@ -102,13 +103,14 @@ export const TimelineDataTableComponent: React.FC<DataTableProps> = memo( refetch, dataLoadingState, totalCount, - onChangePage, + onFetchMoreRecords, updatedAt, isTextBasedQuery = false, onSetColumns, onSort, onFilter, leadingControlColumns, + onUpdatePageIndex, }) { const dispatch = useDispatch(); @@ -235,9 +237,9 @@ export const TimelineDataTableComponent: React.FC<DataTableProps> = memo( ); const handleFetchMoreRecords = useCallback(() => { - onChangePage(fetchedPage + 1); + onFetchMoreRecords(fetchedPage + 1); setFechedPage(fetchedPage + 1); - }, [fetchedPage, onChangePage]); + }, [fetchedPage, onFetchMoreRecords]); const additionalControls = useMemo( () => <ToolbarAdditionalControls timelineId={timelineId} updatedAt={updatedAt} />, @@ -424,6 +426,7 @@ export const TimelineDataTableComponent: React.FC<DataTableProps> = memo( renderCustomGridBody={finalRenderCustomBodyCallback} trailingControlColumns={finalTrailControlColumns} externalControlColumns={leadingControlColumns} + onUpdatePageIndex={onUpdatePageIndex} /> </StyledTimelineUnifiedDataTable> </StatefulEventContext.Provider> diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx index c660893ba379..7d9bde02259a 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.test.tsx @@ -107,10 +107,11 @@ const TestComponent = ( events: localMockedTimelineData, refetch: jest.fn(), totalCount: localMockedTimelineData.length, - onChangePage: jest.fn(), + onFetchMoreRecords: jest.fn(), dataLoadingState: DataLoadingState.loaded, updatedAt: Date.now(), isTextBasedQuery: false, + onUpdatePageIndex: jest.fn(), }; const dispatch = useDispatch(); diff --git a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx index 112886f93ca3..d350b4b53080 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/timeline/unified_components/index.tsx @@ -12,7 +12,7 @@ import { useDispatch } from 'react-redux'; import { generateFilters } from '@kbn/data-plugin/public'; import type { DataView, DataViewField } from '@kbn/data-plugin/common'; import type { SortOrder } from '@kbn/saved-search-plugin/public'; -import type { DataLoadingState } from '@kbn/unified-data-table'; +import type { DataLoadingState, UnifiedDataTableProps } from '@kbn/unified-data-table'; import { useColumns } from '@kbn/unified-data-table'; import { popularizeField } from '@kbn/unified-data-table/src/utils/popularize_field'; import type { DropType } from '@kbn/dom-drag-drop'; @@ -33,7 +33,7 @@ import type { TimelineItem } from '../../../../../common/search_strategy'; import { useKibana } from '../../../../common/lib/kibana'; import type { ColumnHeaderOptions, - OnChangePage, + OnFetchMoreRecords, RowRenderer, SortColumnTimeline, TimelineTabs, @@ -106,7 +106,7 @@ interface Props { events: TimelineItem[]; refetch: inputsModel.Refetch; totalCount: number; - onChangePage: OnChangePage; + onFetchMoreRecords: OnFetchMoreRecords; activeTab: TimelineTabs; dataLoadingState: DataLoadingState; updatedAt: number; @@ -114,6 +114,7 @@ interface Props { dataView: DataView; trailingControlColumns?: EuiDataGridProps['trailingControlColumns']; leadingControlColumns?: EuiDataGridProps['leadingControlColumns']; + onUpdatePageIndex?: UnifiedDataTableProps['onUpdatePageIndex']; } const UnifiedTimelineComponent: React.FC<Props> = ({ @@ -129,12 +130,13 @@ const UnifiedTimelineComponent: React.FC<Props> = ({ refetch, dataLoadingState, totalCount, - onChangePage, + onFetchMoreRecords, updatedAt, isTextBasedQuery, dataView, trailingControlColumns, leadingControlColumns, + onUpdatePageIndex, }) => { const dispatch = useDispatch(); const unifiedFieldListContainerRef = useRef<UnifiedFieldListSidebarContainerApi>(null); @@ -435,13 +437,14 @@ const UnifiedTimelineComponent: React.FC<Props> = ({ onFieldEdited={onFieldEdited} dataLoadingState={dataLoadingState} totalCount={totalCount} - onChangePage={onChangePage} + onFetchMoreRecords={onFetchMoreRecords} activeTab={activeTab} updatedAt={updatedAt} isTextBasedQuery={isTextBasedQuery} onFilter={onAddFilter as DocViewFilterFn} trailingControlColumns={trailingControlColumns} leadingControlColumns={leadingControlColumns} + onUpdatePageIndex={onUpdatePageIndex} /> </EventDetailsWidthProvider> </DropOverlayWrapper> diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx index f00ca0551a9a..822740f3b997 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.test.tsx @@ -30,7 +30,7 @@ jest.mock('../../notes/hooks/use_fetch_notes'); const onLoadMock = jest.fn(); const useFetchNotesMock = useFetchNotes as jest.Mock; -const mockEvents = mockTimelineData.filter((i, index) => index <= 11); +const mockEvents = mockTimelineData.slice(0, 10); const mockSearch = jest.fn(); @@ -70,13 +70,13 @@ jest.mock('../../common/lib/kibana', () => ({ }, edges: mockEvents.map((item) => ({ node: item })), pageInfo: { - activePage: 0, + activePage: args.pagination.activePage, totalPages: 10, }, rawResponse: {}, totalCount: mockTimelineData.length, }); - }, 0); + }, 50); return { unsubscribe: jest.fn() }; }), }; @@ -124,12 +124,12 @@ describe('useTimelineEvents', () => { const endDate: string = '3000-01-01T00:00:00.000Z'; const props: UseTimelineEventsProps = { dataViewId: 'data-view-id', - endDate: '', + endDate, id: TimelineId.active, indexNames: ['filebeat-*'], fields: ['@timestamp', 'event.kind'], filterQuery: '', - startDate: '', + startDate, limit: 25, runtimeMappings: {}, sort: initSortDefault, @@ -166,10 +166,9 @@ describe('useTimelineEvents', () => { >((args) => useTimelineEvents(args), { initialProps: props, }); - // useEffect on params request await waitFor(() => new Promise((resolve) => resolve(null))); - rerender({ ...props, startDate, endDate }); + rerender({ ...props, startDate: '', endDate: '' }); // useEffect on params request await waitFor(() => { expect(mockSearch).toHaveBeenCalledTimes(2); @@ -197,12 +196,6 @@ describe('useTimelineEvents', () => { initialProps: props, }); - // useEffect on params request - await waitFor(() => new Promise((resolve) => resolve(null))); - rerender({ ...props, startDate, endDate }); - // useEffect on params request - await waitFor(() => new Promise((resolve) => resolve(null))); - mockUseRouteSpy.mockReturnValue([ { pageName: SecurityPageName.timelines, @@ -213,7 +206,13 @@ describe('useTimelineEvents', () => { }, ]); - expect(mockSearch).toHaveBeenCalledTimes(2); + rerender({ ...props, startDate, endDate }); + + await waitFor(() => { + expect(result.current[0]).toEqual(DataLoadingState.loaded); + }); + + expect(mockSearch).toHaveBeenCalledTimes(1); expect(result.current).toEqual([ DataLoadingState.loaded, @@ -283,7 +282,7 @@ describe('useTimelineEvents', () => { // useEffect on params request await waitFor(() => new Promise((resolve) => resolve(null))); - expect(mockSearch).toHaveBeenCalledTimes(2); + expect(mockSearch).toHaveBeenCalledTimes(1); mockSearch.mockClear(); rerender({ @@ -307,7 +306,7 @@ describe('useTimelineEvents', () => { // useEffect on params request await waitFor(() => new Promise((resolve) => resolve(null))); - expect(mockSearch).toHaveBeenCalledTimes(2); + expect(mockSearch).toHaveBeenCalledTimes(1); mockSearch.mockClear(); rerender({ ...props, startDate, endDate, fields: ['@timestamp'] }); @@ -325,7 +324,7 @@ describe('useTimelineEvents', () => { // useEffect on params request await waitFor(() => new Promise((resolve) => resolve(null))); - expect(mockSearch).toHaveBeenCalledTimes(2); + expect(mockSearch).toHaveBeenCalledTimes(1); mockSearch.mockClear(); // remove `event.kind` from default fields @@ -343,16 +342,22 @@ describe('useTimelineEvents', () => { await waitFor(() => expect(mockSearch).toHaveBeenCalledTimes(0)); }); - describe('Fetch Notes', () => { - test('should call onLoad for notes when events are fetched', async () => { - renderHook((args) => useTimelineEvents(args), { - initialProps: props, - }); + test('should return the combined list of events for all the pages when multiple pages are queried', async () => { + const { result } = renderHook((args) => useTimelineEvents(args), { + initialProps: { ...props }, + }); + await waitFor(() => { + expect(result.current[1].events).toHaveLength(10); + }); - await waitFor(() => { - expect(mockSearch).toHaveBeenCalledTimes(1); - expect(onLoadMock).toHaveBeenNthCalledWith(1, expect.objectContaining(mockEvents)); - }); + result.current[1].loadPage(1); + + await waitFor(() => { + expect(result.current[0]).toEqual(DataLoadingState.loadingMore); + }); + + await waitFor(() => { + expect(result.current[1].events).toHaveLength(20); }); }); }); diff --git a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx index 0301f0123c30..baaed281c739 100644 --- a/x-pack/plugins/security_solution/public/timelines/containers/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/containers/index.tsx @@ -7,7 +7,7 @@ import deepEqual from 'fast-deep-equal'; import { isEmpty, noop } from 'lodash/fp'; -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { Subscription } from 'rxjs'; @@ -46,12 +46,21 @@ import type { } from '../../../common/search_strategy/timeline/events/eql'; import { useTrackHttpRequest } from '../../common/lib/apm/use_track_http_request'; import { APP_UI_ID } from '../../../common/constants'; -import { useFetchNotes } from '../../notes/hooks/use_fetch_notes'; export interface TimelineArgs { events: TimelineItem[]; id: string; inspect: InspectResponse; + + /** + * `loadPage` loads the next page/batch of records. + * This is different from the data grid pages. Data grid pagination is only + * client side and changing data grid pages does not impact this function. + * + * When user manually requests next batch of records, then a next batch is fetched + * irrespective of where user is in Data grid pagination. + * + */ loadPage: LoadPage; pageInfo: Pick<PaginationInputPaginated, 'activePage' | 'querySize'>; refetch: inputsModel.Refetch; @@ -174,6 +183,15 @@ export const useTimelineEventsHandler = ({ } }, [dispatch, id]); + /** + * `wrappedLoadPage` loads the next page/batch of records. + * This is different from the data grid pages. Data grid pagination is only + * client side and changing data grid pages does not impact this function. + * + * When user manually requests next batch of records, then a next batch is fetched + * irrespective of where user is in Data grid pagination. + * + */ const wrappedLoadPage = useCallback( (newActivePage: number) => { clearSignalsState(); @@ -186,6 +204,12 @@ export const useTimelineEventsHandler = ({ [clearSignalsState, id] ); + useEffect(() => { + return () => { + searchSubscription$.current?.unsubscribe(); + }; + }, []); + const refetchGrid = useCallback(() => { if (refetch.current != null) { refetch.current(); @@ -240,10 +264,12 @@ export const useTimelineEventsHandler = ({ next: (response) => { if (!isRunningResponse(response)) { endTracking('success'); + setLoading(DataLoadingState.loaded); setTimelineResponse((prevResponse) => { const newTimelineResponse = { ...prevResponse, + /**/ events: getTimelineEvents(response.edges), inspect: getInspectResponse(response, prevResponse.inspect), pageInfo: response.pageInfo, @@ -269,6 +295,7 @@ export const useTimelineEventsHandler = ({ }, error: (msg) => { endTracking(abortCtrl.current.signal.aborted ? 'aborted' : 'error'); + setLoading(DataLoadingState.loaded); data.search.showError(msg); searchSubscription$.current.unsubscribe(); @@ -483,8 +510,8 @@ export const useTimelineEvents = ({ sort = initSortDefault, skip = false, timerangeKind, - fetchNotes = true, }: UseTimelineEventsProps): [DataLoadingState, TimelineArgs] => { + const [eventsPerPage, setEventsPerPage] = useState<TimelineItem[][]>([[]]); const [dataLoadingState, timelineResponse, timelineSearchHandler] = useTimelineEventsHandler({ dataViewId, endDate, @@ -501,19 +528,35 @@ export const useTimelineEvents = ({ skip, timerangeKind, }); - const { onLoad } = useFetchNotes(); - const onTimelineSearchComplete: OnNextResponseHandler = useCallback( - (response) => { - if (fetchNotes) onLoad(response.events); - }, - [fetchNotes, onLoad] - ); + useEffect(() => { + /* + * `timelineSearchHandler` only returns the events for the current page. + * This effect is responsible for storing the events for each page so that + * the combined list of events can be supplied to DataGrid. + * + * */ + setEventsPerPage((prev) => { + const result = [...prev]; + result[timelineResponse.pageInfo.activePage] = timelineResponse.events; + return result; + }); + }, [timelineResponse.events, timelineResponse.pageInfo.activePage]); useEffect(() => { if (!timelineSearchHandler) return; - timelineSearchHandler(onTimelineSearchComplete); - }, [timelineSearchHandler, onTimelineSearchComplete]); + timelineSearchHandler(); + }, [timelineSearchHandler]); + + const combinedEvents = useMemo(() => eventsPerPage.flat(), [eventsPerPage]); + + const combinedResponse = useMemo( + () => ({ + ...timelineResponse, + events: combinedEvents, + }), + [timelineResponse, combinedEvents] + ); - return [dataLoadingState, timelineResponse]; + return [dataLoadingState, combinedResponse]; }; diff --git a/x-pack/plugins/security_solution/public/types.ts b/x-pack/plugins/security_solution/public/types.ts index 9829fe2ad0c2..2380c5a7cb08 100644 --- a/x-pack/plugins/security_solution/public/types.ts +++ b/x-pack/plugins/security_solution/public/types.ts @@ -61,6 +61,7 @@ import type { PluginStartContract } from '@kbn/alerting-plugin/public/plugin'; import type { MapsStartApi } from '@kbn/maps-plugin/public'; import type { IntegrationAssistantPluginStart } from '@kbn/integration-assistant-plugin/public'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { DiscoverSharedPublicStart } from '@kbn/discover-shared-plugin/public'; import type { ResolverPluginSetup } from './resolver/types'; import type { Inspect } from '../common/search_strategy'; import type { Detections } from './detections'; @@ -94,6 +95,7 @@ import type { ConfigSettings } from '../common/config_settings'; import type { OnboardingService } from './onboarding/service'; import type { SolutionNavigation } from './app/solution_navigation/solution_navigation'; import type { TelemetryServiceStart } from './common/lib/telemetry'; +import type { SiemMigrationsService } from './siem_migrations/service'; export interface SetupPlugins { cloud?: CloudSetup; @@ -106,6 +108,7 @@ export interface SetupPlugins { ml?: MlPluginSetup; cases?: CasesPublicSetup; data: DataPublicPluginSetup; + discoverShared: DiscoverSharedPublicStart; } /** @@ -137,7 +140,7 @@ export interface StartPlugins { uiActions: UiActionsStart; maps: MapsStartApi; ml?: MlPluginStart; - spaces?: SpacesPluginStart; + spaces: SpacesPluginStart; dataViewFieldEditor: IndexPatternFieldEditorStart; osquery: OsqueryPluginStart; security: SecurityPluginStart; @@ -193,6 +196,7 @@ export type StartServices = CoreStart & customDataService: DataPublicPluginStart; topValuesPopover: TopValuesPopoverService; timelineDataService: DataPublicPluginStart; + siemMigrations: SiemMigrationsService; }; export type StartRenderServices = Pick< diff --git a/x-pack/plugins/security_solution/scripts/siem_migration/draw_graphs.js b/x-pack/plugins/security_solution/scripts/siem_migration/draw_graphs.js new file mode 100644 index 000000000000..010b6c15f323 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/siem_migration/draw_graphs.js @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +require('../../../../../src/setup_node_env'); +require('./draw_graphs_script').draw(); diff --git a/x-pack/plugins/security_solution/scripts/siem_migration/draw_graphs_script.ts b/x-pack/plugins/security_solution/scripts/siem_migration/draw_graphs_script.ts new file mode 100644 index 000000000000..4cb2b5c74047 --- /dev/null +++ b/x-pack/plugins/security_solution/scripts/siem_migration/draw_graphs_script.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { InferenceClient } from '@kbn/inference-plugin/server'; +import type { + ActionsClientChatOpenAI, + ActionsClientSimpleChatModel, +} from '@kbn/langchain/server/language_models'; +import type { Logger } from '@kbn/logging'; +import { ToolingLog } from '@kbn/tooling-log'; +import { FakeLLM } from '@langchain/core/utils/testing'; +import fs from 'fs/promises'; +import path from 'path'; +import { getRuleMigrationAgent } from '../../server/lib/siem_migrations/rules/task/agent'; +import type { IntegrationRetriever } from '../../server/lib/siem_migrations/rules/task/util/integration_retriever'; +import type { PrebuiltRulesMapByName } from '../../server/lib/siem_migrations/rules/task/util/prebuilt_rules'; +import type { RuleResourceRetriever } from '../../server/lib/siem_migrations/rules/task/util/rule_resource_retriever'; + +interface Drawable { + drawMermaidPng: () => Promise<Blob>; +} + +const mockLlm = new FakeLLM({ + response: JSON.stringify({}, null, 2), +}) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; + +const inferenceClient = {} as InferenceClient; +const connectorId = 'draw_graphs'; +const prebuiltRulesMap = {} as PrebuiltRulesMapByName; +const resourceRetriever = {} as RuleResourceRetriever; +const integrationRetriever = {} as IntegrationRetriever; + +const createLlmInstance = () => { + return mockLlm; +}; + +async function getAgentGraph(logger: Logger): Promise<Drawable> { + const model = createLlmInstance(); + const graph = getRuleMigrationAgent({ + model, + inferenceClient, + prebuiltRulesMap, + resourceRetriever, + integrationRetriever, + connectorId, + logger, + }); + return graph.getGraphAsync({ xray: true }); +} + +export const drawGraph = async ({ + getGraphAsync, + outputFilename, +}: { + getGraphAsync: (logger: Logger) => Promise<Drawable>; + outputFilename: string; +}) => { + const logger = new ToolingLog({ + level: 'info', + writeTo: process.stdout, + }) as unknown as Logger; + logger.info('Compiling graph'); + const outputPath = path.join(__dirname, outputFilename); + const graph = await getGraphAsync(logger); + const output = await graph.drawMermaidPng(); + const buffer = Buffer.from(await output.arrayBuffer()); + logger.info(`Writing graph to ${outputPath}`); + await fs.writeFile(outputPath, buffer); +}; + +export const draw = async () => { + await drawGraph({ + getGraphAsync: getAgentGraph, + outputFilename: '../../docs/siem_migration/img/agent_graph.png', + }); +}; diff --git a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts index 1afa24ebbd52..bdffed6c1269 100644 --- a/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts +++ b/x-pack/plugins/security_solution/server/endpoint/endpoint_app_context_services.ts @@ -21,7 +21,7 @@ import type { FleetStartContract, MessageSigningServiceInterface, } from '@kbn/fleet-plugin/server'; -import type { PluginStartContract as AlertsPluginStartContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { CloudSetup } from '@kbn/cloud-plugin/server'; import type { FleetActionsClientInterface } from '@kbn/fleet-plugin/server/services/actions/types'; import type { PluginStartContract as ActionsPluginStartContract } from '@kbn/actions-plugin/server'; @@ -73,7 +73,7 @@ export interface EndpointAppContextServiceStartContract { fleetStartServices: FleetStartContract; manifestManager: ManifestManager; security: SecurityServiceStart; - alerting: AlertsPluginStartContract; + alerting: AlertingServerStart; config: ConfigType; registerListsServerExtension?: ListsServerExtensionRegistrar; licenseService: LicenseService; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts index dff47cf86ab6..1bd7c2eece1d 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/agent/clients/crowdstrike/crowdstrike_agent_status_client.ts @@ -132,7 +132,7 @@ export class CrowdstrikeAgentStatusClient extends AgentStatusClient { const agentStatuses = await this.getAgentStatusFromConnectorAction(agentIds); return agentIds.reduce<AgentStatusRecords>((acc, agentId) => { - const { device, crowdstrike } = mostRecentAgentInfosByAgentId[agentId]; + const { device, crowdstrike } = mostRecentAgentInfosByAgentId[agentId] || {}; const agentStatus = agentStatuses[agentId]; const pendingActions = allPendingActions.find( diff --git a/x-pack/plugins/security_solution/server/endpoint/services/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/index.ts index 242639818566..53c49d315ffa 100644 --- a/x-pack/plugins/security_solution/server/endpoint/services/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/services/index.ts @@ -9,4 +9,5 @@ export * from './artifacts'; export * from './actions'; export * from './agent'; export * from './artifacts_exception_list'; +export * from './workflow_insights'; export type { FeatureKeys } from './feature_usage'; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/constants.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/constants.ts new file mode 100644 index 000000000000..f8b97932289f --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/constants.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const DATA_STREAM_PREFIX = '.edr-workflow-insights'; +export const COMPONENT_TEMPLATE_NAME = `${DATA_STREAM_PREFIX}-component-template`; +export const INDEX_TEMPLATE_NAME = `${DATA_STREAM_PREFIX}-index-template`; +export const INGEST_PIPELINE_NAME = `${DATA_STREAM_PREFIX}-ingest-pipeline`; +export const DATA_STREAM_NAME = `${DATA_STREAM_PREFIX}-default`; + +export const TOTAL_FIELDS_LIMIT = 2000; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/errors.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/errors.ts new file mode 100644 index 000000000000..fa2cba3a6cd7 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/errors.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EndpointError } from '../../../../common/endpoint/errors'; + +export class SecurityWorkflowInsightsFailedInitialized extends EndpointError { + constructor(msg: string) { + super(`security workflow insights service failed to initialize with error: ${msg}`); + } +} diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/field_map_configurations.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/field_map_configurations.ts new file mode 100644 index 000000000000..32cc845ab00d --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/field_map_configurations.ts @@ -0,0 +1,183 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { FieldMap } from '@kbn/data-stream-adapter'; + +export const securityWorkflowInsightsFieldMap: FieldMap = { + '@timestamp': { + type: 'date', + array: false, + required: true, + }, + message: { + type: 'text', + array: false, + required: true, + }, + // endpoint or other part of security + category: { + type: 'keyword', + array: false, + required: true, + }, + // incompatible_virus, noisy_process_tree, etc + type: { + type: 'keyword', + array: false, + required: true, + }, + // the creator of the insight + source: { + type: 'nested', + array: false, + required: true, + }, + // kibana-insight-task, llm-request-id, etc + 'source.id': { + type: 'keyword', + array: false, + required: true, + }, + // endpoint, kibana, llm, etc + 'source.type': { + type: 'keyword', + array: false, + required: true, + }, + // starting timestamp of the source data used to generate the insight + 'source.data_range_start': { + type: 'date', + array: false, + required: true, + }, + // ending timestamp of the source data used to generate the insight + 'source.data_range_end': { + type: 'date', + array: false, + required: true, + }, + // the target that this insight is created for + target: { + type: 'nested', + array: false, + required: true, + }, + // endpoint, policy, etc + 'target.id': { + type: 'keyword', + array: true, + required: true, + }, + // endpoint ids, policy ids, etc + 'target.type': { + type: 'keyword', + array: false, + required: true, + }, + // latest action taken on the insight + action: { + type: 'nested', + array: false, + required: true, + }, + // refreshed, remediated, suppressed, dismissed + 'action.type': { + type: 'keyword', + array: false, + required: true, + }, + 'action.timestamp': { + type: 'date', + array: false, + required: true, + }, + // unique key for this insight, used for deduplicating insights. + // ie. crowdstrike or windows_defender + value: { + type: 'keyword', + array: false, + required: true, + }, + // suggested remediation for insight + remediation: { + type: 'object', + array: false, + required: true, + }, + // if remediation includes exception list items + 'remediation.exception_list_items': { + type: 'object', + array: true, + required: false, + }, + 'remediation.exception_list_items.list_id': { + type: 'keyword', + array: false, + required: true, + }, + 'remediation.exception_list_items.name': { + type: 'text', + array: false, + required: true, + }, + 'remediation.exception_list_items.description': { + type: 'text', + array: false, + required: false, + }, + 'remediation.exception_list_items.entries': { + type: 'object', + array: true, + required: true, + }, + 'remediation.exception_list_items.entries.field': { + type: 'keyword', + array: false, + required: true, + }, + 'remediation.exception_list_items.entries.operator': { + type: 'keyword', + array: false, + required: true, + }, + 'remediation.exception_list_items.entries.type': { + type: 'keyword', + array: false, + required: true, + }, + 'remediation.exception_list_items.entries.value': { + type: 'text', + array: false, + required: true, + }, + 'remediation.exception_list_items.tags': { + type: 'keyword', + array: true, + required: true, + }, + 'remediation.exception_list_items.os_types': { + type: 'keyword', + array: true, + required: true, + }, + metadata: { + type: 'object', + array: false, + required: true, + }, + // optional KV for notes + 'metadata.notes': { + type: 'object', + array: false, + required: false, + }, + // optional i8n variables + 'metadata.message_variables': { + type: 'text', + array: true, + required: false, + }, +} as const; diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/helpers.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/helpers.test.ts new file mode 100644 index 000000000000..119c1848f6a1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/helpers.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ElasticsearchClient } from '@kbn/core/server'; + +import { DataStreamSpacesAdapter } from '@kbn/data-stream-adapter'; +import { DefendInsightType } from '@kbn/elastic-assistant-common'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { kibanaPackageJson } from '@kbn/repo-info'; + +import type { SearchParams } from '../../../../common/endpoint/types/workflow_insights'; + +import { buildEsQueryParams, createDatastream, createPipeline } from './helpers'; +import { + DATA_STREAM_PREFIX, + COMPONENT_TEMPLATE_NAME, + INDEX_TEMPLATE_NAME, + INGEST_PIPELINE_NAME, + TOTAL_FIELDS_LIMIT, +} from './constants'; +import { securityWorkflowInsightsFieldMap } from './field_map_configurations'; +import { + ActionType, + Category, + SourceType, + TargetType, +} from '../../../../common/endpoint/types/workflow_insights'; + +jest.mock('@kbn/data-stream-adapter', () => ({ + DataStreamSpacesAdapter: jest.fn().mockImplementation(() => ({ + setComponentTemplate: jest.fn(), + setIndexTemplate: jest.fn(), + })), +})); + +describe('helpers', () => { + describe('createDatastream', () => { + it('should create a DataStreamSpacesAdapter with the correct configuration', () => { + const kibanaVersion = kibanaPackageJson.version; + const ds = createDatastream(kibanaVersion); + + expect(DataStreamSpacesAdapter).toHaveBeenCalledTimes(1); + expect(DataStreamSpacesAdapter).toHaveBeenCalledWith(DATA_STREAM_PREFIX, { + kibanaVersion, + totalFieldsLimit: TOTAL_FIELDS_LIMIT, + }); + expect(ds.setComponentTemplate).toHaveBeenCalledTimes(1); + expect(ds.setComponentTemplate).toHaveBeenCalledWith({ + name: COMPONENT_TEMPLATE_NAME, + fieldMap: securityWorkflowInsightsFieldMap, + }); + expect(ds.setIndexTemplate).toHaveBeenCalledTimes(1); + expect(ds.setIndexTemplate).toHaveBeenCalledWith({ + name: INDEX_TEMPLATE_NAME, + componentTemplateRefs: [COMPONENT_TEMPLATE_NAME], + template: { + settings: { + default_pipeline: INGEST_PIPELINE_NAME, + }, + }, + hidden: true, + }); + }); + }); + + describe('createPipeline', () => { + let esClient: ElasticsearchClient; + + beforeEach(() => { + esClient = elasticsearchServiceMock.createElasticsearchClient(); + }); + + it('should create an ingest pipeline with the correct configuration', async () => { + await createPipeline(esClient); + + expect(esClient.ingest.putPipeline).toHaveBeenCalledTimes(1); + expect(esClient.ingest.putPipeline).toHaveBeenCalledWith({ + id: INGEST_PIPELINE_NAME, + processors: [], + _meta: { + managed: true, + }, + }); + }); + }); + + describe('buildEsQueryParams', () => { + it('should build es query correct', () => { + const searchParams: SearchParams = { + size: 50, + from: 50, + ids: ['id1', 'id2'], + categories: [Category.Endpoint], + types: [DefendInsightType.Enum.incompatible_antivirus], + sourceTypes: [SourceType.LlmConnector], + sourceIds: ['source-id1', 'source-id2'], + targetTypes: [TargetType.Endpoint], + targetIds: ['target-id1', 'target-id2'], + actionTypes: [ActionType.Refreshed, ActionType.Remediated], + }; + const result = buildEsQueryParams(searchParams); + expect(result).toEqual([ + { + terms: { + _id: ['id1', 'id2'], + }, + }, + { + terms: { + categories: ['endpoint'], + }, + }, + { + terms: { + types: ['incompatible_antivirus'], + }, + }, + { + terms: { + 'source.type': ['llm-connector'], + }, + }, + { + terms: { + 'source.id': ['source-id1', 'source-id2'], + }, + }, + { + terms: { + 'target.type': ['endpoint'], + }, + }, + { + terms: { + 'target.id': ['target-id1', 'target-id2'], + }, + }, + { + terms: { + 'action.type': ['refreshed', 'remediated'], + }, + }, + ]); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/helpers.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/helpers.ts new file mode 100644 index 000000000000..f0057faed6aa --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/helpers.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { get as _get } from 'lodash'; + +import type { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types'; +import type { ElasticsearchClient } from '@kbn/core/server'; + +import { DataStreamSpacesAdapter } from '@kbn/data-stream-adapter'; + +import type { SearchParams } from '../../../../common/endpoint/types/workflow_insights'; + +import { + COMPONENT_TEMPLATE_NAME, + DATA_STREAM_PREFIX, + INDEX_TEMPLATE_NAME, + INGEST_PIPELINE_NAME, + TOTAL_FIELDS_LIMIT, +} from './constants'; +import { securityWorkflowInsightsFieldMap } from './field_map_configurations'; + +export function createDatastream(kibanaVersion: string): DataStreamSpacesAdapter { + const ds = new DataStreamSpacesAdapter(DATA_STREAM_PREFIX, { + kibanaVersion, + totalFieldsLimit: TOTAL_FIELDS_LIMIT, + }); + ds.setComponentTemplate({ + name: COMPONENT_TEMPLATE_NAME, + fieldMap: securityWorkflowInsightsFieldMap, + }); + ds.setIndexTemplate({ + name: INDEX_TEMPLATE_NAME, + componentTemplateRefs: [COMPONENT_TEMPLATE_NAME], + template: { + settings: { + default_pipeline: INGEST_PIPELINE_NAME, + }, + }, + hidden: true, + }); + return ds; +} + +export async function createPipeline(esClient: ElasticsearchClient): Promise<boolean> { + const response = await esClient.ingest.putPipeline({ + id: INGEST_PIPELINE_NAME, + processors: [ + // requires @elastic/elasticsearch 8.16.0 + // { + // fingerprint: { + // fields: ['type', 'category', 'value', 'target.type', 'target.id'], + // target_field: '_id', + // method: 'SHA-256', + // if: 'ctx._id == null', + // }, + // }, + ], + _meta: { + managed: true, + }, + }); + return response.acknowledged; +} + +const validKeys = new Set([ + 'ids', + 'categories', + 'types', + 'sourceTypes', + 'sourceIds', + 'targetTypes', + 'targetIds', + 'actionTypes', +]); +const paramFieldMap = { + ids: '_id', + sourceTypes: 'source.type', + sourceIds: 'source.id', + targetTypes: 'target.type', + targetIds: 'target.id', + actionTypes: 'action.type', +}; +export function buildEsQueryParams(searchParams: SearchParams): QueryDslQueryContainer[] { + return Object.entries(searchParams).reduce((acc: object[], [k, v]) => { + if (!validKeys.has(k)) { + return acc; + } + + const paramKey = _get(paramFieldMap, k, k); + const next = { terms: { [paramKey]: v } }; + + return [...acc, next]; + }, []); +} diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/index.test.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/index.test.ts new file mode 100644 index 000000000000..792a7a9ecd94 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/index.test.ts @@ -0,0 +1,322 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { merge } from 'lodash'; +import moment from 'moment'; +import { ReplaySubject } from 'rxjs'; + +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; + +import { DataStreamSpacesAdapter } from '@kbn/data-stream-adapter'; +import { DefendInsightType } from '@kbn/elastic-assistant-common'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { kibanaPackageJson } from '@kbn/repo-info'; +import { loggerMock } from '@kbn/logging-mocks'; + +import type { + SearchParams, + SecurityWorkflowInsight, +} from '../../../../common/endpoint/types/workflow_insights'; + +import { + Category, + SourceType, + TargetType, + ActionType, +} from '../../../../common/endpoint/types/workflow_insights'; +import { createDatastream, createPipeline } from './helpers'; +import { securityWorkflowInsightsService } from '.'; +import { DATA_STREAM_NAME } from './constants'; + +jest.mock('./helpers', () => { + const original = jest.requireActual('./helpers'); + return { + ...original, + createDatastream: jest.fn(), + createPipeline: jest.fn(), + }; +}); + +function getDefaultInsight(overrides?: Partial<SecurityWorkflowInsight>): SecurityWorkflowInsight { + const defaultInsight = { + '@timestamp': moment(), + message: 'This is a test message', + category: Category.Endpoint, + type: DefendInsightType.Enum.incompatible_antivirus, + source: { + type: SourceType.LlmConnector, + id: 'openai-connector-id', + data_range_start: moment(), + data_range_end: moment(), + }, + target: { + type: TargetType.Endpoint, + ids: ['endpoint-1', 'endpoint-2'], + }, + action: { + type: ActionType.Refreshed, + timestamp: moment(), + }, + value: 'unique-key', + remediation: { + exception_list_items: [ + { + list_id: 'example-list-id', + name: 'Example List Name', + description: 'Example description', + entries: [ + { + field: 'example-field', + operator: 'included', + type: 'match', + value: 'example-value', + }, + ], + tags: ['example-tag'], + os_types: ['windows', 'linux'], + }, + ], + }, + metadata: { + notes: { + key1: 'value1', + key2: 'value2', + }, + message_variables: ['variable1', 'variable2'], + }, + }; + return merge(defaultInsight, overrides); +} + +describe('SecurityWorkflowInsightsService', () => { + let logger: Logger; + let esClient: ElasticsearchClient; + + beforeEach(() => { + logger = loggerMock.create(); + esClient = elasticsearchServiceMock.createElasticsearchClient(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('setup', () => { + it('should set up the data stream', () => { + const createDatastreamMock = createDatastream as jest.Mock; + createDatastreamMock.mockReturnValueOnce( + new DataStreamSpacesAdapter(DATA_STREAM_NAME, { + kibanaVersion: kibanaPackageJson.version, + }) + ); + + securityWorkflowInsightsService.setup({ + kibanaVersion: kibanaPackageJson.version, + logger, + isFeatureEnabled: true, + }); + + expect(createDatastreamMock).toHaveBeenCalledTimes(1); + expect(createDatastreamMock).toHaveBeenCalledWith(kibanaPackageJson.version); + }); + + it('should log a warning if createDatastream throws an error', () => { + const createDatastreamMock = createDatastream as jest.Mock; + createDatastreamMock.mockImplementation(() => { + throw new Error('test error'); + }); + + securityWorkflowInsightsService.setup({ + kibanaVersion: kibanaPackageJson.version, + logger, + isFeatureEnabled: true, + }); + + expect(logger.warn).toHaveBeenCalledTimes(1); + expect(logger.warn).toHaveBeenCalledWith(expect.stringContaining('test error')); + }); + }); + + describe('start', () => { + it('should start the service', async () => { + const createDatastreamMock = createDatastream as jest.Mock; + const ds = new DataStreamSpacesAdapter(DATA_STREAM_NAME, { + kibanaVersion: kibanaPackageJson.version, + }); + const dsInstallSpy = jest.spyOn(ds, 'install'); + dsInstallSpy.mockResolvedValueOnce(); + createDatastreamMock.mockReturnValueOnce(ds); + const createPipelineMock = createPipeline as jest.Mock; + createPipelineMock.mockResolvedValueOnce(true); + const createDataStreamMock = esClient.indices.createDataStream as jest.Mock; + + securityWorkflowInsightsService.setup({ + kibanaVersion: kibanaPackageJson.version, + logger, + isFeatureEnabled: true, + }); + expect(createDatastreamMock).toHaveBeenCalledTimes(1); + expect(createDatastreamMock).toHaveBeenCalledWith(kibanaPackageJson.version); + + await securityWorkflowInsightsService.start({ esClient }); + + expect(createPipelineMock).toHaveBeenCalledTimes(1); + expect(createPipelineMock).toHaveBeenCalledWith(esClient); + expect(dsInstallSpy).toHaveBeenCalledTimes(1); + expect(dsInstallSpy).toHaveBeenCalledWith({ + logger, + esClient, + pluginStop$: expect.any(ReplaySubject), + }); + expect(createDataStreamMock).toHaveBeenCalledTimes(1); + expect(createDataStreamMock).toHaveBeenCalledWith({ name: DATA_STREAM_NAME }); + }); + + it('should log a warning if createPipeline or ds.install throws an error', async () => { + securityWorkflowInsightsService.setup({ + kibanaVersion: kibanaPackageJson.version, + logger, + isFeatureEnabled: true, + }); + + const createPipelineMock = createPipeline as jest.Mock; + createPipelineMock.mockImplementationOnce(() => { + throw new Error('test error'); + }); + + await securityWorkflowInsightsService.start({ esClient }); + + expect(logger.warn).toHaveBeenCalledTimes(2); + expect(logger.warn).toHaveBeenNthCalledWith(1, expect.stringContaining('test error')); + }); + }); + + describe('create', () => { + it('should index the doc correctly', async () => { + const isInitializedSpy = jest + .spyOn(securityWorkflowInsightsService, 'isInitialized', 'get') + .mockResolvedValueOnce([undefined, undefined]); + + await securityWorkflowInsightsService.start({ esClient }); + const insight = getDefaultInsight(); + await securityWorkflowInsightsService.create(insight); + + // ensure it waits for initialization first + expect(isInitializedSpy).toHaveBeenCalledTimes(1); + // indexes the doc + expect(esClient.index).toHaveBeenCalledTimes(1); + expect(esClient.index).toHaveBeenCalledWith({ + index: DATA_STREAM_NAME, + body: insight, + }); + }); + }); + + describe('update', () => { + it('should update the doc correctly', async () => { + const isInitializedSpy = jest + .spyOn(securityWorkflowInsightsService, 'isInitialized', 'get') + .mockResolvedValueOnce([undefined, undefined]); + + await securityWorkflowInsightsService.start({ esClient }); + const insightId = 'some-insight-id'; + const insight = getDefaultInsight(); + await securityWorkflowInsightsService.update(insightId, insight); + + // ensure it waits for initialization first + expect(isInitializedSpy).toHaveBeenCalledTimes(1); + // updates the doc + expect(esClient.update).toHaveBeenCalledTimes(1); + expect(esClient.update).toHaveBeenCalledWith({ + index: DATA_STREAM_NAME, + id: insightId, + body: { doc: insight }, + }); + }); + }); + + describe('fetch', () => { + it('should fetch the docs with the correct params', async () => { + const isInitializedSpy = jest + .spyOn(securityWorkflowInsightsService, 'isInitialized', 'get') + .mockResolvedValueOnce([undefined, undefined]); + + await securityWorkflowInsightsService.start({ esClient }); + const searchParams: SearchParams = { + size: 50, + from: 50, + ids: ['id1', 'id2'], + categories: [Category.Endpoint], + types: [DefendInsightType.Enum.incompatible_antivirus], + sourceTypes: [SourceType.LlmConnector], + sourceIds: ['source-id1', 'source-id2'], + targetTypes: [TargetType.Endpoint], + targetIds: ['target-id1', 'target-id2'], + actionTypes: [ActionType.Refreshed, ActionType.Remediated], + }; + await securityWorkflowInsightsService.fetch(searchParams); + + // ensure it waits for initialization first + expect(isInitializedSpy).toHaveBeenCalledTimes(1); + // fetches the doc + expect(esClient.search).toHaveBeenCalledTimes(1); + expect(esClient.search).toHaveBeenCalledWith({ + index: DATA_STREAM_NAME, + body: { + query: { + bool: { + must: [ + { + terms: { + _id: ['id1', 'id2'], + }, + }, + { + terms: { + categories: ['endpoint'], + }, + }, + { + terms: { + types: ['incompatible_antivirus'], + }, + }, + { + terms: { + 'source.type': ['llm-connector'], + }, + }, + { + terms: { + 'source.id': ['source-id1', 'source-id2'], + }, + }, + { + terms: { + 'target.type': ['endpoint'], + }, + }, + { + terms: { + 'target.id': ['target-id1', 'target-id2'], + }, + }, + { + terms: { + 'action.type': ['refreshed', 'remediated'], + }, + }, + ], + }, + }, + size: searchParams.size, + from: searchParams.from, + }, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/index.ts b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/index.ts new file mode 100644 index 000000000000..0aa495dac093 --- /dev/null +++ b/x-pack/plugins/security_solution/server/endpoint/services/workflow_insights/index.ts @@ -0,0 +1,177 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ReplaySubject, firstValueFrom, combineLatest } from 'rxjs'; + +import type { + SearchHit, + UpdateResponse, + WriteResponseBase, +} from '@elastic/elasticsearch/lib/api/types'; +import type { ElasticsearchClient, Logger } from '@kbn/core/server'; +import type { DataStreamSpacesAdapter } from '@kbn/data-stream-adapter'; + +import type { + SearchParams, + SecurityWorkflowInsight, +} from '../../../../common/endpoint/types/workflow_insights'; + +import { SecurityWorkflowInsightsFailedInitialized } from './errors'; +import { buildEsQueryParams, createDatastream, createPipeline } from './helpers'; +import { DATA_STREAM_NAME } from './constants'; + +const DEFAULT_PAGE_SIZE = 10; + +interface SetupInterface { + kibanaVersion: string; + logger: Logger; + isFeatureEnabled: boolean; +} + +interface StartInterface { + esClient: ElasticsearchClient; +} + +class SecurityWorkflowInsightsService { + private setup$ = new ReplaySubject<void>(1); + private start$ = new ReplaySubject<void>(1); + private stop$ = new ReplaySubject<void>(1); + private ds: DataStreamSpacesAdapter | undefined; + private _esClient: ElasticsearchClient | undefined; + private _logger: Logger | undefined; + private _isInitialized: Promise<[void, void]> = firstValueFrom( + combineLatest<[void, void]>([this.setup$, this.start$]) + ); + private isFeatureEnabled = false; + + public get isInitialized() { + return this._isInitialized; + } + + public setup({ kibanaVersion, logger, isFeatureEnabled }: SetupInterface) { + this.isFeatureEnabled = isFeatureEnabled; + if (!isFeatureEnabled) { + return; + } + + this._logger = logger; + + try { + this.ds = createDatastream(kibanaVersion); + } catch (err) { + this.logger.warn(new SecurityWorkflowInsightsFailedInitialized(err.message).message); + return; + } + + this.setup$.next(); + } + + public async start({ esClient }: StartInterface) { + if (!this.isFeatureEnabled) { + return; + } + + this._esClient = esClient; + await firstValueFrom(this.setup$); + + try { + await createPipeline(esClient); + await this.ds?.install({ + logger: this.logger, + esClient, + pluginStop$: this.stop$, + }); + await esClient.indices.createDataStream({ name: DATA_STREAM_NAME }); + } catch (err) { + // ignore datastream already exists error + if (err?.body?.error?.type === 'resource_already_exists_exception') { + return; + } + + this.logger.warn(new SecurityWorkflowInsightsFailedInitialized(err.message).message); + return; + } + + this.start$.next(); + } + + public stop() { + this.setup$.next(); + this.setup$.complete(); + this.start$.next(); + this.start$.complete(); + this.stop$.next(); + this.stop$.complete(); + } + + public async create(insight: SecurityWorkflowInsight): Promise<WriteResponseBase> { + await this.isInitialized; + + const response = await this.esClient.index<SecurityWorkflowInsight>({ + index: DATA_STREAM_NAME, + body: insight, + }); + + return response; + } + + public async update( + id: string, + insight: Partial<SecurityWorkflowInsight> + ): Promise<UpdateResponse> { + await this.isInitialized; + + const response = await this.esClient.update<SecurityWorkflowInsight>({ + index: DATA_STREAM_NAME, + id, + body: { doc: insight }, + }); + + return response; + } + + public async fetch(params?: SearchParams): Promise<Array<SearchHit<SecurityWorkflowInsight>>> { + await this.isInitialized; + + const size = params?.size ?? DEFAULT_PAGE_SIZE; + const from = params?.from ?? 0; + + const termFilters = params ? buildEsQueryParams(params) : []; + const response = await this.esClient.search<SecurityWorkflowInsight>({ + index: DATA_STREAM_NAME, + body: { + query: { + bool: { + must: termFilters, + }, + }, + size, + from, + }, + }); + + return response?.hits?.hits ?? []; + } + + private get esClient(): ElasticsearchClient { + if (!this._esClient) { + throw new SecurityWorkflowInsightsFailedInitialized('no elasticsearch client found'); + } + + return this._esClient; + } + + private get logger(): Logger { + if (!this._logger) { + throw new SecurityWorkflowInsightsFailedInitialized('no logger found'); + } + + return this._logger; + } +} + +export const securityWorkflowInsightsService = new SecurityWorkflowInsightsService(); diff --git a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts index 54f1ce8cc7e0..4987250644cb 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/fleet_integration.ts @@ -7,7 +7,7 @@ import type { Logger, ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; -import type { PluginStartContract as AlertsStartContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { PostPackagePolicyCreateCallback, PostPackagePolicyPostDeleteCallback, @@ -119,7 +119,7 @@ export const getPackagePolicyCreateCallback = ( logger: Logger, manifestManager: ManifestManager, securitySolutionRequestContextFactory: IRequestContextFactory, - alerts: AlertsStartContract, + alerts: AlertingServerStart, licenseService: LicenseService, exceptionsClient: ExceptionListClient | undefined, cloud: CloudSetup, diff --git a/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts b/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts index d4a60be85d3e..891face9f287 100644 --- a/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts +++ b/x-pack/plugins/security_solution/server/fleet_integration/handlers/install_prepackaged_rules.ts @@ -7,7 +7,7 @@ import type { KibanaRequest, Logger } from '@kbn/core/server'; import type { ExceptionListClient } from '@kbn/lists-plugin/server'; -import type { PluginStartContract as AlertsStartContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerStart } from '@kbn/alerting-plugin/server'; import { createDetectionIndex } from '../../lib/detection_engine/routes/index/create_index_route'; import { createPrepackagedRules } from '../../lib/detection_engine/prebuilt_rules'; import type { SecuritySolutionApiRequestHandlerContext } from '../../types'; @@ -16,7 +16,7 @@ export interface InstallPrepackagedRulesProps { logger: Logger; context: SecuritySolutionApiRequestHandlerContext; request: KibanaRequest; - alerts: AlertsStartContract; + alerts: AlertingServerStart; exceptionsClient: ExceptionListClient; } @@ -45,11 +45,8 @@ export const installPrepackagedRules = async ({ try { // this checks to make sure index exists first, safe to try in case of failure above // may be able to recover from minor errors - await createPrepackagedRules( - context, - alerts.getRulesClientWithRequest(request), - exceptionsClient - ); + const rulesClient = await alerts.getRulesClientWithRequest(request); + await createPrepackagedRules(context, rulesClient, exceptionsClient); } catch (err) { logger.error( `Unable to create detection rules automatically (${err.statusCode}): ${err.message}` diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts index dc9c15ac5b5f..718c16387281 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.ts @@ -45,7 +45,7 @@ export const getPrebuiltRulesAndTimelinesStatusRoute = (router: SecuritySolution const siemResponse = buildSiemResponse(response); const ctx = await context.resolve(['core', 'alerting']); const savedObjectsClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const ruleAssetsClient = createPrebuiltRuleAssetsClient(savedObjectsClient); try { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/get_prebuilt_rules_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/get_prebuilt_rules_status_route.ts index 0561c826e0c7..52e2c552c74f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/get_prebuilt_rules_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/get_prebuilt_rules_status/get_prebuilt_rules_status_route.ts @@ -37,7 +37,7 @@ export const getPrebuiltRulesStatusRoute = (router: SecuritySolutionPluginRouter try { const ctx = await context.resolve(['core', 'alerting']); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient); const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.ts index 8740d27fce81..f24454726c61 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.ts @@ -53,7 +53,7 @@ export const installPrebuiltRulesAndTimelinesRoute = (router: SecuritySolutionPl const siemResponse = buildSiemResponse(response); try { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const validated = await createPrepackagedRules( await context.securitySolution, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts index 8b4d38bd2f4a..a2abc00b43a3 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_installation/perform_rule_installation_route.ts @@ -61,7 +61,7 @@ export const performRuleInstallationRoute = (router: SecuritySolutionPluginRoute const ctx = await context.resolve(['core', 'alerting', 'securitySolution']); const config = ctx.securitySolution.getConfig(); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient); const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts index db5f7a186d30..cb0baca5c522 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/perform_rule_upgrade/perform_rule_upgrade_route.ts @@ -61,7 +61,7 @@ export const performRuleUpgradeRoute = ( try { const ctx = await context.resolve(['core', 'alerting', 'securitySolution']); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient); const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/review_rule_installation_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/review_rule_installation_route.ts index c1c45532f61b..78d75603dd23 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/review_rule_installation_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_installation/review_rule_installation_route.ts @@ -48,7 +48,7 @@ export const reviewRuleInstallationRoute = (router: SecuritySolutionPluginRouter try { const ctx = await context.resolve(['core', 'alerting']); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient); const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts index 3da62bd9bb21..0f8dee1a4e2f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts @@ -57,7 +57,7 @@ export const reviewRuleUpgradeRoute = (router: SecuritySolutionPluginRouter) => try { const ctx = await context.resolve(['core', 'alerting']); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const ruleAssetsClient = createPrebuiltRuleAssetsClient(soClient); const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/force_target_version_diff_algorithm.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/force_target_version_diff_algorithm.test.ts new file mode 100644 index 000000000000..f6035c9e87ca --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/force_target_version_diff_algorithm.test.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ThreeVersionsOf } from '../../../../../../../../common/api/detection_engine'; +import { + ThreeWayMergeOutcome, + MissingVersion, + ThreeWayDiffConflict, +} from '../../../../../../../../common/api/detection_engine'; +import { forceTargetVersionDiffAlgorithm } from './force_target_version_diff_algorithm'; + +describe('forceTargetVersionDiffAlgorithm', () => { + describe('when base version exists', () => { + it('returns a NON conflict diff', () => { + const mockVersions: ThreeVersionsOf<number> = { + base_version: 1, + current_version: 1, + target_version: 2, + }; + + const result = forceTargetVersionDiffAlgorithm(mockVersions); + + expect(result).toMatchObject({ + conflict: ThreeWayDiffConflict.NONE, + }); + }); + + it('return merge outcome TARGET', () => { + const mockVersions: ThreeVersionsOf<number> = { + base_version: 1, + current_version: 1, + target_version: 2, + }; + + const result = forceTargetVersionDiffAlgorithm(mockVersions); + + expect(result).toMatchObject({ + has_base_version: true, + merge_outcome: ThreeWayMergeOutcome.Target, + }); + }); + }); + + describe('when base version missing', () => { + it('returns a NON conflict diff', () => { + const mockVersions: ThreeVersionsOf<number> = { + base_version: MissingVersion, + current_version: 1, + target_version: 2, + }; + + const result = forceTargetVersionDiffAlgorithm(mockVersions); + + expect(result).toMatchObject({ + conflict: ThreeWayDiffConflict.NONE, + }); + }); + + it('return merge outcome TARGET', () => { + const mockVersions: ThreeVersionsOf<number> = { + base_version: MissingVersion, + current_version: 1, + target_version: 2, + }; + + const result = forceTargetVersionDiffAlgorithm(mockVersions); + + expect(result).toMatchObject({ + has_base_version: false, + merge_outcome: ThreeWayMergeOutcome.Target, + }); + }); + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/force_target_version_diff_algorithm.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/force_target_version_diff_algorithm.ts new file mode 100644 index 000000000000..ed19be0275ae --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/force_target_version_diff_algorithm.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + ThreeVersionsOf, + ThreeWayDiff, +} from '../../../../../../../../common/api/detection_engine/prebuilt_rules'; +import { + MissingVersion, + ThreeWayDiffConflict, + ThreeWayMergeOutcome, + determineDiffOutcome, +} from '../../../../../../../../common/api/detection_engine/prebuilt_rules'; + +/** + * Diff algorithm forcing target version. Useful for special fields like `version`. + */ +export const forceTargetVersionDiffAlgorithm = <TValue>( + versions: ThreeVersionsOf<TValue> +): ThreeWayDiff<TValue> => { + const { + base_version: baseVersion, + current_version: currentVersion, + target_version: targetVersion, + } = versions; + const hasBaseVersion = baseVersion !== MissingVersion; + const hasUpdate = targetVersion !== currentVersion; + + return { + has_base_version: hasBaseVersion, + base_version: hasBaseVersion ? baseVersion : undefined, + current_version: currentVersion, + target_version: targetVersion, + merged_version: targetVersion, + merge_outcome: ThreeWayMergeOutcome.Target, + + diff_outcome: determineDiffOutcome(baseVersion, currentVersion, targetVersion), + has_update: hasUpdate, + conflict: ThreeWayDiffConflict.NONE, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts index c8b55a49edc0..b0f192cf70e4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/algorithms/index.ts @@ -15,3 +15,4 @@ export { kqlQueryDiffAlgorithm } from './kql_query_diff_algorithm'; export { eqlQueryDiffAlgorithm } from './eql_query_diff_algorithm'; export { esqlQueryDiffAlgorithm } from './esql_query_diff_algorithm'; export { ruleTypeDiffAlgorithm } from './rule_type_diff_algorithm'; +export { forceTargetVersionDiffAlgorithm } from './force_target_version_diff_algorithm'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts index 5730af03789d..78ea28137bbf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/calculation/calculate_rule_fields_diff.ts @@ -48,6 +48,7 @@ import { eqlQueryDiffAlgorithm, esqlQueryDiffAlgorithm, ruleTypeDiffAlgorithm, + forceTargetVersionDiffAlgorithm, } from './algorithms'; const BASE_TYPE_ERROR = `Base version can't be of different rule type`; @@ -179,7 +180,11 @@ const calculateCommonFieldsDiff = ( const commonFieldsDiffAlgorithms: FieldsDiffAlgorithmsFor<DiffableCommonFields> = { rule_id: simpleDiffAlgorithm, - version: numberDiffAlgorithm, + /** + * `version` shouldn't have a conflict. It always get target value automatically. + * Diff has informational purpose. + */ + version: forceTargetVersionDiffAlgorithm, name: singleLineStringDiffAlgorithm, tags: scalarArrayDiffAlgorithm, description: multiLineStringDiffAlgorithm, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts index cba989890438..3c99cebbbe8f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/__mocks__/request_context.ts @@ -103,7 +103,7 @@ const createRequestContextMock = ( getActionsClient: jest.fn(() => clients.actionsClient), } as unknown as jest.Mocked<ActionsApiRequestHandlerContext>, alerting: { - getRulesClient: jest.fn(() => clients.rulesClient), + getRulesClient: jest.fn().mockResolvedValue(clients.rulesClient), } as unknown as jest.Mocked<AlertingApiRequestHandlerContext>, licensing: clients.licensing, lists: { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts index d5623df8db91..2a06549f3f35 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/api/create_legacy_notification/route.ts @@ -64,7 +64,7 @@ export const legacyCreateLegacyNotificationRoute = ( }, }, async (context, request, response) => { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const savedObjectsClient = (await context.core).savedObjects.client; const { alert_id: ruleAlertId } = request.query; const { actions, interval, name } = request.body; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts index 4adf71d258e0..1cb8d83dc965 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_actions_legacy/logic/notifications/legacy_rules_notification_rule_type.test.ts @@ -191,6 +191,7 @@ describe('legacyRules_notification_rule_type', () => { const date = new Date('2019-12-14T16:40:33.400Z').toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }; rule = legacyRulesNotificationRuleType({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts index 1d8038b1052c..b178d912ccf2 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/create_rule_exceptions/route.ts @@ -63,7 +63,7 @@ export const createRuleExceptionsRoute = (router: SecuritySolutionPluginRouter) 'licensing', 'lists', ]); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const listsClient = ctx.securitySolution.getExceptionListClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts index 3680a70525fd..db890c7104e5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_exceptions/api/find_exception_references/route.ts @@ -54,7 +54,7 @@ export const findRuleExceptionReferencesRoute = (router: SecuritySolutionPluginR const { ids, namespace_types: namespaceTypes, list_ids: listIds } = request.query; const ctx = await context.resolve(['core', 'securitySolution', 'alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const listsClient = ctx.securitySolution.getExceptionListClient(); if ( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts index e599ff4a936e..e0b33b35e2e1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_actions/route.ts @@ -131,7 +131,7 @@ export const performBulkActionRoute = ( 'actions', ]); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const exceptionsClient = ctx.lists?.getExceptionListClient(); const savedObjectsClient = ctx.core.savedObjects.client; const actionsClient = ctx.actions.getActionsClient(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts index 225782ef0194..8d35de954715 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts @@ -66,7 +66,7 @@ export const bulkCreateRulesRoute = (router: SecuritySolutionPluginRouter, logge try { const ctx = await context.resolve(['core', 'securitySolution', 'licensing', 'alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const ruleDefinitions = request.body; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts index f24f563e1a99..c38bd58bde5a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts @@ -61,7 +61,7 @@ export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logge try { const ctx = await context.resolve(['core', 'securitySolution', 'alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const rules = await Promise.all( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts index 5bd8adaf86a3..fbbfc2656124 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts @@ -60,7 +60,7 @@ export const bulkPatchRulesRoute = (router: SecuritySolutionPluginRouter, logger try { const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const rules = await Promise.all( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts index d2c985fbc70e..ad82d5a0edce 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts @@ -64,7 +64,7 @@ export const bulkUpdateRulesRoute = (router: SecuritySolutionPluginRouter, logge try { const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const rules = await Promise.all( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/coverage_overview/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/coverage_overview/route.ts index a959c522c171..a3c6a07e0b8b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/coverage_overview/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/coverage_overview/route.ts @@ -45,7 +45,7 @@ export const getCoverageOverviewRoute = (router: SecuritySolutionPluginRouter) = const responseData = await handleCoverageOverviewRequest({ params: request.body, - deps: { rulesClient: ctx.alerting.getRulesClient() }, + deps: { rulesClient: await ctx.alerting.getRulesClient() }, }); return response.ok({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts index a5fee66d0014..dbeaed85db05 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts @@ -58,7 +58,7 @@ export const createRuleRoute = (router: SecuritySolutionPluginRouter): void => { 'lists', ]); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const exceptionsClient = ctx.lists?.getExceptionListClient(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts index a5854e9a2caf..3e5ef8aa8ab7 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts @@ -50,7 +50,7 @@ export const deleteRuleRoute = (router: SecuritySolutionPluginRouter) => { const { id, rule_id: ruleId } = request.query; const ctx = await context.resolve(['core', 'securitySolution', 'alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); const rule = await readRules({ rulesClient, id, ruleId }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts index a37bb2996333..be19da6df831 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/export_rules/route.ts @@ -56,7 +56,7 @@ export const exportRulesRoute = ( }, async (context, request, response) => { const siemResponse = buildSiemResponse(response); - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const exceptionsClient = (await context.lists)?.getExceptionListClient(); const actionsClient = (await context.actions)?.getActionsClient(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts index 05633892cddd..6496c6edc2a8 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/filters/route.ts @@ -70,7 +70,7 @@ export const getRuleManagementFilters = (router: SecuritySolutionPluginRouter) = async (context, _, response): Promise<IKibanaResponse<GetRuleManagementFiltersResponse>> => { const siemResponse = buildSiemResponse(response); const ctx = await context.resolve(['alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); try { const [{ prebuilt: prebuiltRulesCount, custom: customRulesCount }, tags] = diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts index 899e568e7963..dbe58e7815ea 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/find_rules/route.ts @@ -51,7 +51,7 @@ export const findRulesRoute = (router: SecuritySolutionPluginRouter, logger: Log try { const { query } = request; const ctx = await context.resolve(['core', 'securitySolution', 'alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const rules = await findRules({ rulesClient, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts index fcd388e81d1e..6971628a780d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts @@ -52,7 +52,7 @@ export const patchRuleRoute = (router: SecuritySolutionPluginRouter) => { } try { const params = request.body; - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); const detectionRulesClient = (await context.securitySolution).getDetectionRulesClient(); const existingRule = await readRules({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts index f8826e8aad45..53b8ca408520 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts @@ -49,7 +49,7 @@ export const readRuleRoute = (router: SecuritySolutionPluginRouter, logger: Logg const { id, rule_id: ruleId } = request.query; try { - const rulesClient = (await context.alerting).getRulesClient(); + const rulesClient = await (await context.alerting).getRulesClient(); // TODO: https://github.com/elastic/kibana/issues/125642 Reuse fetchRuleById const rule = await readRules({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts index 0bedcb25de52..8a83aae938d6 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts @@ -50,7 +50,7 @@ export const updateRuleRoute = (router: SecuritySolutionPluginRouter) => { } try { const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const detectionRulesClient = ctx.securitySolution.getDetectionRulesClient(); checkDefaultRuleExceptionListReferences({ exceptionLists: request.body.exceptions_list }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts index d94f695f3917..0332dfe02496 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/tags/read_tags/route.ts @@ -32,7 +32,7 @@ export const readTagsRoute = (router: SecuritySolutionPluginRouter) => { async (context, request, response): Promise<IKibanaResponse<ReadTagsResponse>> => { const siemResponse = buildSiemResponse(response); const ctx = await context.resolve(['alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); try { const tags = await readTags({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts index bc805867f69e..8e8093d96c3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts @@ -83,7 +83,8 @@ export const previewRulesRoute = ( securityRuleTypeOptions: CreateSecurityRuleTypeWrapperProps, previewRuleDataClient: IRuleDataClient, getStartServices: StartServicesAccessor<StartPlugins>, - logger: Logger + logger: Logger, + isServerless: boolean ) => { router.versioned .post({ @@ -320,6 +321,7 @@ export const previewRulesRoute = ( const date = startedAt.toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless, })) as { state: TState; loggedRequests: RulePreviewLoggedRequest[] }); const errors = loggedStatusChanges diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.ts index 4fedc1ea2784..71f5a9b5ee79 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/register_routes.ts @@ -24,7 +24,8 @@ export const registerRulePreviewRoutes = ( securityRuleTypeOptions: CreateSecurityRuleTypeWrapperProps, previewRuleDataClient: IRuleDataClient, getStartServices: StartServicesAccessor<StartPlugins>, - logger: Logger + logger: Logger, + isServerless: boolean ) => { previewRulesRoute( router, @@ -35,6 +36,7 @@ export const registerRulePreviewRoutes = ( securityRuleTypeOptions, previewRuleDataClient, getStartServices, - logger + logger, + isServerless ); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts index c3b748f5d182..b36ca687bc51 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/__mocks__/rule_type.ts @@ -16,7 +16,7 @@ import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import { ruleRegistryMocks } from '@kbn/rule-registry-plugin/server/mocks'; import { eventLogServiceMock } from '@kbn/event-log-plugin/server/mocks'; import type { PluginSetupContract as ActionsPluginSetupContract } from '@kbn/actions-plugin/server'; -import type { PluginSetupContract as AlertingPluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; import type { ConfigType } from '../../../../config'; import type { AlertAttributes } from '../types'; import { createRuleMock } from './rule'; @@ -48,7 +48,7 @@ export const createRuleTypeMocks = ( alertExecutor = executor; }, getConfig: () => ({ run: { alerts: { max: DEFAULT_MAX_ALERTS } } }), - } as AlertingPluginSetupContract; + } as AlertingServerSetup; const actions = { registerType: jest.fn(), diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/search_after_bulk_create.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/search_after_bulk_create.test.ts index d2e51e03908f..d3b0c2dd6b42 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/search_after_bulk_create.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/search_after_bulk_create.test.ts @@ -48,7 +48,7 @@ import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; import type { BuildReasonMessage } from './reason_formatters'; import type { QueryRuleParams } from '../../rule_schema'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; describe('searchAfterAndBulkCreate', () => { let mockService: RuleExecutorServicesMock; @@ -58,7 +58,7 @@ describe('searchAfterAndBulkCreate', () => { let wrapHits: WrapHits; let inputIndexPattern: string[] = []; let listClient = listMock.getListClient(); - let alerting: PluginSetupContract; + let alerting: AlertingServerSetup; const ruleExecutionLogger = ruleExecutionLogMock.forExecutors.create(); const someGuids = Array.from({ length: 13 }).map(() => uuidv4()); const sampleParams = getQueryRuleParams(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts index 5397d473af3c..0a625ed5f245 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.test.ts @@ -68,7 +68,7 @@ import type { ShardError } from '../../../types'; import { ruleExecutionLogMock } from '../../rule_monitoring/mocks'; import type { GenericBulkCreateResponse } from '../factories'; import type { BaseFieldsLatest } from '../../../../../common/api/detection_engine/model/alerts'; -import type { PluginSetupContract } from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server'; describe('utils', () => { const anchor = '2020-01-01T06:06:06.666Z'; @@ -446,7 +446,7 @@ describe('utils', () => { }); describe('getRuleRangeTuples', () => { - let alerting: PluginSetupContract; + let alerting: AlertingServerSetup; beforeEach(() => { alerting = alertsMock.createSetup(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts index 45193c14fa39..bf0899978f2b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/utils/utils.ts @@ -27,7 +27,7 @@ import type { import type { AlertInstanceContext, AlertInstanceState, - PluginSetupContract, + AlertingServerSetup, RuleExecutorServices, } from '@kbn/alerting-plugin/server'; import { parseDuration } from '@kbn/alerting-plugin/server'; @@ -429,7 +429,7 @@ export const getRuleRangeTuples = async ({ interval: string; maxSignals: number; ruleExecutionLogger: IRuleExecutionLogForExecutors; - alerting: PluginSetupContract; + alerting: AlertingServerSetup; }) => { const originalFrom = dateMath.parse(from, { forceNow: startedAt }); const originalTo = dateMath.parse(to, { forceNow: startedAt }); diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts deleted file mode 100644 index 67d33fb42dc9..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/auditing/resources.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export const EntityStoreResource = { - ENTITY_ENGINE: 'entity_engine', - ENTITY_DEFINITION: 'entity_definition', - ENTITY_INDEX: 'entity_index', - INDEX_COMPONENT_TEMPLATE: 'index_component_template', - PLATFORM_PIPELINE: 'platform_pipeline', - FIELD_RETENTION_ENRICH_POLICY: 'field_retention_enrich_policy', - FIELD_RETENTION_ENRICH_POLICY_TASK: 'field_retention_enrich_policy_task', -} as const; - -export type EntityStoreResource = (typeof EntityStoreResource)[keyof typeof EntityStoreResource]; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/component_template.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/component_template.ts index d0fe14dcd3b8..a1352594ff47 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/component_template.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/component_template.ts @@ -6,6 +6,10 @@ */ import type { ElasticsearchClient } from '@kbn/core/server'; +import { + EngineComponentResourceEnum, + type EngineComponentStatus, +} from '../../../../../common/api/entity_analytics'; import type { UnitedEntityDefinition } from '../united_entity_definitions'; const getComponentTemplateName = (definitionId: string) => `${definitionId}-latest@platform`; @@ -41,3 +45,24 @@ export const deleteEntityIndexComponentTemplate = ({ unitedDefinition, esClient } ); }; + +export const getEntityIndexComponentTemplateStatus = async ({ + definitionId, + esClient, +}: Pick<Options, 'esClient'> & { definitionId: string }): Promise<EngineComponentStatus> => { + const name = getComponentTemplateName(definitionId); + const componentTemplate = await esClient.cluster.getComponentTemplate( + { + name, + }, + { + ignore: [404], + } + ); + + return { + id: name, + installed: componentTemplate?.component_templates?.length > 0, + resource: EngineComponentResourceEnum.component_template, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/enrich_policy.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/enrich_policy.ts index 4b8ce594a6cb..7064a4dd9885 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/enrich_policy.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/enrich_policy.ts @@ -7,6 +7,7 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { EnrichPutPolicyRequest } from '@elastic/elasticsearch/lib/api/types'; +import { EngineComponentResourceEnum } from '../../../../../common/api/entity_analytics'; import { getEntitiesIndexName } from '../utils'; import type { UnitedEntityDefinition } from '../united_entity_definitions'; @@ -105,3 +106,21 @@ export const deleteFieldRetentionEnrichPolicy = async ({ } } }; + +export const getFieldRetentionEnrichPolicyStatus = async ({ + definitionMetadata, + esClient, +}: { + definitionMetadata: DefinitionMetadata; + esClient: ElasticsearchClient; +}) => { + const name = getFieldRetentionEnrichPolicyName(definitionMetadata); + const policy = await esClient.enrich.getPolicy({ name }, { ignore: [404] }); + const policies = policy.policies; + + return { + installed: policies.length > 0, + id: name, + resource: EngineComponentResourceEnum.enrich_policy, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts index 6fb5935618df..0de8fe20050c 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/entity_index.ts @@ -6,7 +6,11 @@ */ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; -import type { EntityType } from '../../../../../common/api/entity_analytics'; +import { + EngineComponentResourceEnum, + type EngineComponentStatus, + type EntityType, +} from '../../../../../common/api/entity_analytics'; import { getEntitiesIndexName } from '../utils'; import { createOrUpdateIndex } from '../../utils/create_or_update_index'; @@ -36,3 +40,21 @@ export const deleteEntityIndex = ({ entityType, esClient, namespace }: Options) ignore: [404], } ); + +export const getEntityIndexStatus = async ({ + entityType, + esClient, + namespace, +}: Pick<Options, 'entityType' | 'namespace' | 'esClient'>): Promise<EngineComponentStatus> => { + const index = getEntitiesIndexName(entityType, namespace); + const exists = await esClient.indices.exists( + { + index, + }, + { + ignore: [404], + } + ); + + return { id: index, installed: exists, resource: EngineComponentResourceEnum.index }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts index f4d2b848b726..f57102fd13f1 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/elasticsearch_assets/ingest_pipeline.ts @@ -8,6 +8,7 @@ import type { ElasticsearchClient, Logger } from '@kbn/core/server'; import type { IngestProcessorContainer } from '@elastic/elasticsearch/lib/api/types'; import type { EntityDefinition } from '@kbn/entities-schema'; +import { EngineComponentResourceEnum } from '../../../../../common/api/entity_analytics'; import { type FieldRetentionDefinition } from '../field_retention_definition'; import { debugDeepCopyContextStep, @@ -161,3 +162,27 @@ export const deletePlatformPipeline = ({ } ); }; + +export const getPlatformPipelineStatus = async ({ + definition, + esClient, +}: { + definition: EntityDefinition; + esClient: ElasticsearchClient; +}) => { + const pipelineId = getPlatformPipelineId(definition); + const pipeline = await esClient.ingest.getPipeline( + { + id: pipelineId, + }, + { + ignore: [404], + } + ); + + return { + id: pipelineId, + installed: !!pipeline[pipelineId], + resource: EngineComponentResourceEnum.ingest_pipeline, + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts index a89469acf569..72d650846fc5 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/entity_store_data_client.ts @@ -20,19 +20,28 @@ import type { TaskManagerStartContract } from '@kbn/task-manager-plugin/server'; import type { DataViewsService } from '@kbn/data-views-plugin/common'; import { isEqual } from 'lodash/fp'; import moment from 'moment'; +import type { EntityDefinitionWithState } from '@kbn/entityManager-plugin/server/lib/entities/types'; +import type { EntityDefinition } from '@kbn/entities-schema'; +import type { estypes } from '@elastic/elasticsearch'; import type { + GetEntityStoreStatusRequestQuery, GetEntityStoreStatusResponse, +} from '../../../../common/api/entity_analytics/entity_store/status.gen'; +import type { InitEntityStoreRequestBody, InitEntityStoreResponse, -} from '../../../../common/api/entity_analytics/entity_store/enablement.gen'; +} from '../../../../common/api/entity_analytics/entity_store/enable.gen'; import type { AppClient } from '../../..'; -import { EntityType } from '../../../../common/api/entity_analytics'; +import { EngineComponentResourceEnum, EntityType } from '../../../../common/api/entity_analytics'; import type { Entity, EngineDataviewUpdateResult, InitEntityEngineRequestBody, InitEntityEngineResponse, InspectQuery, + ListEntityEnginesResponse, + EngineComponentStatus, + EngineComponentResource, } from '../../../../common/api/entity_analytics'; import { EngineDescriptorClient } from './saved_object/engine_descriptor'; import { ENGINE_STATUS, ENTITY_STORE_STATUS, MAX_SEARCH_RESPONSE_SIZE } from './constants'; @@ -41,6 +50,7 @@ import { getUnitedEntityDefinition } from './united_entity_definitions'; import { startEntityStoreFieldRetentionEnrichTask, removeEntityStoreFieldRetentionEnrichTask, + getEntityStoreFieldRetentionEnrichTaskState as getEntityStoreFieldRetentionEnrichTaskStatus, } from './task'; import { createEntityIndex, @@ -52,6 +62,10 @@ import { createFieldRetentionEnrichPolicy, executeFieldRetentionEnrichPolicy, deleteFieldRetentionEnrichPolicy, + getPlatformPipelineStatus, + getFieldRetentionEnrichPolicyStatus, + getEntityIndexStatus, + getEntityIndexComponentTemplateStatus, } from './elasticsearch_assets'; import { RiskScoreDataClient } from '../risk_score/risk_score_data_client'; import { @@ -62,7 +76,6 @@ import { isPromiseRejected, } from './utils'; import { EntityEngineActions } from './auditing/actions'; -import { EntityStoreResource } from './auditing/resources'; import { AUDIT_CATEGORY, AUDIT_OUTCOME, AUDIT_TYPE } from '../audit'; import type { EntityRecord, EntityStoreConfig } from './types'; import { @@ -71,6 +84,19 @@ import { } from '../../telemetry/event_based/events'; import { CRITICALITY_VALUES } from '../asset_criticality/constants'; +// Workaround. TransformState type is wrong. The health type should be: TransformHealth from '@kbn/transform-plugin/common/types/transform_stats' +export interface TransformHealth extends estypes.TransformGetTransformStatsTransformStatsHealth { + issues?: TransformHealthIssue[]; +} + +export interface TransformHealthIssue { + type: string; + issue: string; + details?: string; + count: number; + first_occurrence?: number; +} + interface EntityStoreClientOpts { logger: Logger; clusterClient: IScopedClusterClient; @@ -131,6 +157,42 @@ export class EntityStoreDataClient { }); } + private async getEngineComponentsState( + type: EntityType, + definition?: EntityDefinition + ): Promise<EngineComponentStatus[]> { + const { namespace, taskManager } = this.options; + + return definition + ? Promise.all([ + ...(taskManager + ? [getEntityStoreFieldRetentionEnrichTaskStatus({ namespace, taskManager })] + : []), + getPlatformPipelineStatus({ + definition, + esClient: this.esClient, + }), + getFieldRetentionEnrichPolicyStatus({ + definitionMetadata: { + namespace, + entityType: type, + version: definition.version, + }, + esClient: this.esClient, + }), + getEntityIndexStatus({ + entityType: type, + esClient: this.esClient, + namespace, + }), + getEntityIndexComponentTemplateStatus({ + definitionId: definition.id, + esClient: this.esClient, + }), + ]) + : Promise.resolve([] as EngineComponentStatus[]); + } + public async enable( { indexPattern = '', filter = '', fieldHistoryLength = 10 }: InitEntityStoreRequestBody, { pipelineDebugMode = false }: { pipelineDebugMode?: boolean } = {} @@ -152,7 +214,10 @@ export class EntityStoreDataClient { return { engines, succeeded: true }; } - public async status(): Promise<GetEntityStoreStatusResponse> { + public async status({ + include_components: withComponents = false, + }: GetEntityStoreStatusRequestQuery): Promise<GetEntityStoreStatusResponse> { + const { namespace } = this.options; const { engines, count } = await this.engineClient.list(); let status = ENTITY_STORE_STATUS.RUNNING; @@ -166,7 +231,38 @@ export class EntityStoreDataClient { status = ENTITY_STORE_STATUS.INSTALLING; } - return { engines, status }; + if (withComponents) { + const enginesWithComponents = await Promise.all( + engines.map(async (engine) => { + const entityDefinitionId = buildEntityDefinitionId(engine.type, namespace); + const { + definitions: [definition], + } = await this.entityClient.getEntityDefinitions({ + id: entityDefinitionId, + includeState: withComponents, + }); + + const definitionComponents = this.getComponentFromEntityDefinition( + entityDefinitionId, + definition + ); + + const entityStoreComponents = await this.getEngineComponentsState( + engine.type, + definition + ); + + return { + ...engine, + components: [...definitionComponents, ...entityStoreComponents], + }; + }) + ); + + return { engines: enginesWithComponents, status }; + } else { + return { engines, status }; + } } public async init( @@ -203,7 +299,7 @@ export class EntityStoreDataClient { this.log('info', entityType, `Initializing entity store`); this.audit( EntityEngineActions.INIT, - EntityStoreResource.ENTITY_ENGINE, + EngineComponentResourceEnum.entity_engine, entityType, 'Initializing entity engine' ); @@ -332,7 +428,7 @@ export class EntityStoreDataClient { this.audit( EntityEngineActions.INIT, - EntityStoreResource.ENTITY_ENGINE, + EngineComponentResourceEnum.entity_engine, entityType, 'Failed to initialize entity engine resources', err @@ -355,6 +451,50 @@ export class EntityStoreDataClient { } } + public getComponentFromEntityDefinition( + id: string, + definition: EntityDefinitionWithState | EntityDefinition + ): EngineComponentStatus[] { + if (!definition) { + return [ + { + id, + installed: false, + resource: EngineComponentResourceEnum.entity_definition, + }, + ]; + } + + if ('state' in definition) { + return [ + { + id: definition.id, + installed: definition.state.installed, + resource: EngineComponentResourceEnum.entity_definition, + }, + ...definition.state.components.transforms.map(({ installed, running, stats }) => ({ + id, + resource: EngineComponentResourceEnum.transform, + installed, + errors: (stats?.health as TransformHealth)?.issues?.map(({ issue, details }) => ({ + title: issue, + message: details, + })), + })), + ...definition.state.components.ingestPipelines.map((pipeline) => ({ + resource: EngineComponentResourceEnum.ingest_pipeline, + ...pipeline, + })), + ...definition.state.components.indexTemplates.map(({ installed }) => ({ + id, + installed, + resource: EngineComponentResourceEnum.index_template, + })), + ]; + } + return []; + } + public async getExistingEntityDefinition(entityType: EntityType) { const entityDefinitionId = buildEntityDefinitionId(entityType, this.options.namespace); @@ -387,7 +527,7 @@ export class EntityStoreDataClient { const fullEntityDefinition = await this.getExistingEntityDefinition(entityType); this.audit( EntityEngineActions.START, - EntityStoreResource.ENTITY_DEFINITION, + EngineComponentResourceEnum.entity_definition, entityType, 'Starting entity definition' ); @@ -414,7 +554,7 @@ export class EntityStoreDataClient { const fullEntityDefinition = await this.getExistingEntityDefinition(entityType); this.audit( EntityEngineActions.STOP, - EntityStoreResource.ENTITY_DEFINITION, + EngineComponentResourceEnum.entity_definition, entityType, 'Stopping entity definition' ); @@ -428,7 +568,7 @@ export class EntityStoreDataClient { return this.engineClient.get(entityType); } - public async list() { + public async list(): Promise<ListEntityEnginesResponse> { return this.engineClient.list(); } @@ -457,7 +597,7 @@ export class EntityStoreDataClient { this.log('info', entityType, `Deleting entity store`); this.audit( EntityEngineActions.DELETE, - EntityStoreResource.ENTITY_ENGINE, + EngineComponentResourceEnum.entity_engine, entityType, 'Deleting entity engine' ); @@ -525,7 +665,7 @@ export class EntityStoreDataClient { this.audit( EntityEngineActions.DELETE, - EntityStoreResource.ENTITY_ENGINE, + EngineComponentResourceEnum.entity_engine, entityType, 'Failed to delete entity engine', err @@ -672,7 +812,7 @@ export class EntityStoreDataClient { private audit( action: EntityEngineActions, - resource: EntityStoreResource, + resource: EngineComponentResource, entityType: EntityType, msg: string, error?: Error diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/enablement.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/enablement.ts index 16813fccdf23..d19e9699f475 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/enablement.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/enablement.ts @@ -10,8 +10,8 @@ import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; -import type { InitEntityStoreResponse } from '../../../../../common/api/entity_analytics/entity_store/enablement.gen'; -import { InitEntityStoreRequestBody } from '../../../../../common/api/entity_analytics/entity_store/enablement.gen'; +import type { InitEntityStoreResponse } from '../../../../../common/api/entity_analytics/entity_store/enable.gen'; +import { InitEntityStoreRequestBody } from '../../../../../common/api/entity_analytics/entity_store/enable.gen'; import { API_VERSIONS, APP_ID } from '../../../../../common/constants'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { checkAndInitAssetCriticalityResources } from '../../asset_criticality/check_and_init_asset_criticality_resources'; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stats.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stats.ts deleted file mode 100644 index 24785fbd5c01..000000000000 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/stats.ts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { IKibanaResponse, Logger } from '@kbn/core/server'; -import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; -import { transformError } from '@kbn/securitysolution-es-utils'; -import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; - -import type { GetEntityEngineStatsResponse } from '../../../../../common/api/entity_analytics/entity_store/engine/stats.gen'; -import { GetEntityEngineStatsRequestParams } from '../../../../../common/api/entity_analytics/entity_store/engine/stats.gen'; -import { API_VERSIONS, APP_ID } from '../../../../../common/constants'; -import type { EntityAnalyticsRoutesDeps } from '../../types'; - -export const getEntityEngineStatsRoute = ( - router: EntityAnalyticsRoutesDeps['router'], - logger: Logger -) => { - router.versioned - .post({ - access: 'public', - path: '/api/entity_store/engines/{entityType}/stats', - security: { - authz: { - requiredPrivileges: ['securitySolution', `${APP_ID}-entity-analytics`], - }, - }, - }) - .addVersion( - { - version: API_VERSIONS.public.v1, - validate: { - request: { - params: buildRouteValidationWithZod(GetEntityEngineStatsRequestParams), - }, - }, - }, - - async ( - context, - request, - response - ): Promise<IKibanaResponse<GetEntityEngineStatsResponse>> => { - const siemResponse = buildSiemResponse(response); - - try { - // TODO - throw new Error('Not implemented'); - - // return response.ok({ body }); - } catch (e) { - logger.error('Error in GetEntityEngineStats:', e); - const error = transformError(e); - return siemResponse.error({ - statusCode: error.statusCode, - body: error.message, - }); - } - } - ); -}; diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/status.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/status.ts index 7a59b59b9914..c2c24b114f66 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/status.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/routes/status.ts @@ -15,7 +15,9 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils'; import { transformError } from '@kbn/securitysolution-es-utils'; -import type { GetEntityStoreStatusResponse } from '../../../../../common/api/entity_analytics/entity_store/enablement.gen'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import type { GetEntityStoreStatusResponse } from '../../../../../common/api/entity_analytics/entity_store/status.gen'; +import { GetEntityStoreStatusRequestQuery } from '../../../../../common/api/entity_analytics/entity_store/status.gen'; import { API_VERSIONS, APP_ID } from '../../../../../common/constants'; import type { EntityAnalyticsRoutesDeps } from '../../types'; import { checkAndInitAssetCriticalityResources } from '../../asset_criticality/check_and_init_asset_criticality_resources'; @@ -38,7 +40,11 @@ export const getEntityStoreStatusRoute = ( .addVersion( { version: API_VERSIONS.public.v1, - validate: {}, + validate: { + request: { + query: buildRouteValidationWithZod(GetEntityStoreStatusRequestQuery), + }, + }, }, async ( @@ -54,7 +60,7 @@ export const getEntityStoreStatusRoute = ( try { const body: GetEntityStoreStatusResponse = await secSol .getEntityStoreDataClient() - .status(); + .status(request.query); return response.ok({ body }); } catch (e) { diff --git a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts index 708b74277faa..3d103ea2af46 100644 --- a/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts +++ b/x-pack/plugins/security_solution/server/lib/entity_analytics/entity_store/task/field_retention_enrichment_task.ts @@ -13,7 +13,10 @@ import type { TaskManagerSetupContract, TaskManagerStartContract, } from '@kbn/task-manager-plugin/server'; -import type { EntityType } from '../../../../../common/api/entity_analytics/entity_store'; +import { + EngineComponentResourceEnum, + type EntityType, +} from '../../../../../common/api/entity_analytics/entity_store'; import { defaultState, stateSchemaByVersion, @@ -275,3 +278,37 @@ const createTaskRunnerFactory = }, }; }; + +export const getEntityStoreFieldRetentionEnrichTaskState = async ({ + namespace, + taskManager, +}: { + namespace: string; + taskManager: TaskManagerStartContract; +}) => { + const taskId = getTaskId(namespace); + try { + const taskState = await taskManager.get(taskId); + + return { + id: taskState.id, + resource: EngineComponentResourceEnum.task, + installed: true, + enabled: taskState.enabled, + status: taskState.status, + retryAttempts: taskState.attempts, + nextRun: taskState.runAt, + lastRun: taskState.state.lastExecutionTimestamp, + runs: taskState.state.runs, + }; + } catch (e) { + if (SavedObjectsErrorHelpers.isNotFoundError(e)) { + return { + id: taskId, + installed: false, + resource: EngineComponentResourceEnum.task, + }; + } + throw e; + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/get.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/get.ts index e6edb05b3a68..0d880484877f 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/get.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/get.ts @@ -38,7 +38,7 @@ export const registerSiemRuleMigrationsGetRoute = ( const ctx = await context.resolve(['securitySolution']); const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient(); - const migrationRules = await ruleMigrationsClient.data.rules.get(migrationId); + const migrationRules = await ruleMigrationsClient.data.rules.get({ migrationId }); return res.ok({ body: migrationRules }); } catch (err) { diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts index c6ea6b8bf897..601b156aee04 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/index.ts @@ -17,6 +17,8 @@ import { registerSiemRuleMigrationsStatsAllRoute } from './stats_all'; import { registerSiemRuleMigrationsResourceUpsertRoute } from './resources/upsert'; import { registerSiemRuleMigrationsResourceGetRoute } from './resources/get'; import { registerSiemRuleMigrationsRetryRoute } from './retry'; +import { registerSiemRuleMigrationsInstallRoute } from './rules/install'; +import { registerSiemRuleMigrationsInstallTranslatedRoute } from './rules/install_translated'; export const registerSiemRuleMigrationsRoutes = ( router: SecuritySolutionPluginRouter, @@ -30,6 +32,8 @@ export const registerSiemRuleMigrationsRoutes = ( registerSiemRuleMigrationsRetryRoute(router, logger); registerSiemRuleMigrationsStatsRoute(router, logger); registerSiemRuleMigrationsStopRoute(router, logger); + registerSiemRuleMigrationsInstallRoute(router, logger); + registerSiemRuleMigrationsInstallTranslatedRoute(router, logger); registerSiemRuleMigrationsResourceUpsertRoute(router, logger); registerSiemRuleMigrationsResourceGetRoute(router, logger); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/resources/upsert.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/resources/upsert.ts index be1f3e84c46e..645fa09b49dc 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/resources/upsert.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/resources/upsert.ts @@ -7,7 +7,6 @@ import type { IKibanaResponse, Logger } from '@kbn/core/server'; import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; -import type { RuleMigrationResource } from '../../../../../../common/siem_migrations/model/rule_migration.gen'; import { UpsertRuleMigrationResourcesRequestBody, UpsertRuleMigrationResourcesRequestParams, @@ -15,6 +14,7 @@ import { } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; import { SIEM_RULE_MIGRATION_RESOURCES_PATH } from '../../../../../../common/siem_migrations/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; +import type { CreateRuleMigrationResourceInput } from '../../data/rule_migrations_data_resources_client'; import { withLicense } from '../util/with_license'; export const registerSiemRuleMigrationsResourceUpsertRoute = ( @@ -49,7 +49,7 @@ export const registerSiemRuleMigrationsResourceUpsertRoute = ( const ctx = await context.resolve(['securitySolution']); const ruleMigrationsClient = ctx.securitySolution.getSiemRuleMigrationsClient(); - const ruleMigrations = resources.map<RuleMigrationResource>((resource) => ({ + const ruleMigrations = resources.map<CreateRuleMigrationResourceInput>((resource) => ({ migration_id: migrationId, ...resource, })); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/retry.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/retry.ts index 4406afc4333e..0fb96d9aaf72 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/retry.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/retry.ts @@ -50,7 +50,7 @@ export const registerSiemRuleMigrationsRetryRoute = ( const inferenceClient = ctx.securitySolution.getInferenceClient(); const actionsClient = ctx.actions.getActionsClient(); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const invocationConfig = { callbacks: [ diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install.ts new file mode 100644 index 000000000000..7e8b1a25a483 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { IKibanaResponse, Logger } from '@kbn/core/server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { SIEM_RULE_MIGRATION_INSTALL_PATH } from '../../../../../../common/siem_migrations/constants'; +import type { InstallMigrationRulesResponse } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { + InstallMigrationRulesRequestBody, + InstallMigrationRulesRequestParams, +} from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; +import { withLicense } from '../util/with_license'; +import { installTranslated } from '../util/installation'; + +export const registerSiemRuleMigrationsInstallRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + router.versioned + .post({ + path: SIEM_RULE_MIGRATION_INSTALL_PATH, + access: 'internal', + security: { authz: { requiredPrivileges: ['securitySolution'] } }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: buildRouteValidationWithZod(InstallMigrationRulesRequestParams), + body: buildRouteValidationWithZod(InstallMigrationRulesRequestBody), + }, + }, + }, + withLicense( + async (context, req, res): Promise<IKibanaResponse<InstallMigrationRulesResponse>> => { + const { migration_id: migrationId } = req.params; + const ids = req.body; + + try { + const ctx = await context.resolve(['core', 'alerting', 'securitySolution']); + + const securitySolutionContext = ctx.securitySolution; + const savedObjectsClient = ctx.core.savedObjects.client; + const rulesClient = await ctx.alerting.getRulesClient(); + + await installTranslated({ + migrationId, + ids, + securitySolutionContext, + savedObjectsClient, + rulesClient, + logger, + }); + + return res.ok({ body: { installed: true } }); + } catch (err) { + logger.error(err); + return res.badRequest({ body: err.message }); + } + } + ) + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install_translated.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install_translated.ts new file mode 100644 index 000000000000..6fd4b5f0980b --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/rules/install_translated.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 type { IKibanaResponse, Logger } from '@kbn/core/server'; +import { buildRouteValidationWithZod } from '@kbn/zod-helpers'; +import { SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH } from '../../../../../../common/siem_migrations/constants'; +import type { InstallTranslatedMigrationRulesResponse } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import { InstallTranslatedMigrationRulesRequestParams } from '../../../../../../common/siem_migrations/model/api/rules/rule_migration.gen'; +import type { SecuritySolutionPluginRouter } from '../../../../../types'; +import { withLicense } from '../util/with_license'; +import { installTranslated } from '../util/installation'; + +export const registerSiemRuleMigrationsInstallTranslatedRoute = ( + router: SecuritySolutionPluginRouter, + logger: Logger +) => { + router.versioned + .post({ + path: SIEM_RULE_MIGRATION_INSTALL_TRANSLATED_PATH, + access: 'internal', + security: { authz: { requiredPrivileges: ['securitySolution'] } }, + }) + .addVersion( + { + version: '1', + validate: { + request: { + params: buildRouteValidationWithZod(InstallTranslatedMigrationRulesRequestParams), + }, + }, + }, + withLicense( + async ( + context, + req, + res + ): Promise<IKibanaResponse<InstallTranslatedMigrationRulesResponse>> => { + const { migration_id: migrationId } = req.params; + + try { + const ctx = await context.resolve(['core', 'alerting', 'securitySolution']); + + const securitySolutionContext = ctx.securitySolution; + const savedObjectsClient = ctx.core.savedObjects.client; + const rulesClient = await ctx.alerting.getRulesClient(); + + await installTranslated({ + migrationId, + securitySolutionContext, + savedObjectsClient, + rulesClient, + logger, + }); + + return res.ok({ body: { installed: true } }); + } catch (err) { + logger.error(err); + return res.badRequest({ body: err.message }); + } + } + ) + ); +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/start.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/start.ts index 73ba2fd3cce7..e9369c0e8d19 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/start.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/start.ts @@ -50,7 +50,7 @@ export const registerSiemRuleMigrationsStartRoute = ( const inferenceClient = ctx.securitySolution.getInferenceClient(); const actionsClient = ctx.actions.getActionsClient(); const soClient = ctx.core.savedObjects.client; - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = await ctx.alerting.getRulesClient(); const invocationConfig = { callbacks: [ diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts new file mode 100644 index 000000000000..ee211e8a935d --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/api/util/installation.ts @@ -0,0 +1,223 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Logger, SavedObjectsClientContract } from '@kbn/core/server'; +import type { RulesClient } from '@kbn/alerting-plugin/server'; +import { + DEFAULT_TRANSLATION_RISK_SCORE, + DEFAULT_TRANSLATION_SEVERITY, +} from '../../../../../../common/siem_migrations/constants'; +import type { SecuritySolutionApiRequestHandlerContext } from '../../../../..'; +import { createPrebuiltRuleObjectsClient } from '../../../../detection_engine/prebuilt_rules/logic/rule_objects/prebuilt_rule_objects_client'; +import { performTimelinesInstallation } from '../../../../detection_engine/prebuilt_rules/logic/perform_timelines_installation'; +import { createPrebuiltRules } from '../../../../detection_engine/prebuilt_rules/logic/rule_objects/create_prebuilt_rules'; +import type { PrebuiltRuleAsset } from '../../../../detection_engine/prebuilt_rules'; +import { getRuleGroups } from '../../../../detection_engine/prebuilt_rules/model/rule_groups/get_rule_groups'; +import { fetchRuleVersionsTriad } from '../../../../detection_engine/prebuilt_rules/logic/rule_versions/fetch_rule_versions_triad'; +import { createPrebuiltRuleAssetsClient } from '../../../../detection_engine/prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_client'; +import type { IDetectionRulesClient } from '../../../../detection_engine/rule_management/logic/detection_rules_client/detection_rules_client_interface'; +import type { RuleCreateProps } from '../../../../../../common/api/detection_engine'; +import type { UpdateRuleMigrationInput } from '../../data/rule_migrations_data_rules_client'; +import type { StoredRuleMigration } from '../../types'; + +const installPrebuiltRules = async ( + rulesToInstall: StoredRuleMigration[], + securitySolutionContext: SecuritySolutionApiRequestHandlerContext, + rulesClient: RulesClient, + savedObjectsClient: SavedObjectsClientContract, + detectionRulesClient: IDetectionRulesClient +): Promise<UpdateRuleMigrationInput[]> => { + const ruleAssetsClient = createPrebuiltRuleAssetsClient(savedObjectsClient); + const ruleObjectsClient = createPrebuiltRuleObjectsClient(rulesClient); + const ruleVersionsMap = await fetchRuleVersionsTriad({ + ruleAssetsClient, + ruleObjectsClient, + }); + const { currentRules, installableRules } = getRuleGroups(ruleVersionsMap); + + const rulesToUpdate: UpdateRuleMigrationInput[] = []; + const assetsToInstall: PrebuiltRuleAsset[] = []; + rulesToInstall.forEach((ruleToInstall) => { + // If prebuilt rule has already been install, then just update migration rule with the installed rule id + const installedRule = currentRules.find( + (rule) => rule.rule_id === ruleToInstall.elastic_rule?.prebuilt_rule_id + ); + if (installedRule) { + rulesToUpdate.push({ + id: ruleToInstall.id, + elastic_rule: { + id: installedRule.id, + }, + }); + return; + } + + // If prebuilt rule is not installed, then keep reference to install it + const installableRule = installableRules.find( + (rule) => rule.rule_id === ruleToInstall.elastic_rule?.prebuilt_rule_id + ); + if (installableRule) { + assetsToInstall.push(installableRule); + } + }); + + // Filter out any duplicates which can occur when multiple translated rules matched the same prebuilt rule + const filteredAssetsToInstall = assetsToInstall.filter( + (value, index, self) => index === self.findIndex((rule) => rule.rule_id === value.rule_id) + ); + + // TODO: we need to do an error handling which can happen during the rule installation + const { results: installedRules } = await createPrebuiltRules( + detectionRulesClient, + filteredAssetsToInstall + ); + await performTimelinesInstallation(securitySolutionContext); + + installedRules.forEach((installedRule) => { + const rules = rulesToInstall.filter( + (rule) => rule.elastic_rule?.prebuilt_rule_id === installedRule.result.rule_id + ); + rules.forEach((prebuiltRule) => { + rulesToUpdate.push({ + id: prebuiltRule.id, + elastic_rule: { + id: installedRule.result.id, + }, + }); + }); + }); + + return rulesToUpdate; +}; + +const installCustomRules = async ( + rulesToInstall: StoredRuleMigration[], + detectionRulesClient: IDetectionRulesClient, + logger: Logger +): Promise<UpdateRuleMigrationInput[]> => { + const rulesToUpdate: UpdateRuleMigrationInput[] = []; + await Promise.all( + rulesToInstall.map(async (rule) => { + if (!rule.elastic_rule?.query || !rule.elastic_rule?.description) { + return; + } + try { + const payloadRule: RuleCreateProps = { + type: 'esql', + language: 'esql', + query: rule.elastic_rule.query, + name: rule.elastic_rule.title, + description: rule.elastic_rule.description, + severity: DEFAULT_TRANSLATION_SEVERITY, + risk_score: DEFAULT_TRANSLATION_RISK_SCORE, + }; + const createdRule = await detectionRulesClient.createCustomRule({ + params: payloadRule, + }); + rulesToUpdate.push({ + id: rule.id, + elastic_rule: { + id: createdRule.id, + }, + }); + } catch (err) { + // TODO: we need to do an error handling which can happen during the rule creation + logger.debug(`Could not create a rule because of error: ${JSON.stringify(err)}`); + } + }) + ); + return rulesToUpdate; +}; + +interface InstallTranslatedProps { + /** + * The migration id + */ + migrationId: string; + + /** + * If specified, then installable translated rules in theThe list will be installed, + * otherwise all installable translated rules will be installed. + */ + ids?: string[]; + + /** + * The security solution context + */ + securitySolutionContext: SecuritySolutionApiRequestHandlerContext; + + /** + * The rules client to create rules + */ + rulesClient: RulesClient; + + /** + * The saved objects client + */ + savedObjectsClient: SavedObjectsClientContract; + + /** + * The logger + */ + logger: Logger; +} + +export const installTranslated = async ({ + migrationId, + ids, + securitySolutionContext, + rulesClient, + savedObjectsClient, + logger, +}: InstallTranslatedProps) => { + const detectionRulesClient = securitySolutionContext.getDetectionRulesClient(); + const ruleMigrationsClient = securitySolutionContext.getSiemRuleMigrationsClient(); + + const rulesToInstall = await ruleMigrationsClient.data.rules.get({ + migrationId, + ids, + installable: true, + }); + + const { customRulesToInstall, prebuiltRulesToInstall } = rulesToInstall.reduce( + (acc, item) => { + if (item.elastic_rule?.prebuilt_rule_id) { + acc.prebuiltRulesToInstall.push(item); + } else { + acc.customRulesToInstall.push(item); + } + return acc; + }, + { customRulesToInstall: [], prebuiltRulesToInstall: [] } as { + customRulesToInstall: StoredRuleMigration[]; + prebuiltRulesToInstall: StoredRuleMigration[]; + } + ); + + const updatedPrebuiltRules = await installPrebuiltRules( + prebuiltRulesToInstall, + securitySolutionContext, + rulesClient, + savedObjectsClient, + detectionRulesClient + ); + + const updatedCustomRules = await installCustomRules( + customRulesToInstall, + detectionRulesClient, + logger + ); + + const rulesToUpdate: UpdateRuleMigrationInput[] = [ + ...updatedPrebuiltRules, + ...updatedCustomRules, + ]; + + if (rulesToUpdate.length) { + await ruleMigrationsClient.data.rules.update(rulesToUpdate); + } +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_resources_client.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_resources_client.ts index 66b463da79cc..888a41aca944 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_resources_client.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_resources_client.ts @@ -14,23 +14,35 @@ import type { import type { StoredRuleMigrationResource } from '../types'; import { RuleMigrationsDataBaseClient } from './rule_migrations_data_base_client'; +export type CreateRuleMigrationResourceInput = Omit<RuleMigrationResource, 'id'>; + /* BULK_MAX_SIZE defines the number to break down the bulk operations by. * The 500 number was chosen as a reasonable number to avoid large payloads. It can be adjusted if needed. */ const BULK_MAX_SIZE = 500 as const; export class RuleMigrationsDataResourcesClient extends RuleMigrationsDataBaseClient { - public async upsert(resources: RuleMigrationResource[]): Promise<void> { + public async upsert(resources: CreateRuleMigrationResourceInput[]): Promise<void> { const index = await this.getIndexName(); - let resourcesSlice: RuleMigrationResource[]; + let resourcesSlice: CreateRuleMigrationResourceInput[]; + + const createdAt = new Date().toISOString(); while ((resourcesSlice = resources.splice(0, BULK_MAX_SIZE)).length > 0) { await this.esClient .bulk({ refresh: 'wait_for', operations: resourcesSlice.flatMap((resource) => [ { update: { _id: this.createId(resource), _index: index } }, - { doc: resource, doc_as_upsert: true }, + { + doc: { + ...resource, + '@timestamp': createdAt, + updated_by: this.username, + updated_at: createdAt, + }, + doc_as_upsert: true, + }, ]), }) .catch((error) => { @@ -65,7 +77,7 @@ export class RuleMigrationsDataResourcesClient extends RuleMigrationsDataBaseCli }); } - private createId(resource: RuleMigrationResource): string { + private createId(resource: CreateRuleMigrationResourceInput): string { const key = `${resource.migration_id}-${resource.type}-${resource.name}`; return sha256.create().update(key).hex(); } diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts index a01d36e9a119..0a82e2c31190 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/data/rule_migrations_data_rules_client.ts @@ -6,8 +6,10 @@ */ import type { + AggregationsAggregationContainer, AggregationsFilterAggregate, AggregationsMaxAggregate, + AggregationsMinAggregate, AggregationsStringTermsAggregate, AggregationsStringTermsBucket, QueryDslQueryContainer, @@ -30,7 +32,14 @@ export type UpdateRuleMigrationInput = { elastic_rule?: Partial<ElasticRule> } & 'id' | 'translation_result' | 'comments' >; export type RuleMigrationDataStats = Omit<RuleMigrationTaskStats, 'status'>; -export type RuleMigrationAllDataStats = Array<RuleMigrationDataStats & { migration_id: string }>; +export type RuleMigrationAllDataStats = RuleMigrationDataStats[]; + +export interface RuleMigrationFilterOptions { + migrationId: string; + status?: SiemMigrationStatus | SiemMigrationStatus[]; + ids?: string[]; + installable?: boolean; +} /* BULK_MAX_SIZE defines the number to break down the bulk operations by. * The 500 number was chosen as a reasonable number to avoid large payloads. It can be adjusted if needed. @@ -99,9 +108,9 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient } /** Retrieves an array of rule documents of a specific migrations */ - async get(migrationId: string): Promise<StoredRuleMigration[]> { + async get(filters: RuleMigrationFilterOptions): Promise<StoredRuleMigration[]> { const index = await this.getIndexName(); - const query = this.getFilterQuery(migrationId); + const query = this.getFilterQuery(filters); const storedRuleMigrations = await this.esClient .search<RuleMigration>({ index, query, sort: '_doc' }) @@ -121,7 +130,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient */ async takePending(migrationId: string, size: number): Promise<StoredRuleMigration[]> { const index = await this.getIndexName(); - const query = this.getFilterQuery(migrationId, SiemMigrationStatus.PENDING); + const query = this.getFilterQuery({ migrationId, status: SiemMigrationStatus.PENDING }); const storedRuleMigrations = await this.esClient .search<RuleMigration>({ index, query, sort: '_doc', size }) @@ -200,7 +209,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient { refresh = false }: { refresh?: boolean } = {} ): Promise<void> { const index = await this.getIndexName(); - const query = this.getFilterQuery(migrationId, statusToQuery); + const query = this.getFilterQuery({ migrationId, status: statusToQuery }); const script = { source: `ctx._source['status'] = '${statusToUpdate}'` }; await this.esClient.updateByQuery({ index, query, script, refresh }).catch((error) => { this.logger.error(`Error updating rule migrations status: ${error.message}`); @@ -211,12 +220,13 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient /** Retrieves the stats for the rule migrations with the provided id */ async getStats(migrationId: string): Promise<RuleMigrationDataStats> { const index = await this.getIndexName(); - const query = this.getFilterQuery(migrationId); + const query = this.getFilterQuery({ migrationId }); const aggregations = { pending: { filter: { term: { status: SiemMigrationStatus.PENDING } } }, processing: { filter: { term: { status: SiemMigrationStatus.PROCESSING } } }, completed: { filter: { term: { status: SiemMigrationStatus.COMPLETED } } }, failed: { filter: { term: { status: SiemMigrationStatus.FAILED } } }, + createdAt: { min: { field: '@timestamp' } }, lastUpdatedAt: { max: { field: 'updated_at' } }, }; const result = await this.esClient @@ -226,30 +236,33 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient throw error; }); - const { pending, processing, completed, lastUpdatedAt, failed } = result.aggregations ?? {}; + const bucket = result.aggregations ?? {}; return { + id: migrationId, rules: { total: this.getTotalHits(result), - pending: (pending as AggregationsFilterAggregate)?.doc_count ?? 0, - processing: (processing as AggregationsFilterAggregate)?.doc_count ?? 0, - completed: (completed as AggregationsFilterAggregate)?.doc_count ?? 0, - failed: (failed as AggregationsFilterAggregate)?.doc_count ?? 0, + pending: (bucket.pending as AggregationsFilterAggregate)?.doc_count ?? 0, + processing: (bucket.processing as AggregationsFilterAggregate)?.doc_count ?? 0, + completed: (bucket.completed as AggregationsFilterAggregate)?.doc_count ?? 0, + failed: (bucket.failed as AggregationsFilterAggregate)?.doc_count ?? 0, }, - last_updated_at: (lastUpdatedAt as AggregationsMaxAggregate)?.value_as_string, + created_at: (bucket.createdAt as AggregationsMinAggregate)?.value_as_string ?? '', + last_updated_at: (bucket.lastUpdatedAt as AggregationsMaxAggregate)?.value_as_string ?? '', }; } - /** Retrieves the stats for all the rule migrations aggregated by migration id */ + /** Retrieves the stats for all the rule migrations aggregated by migration id, in creation order */ async getAllStats(): Promise<RuleMigrationAllDataStats> { const index = await this.getIndexName(); - const aggregations = { + const aggregations: { migrationIds: AggregationsAggregationContainer } = { migrationIds: { - terms: { field: 'migration_id' }, + terms: { field: 'migration_id', order: { createdAt: 'asc' } }, aggregations: { pending: { filter: { term: { status: SiemMigrationStatus.PENDING } } }, processing: { filter: { term: { status: SiemMigrationStatus.PROCESSING } } }, completed: { filter: { term: { status: SiemMigrationStatus.COMPLETED } } }, failed: { filter: { term: { status: SiemMigrationStatus.FAILED } } }, + createdAt: { min: { field: '@timestamp' } }, lastUpdatedAt: { max: { field: 'updated_at' } }, }, }, @@ -264,7 +277,7 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient const migrationsAgg = result.aggregations?.migrationIds as AggregationsStringTermsAggregate; const buckets = (migrationsAgg?.buckets as AggregationsStringTermsBucket[]) ?? []; return buckets.map((bucket) => ({ - migration_id: bucket.key, + id: bucket.key, rules: { total: bucket.doc_count, pending: bucket.pending?.doc_count ?? 0, @@ -272,14 +285,17 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient completed: bucket.completed?.doc_count ?? 0, failed: bucket.failed?.doc_count ?? 0, }, + created_at: bucket.createdAt?.value_as_string, last_updated_at: bucket.lastUpdatedAt?.value_as_string, })); } - private getFilterQuery( - migrationId: string, - status?: SiemMigrationStatus | SiemMigrationStatus[] - ): QueryDslQueryContainer { + private getFilterQuery({ + migrationId, + status, + ids, + installable, + }: RuleMigrationFilterOptions): QueryDslQueryContainer { const filter: QueryDslQueryContainer[] = [{ term: { migration_id: migrationId } }]; if (status) { if (Array.isArray(status)) { @@ -288,6 +304,20 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient filter.push({ term: { status } }); } } + if (ids) { + filter.push({ terms: { _id: ids } }); + } + if (installable) { + filter.push( + { term: { translation_result: 'full' } }, + { + nested: { + path: 'elastic_rule', + query: { bool: { must_not: { exists: { field: 'elastic_rule.id' } } } }, + }, + } + ); + } return { bool: { filter } }; } } diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.test.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.test.ts new file mode 100644 index 000000000000..eece827726a3 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.test.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { InferenceClient } from '@kbn/inference-plugin/server'; +import type { + ActionsClientChatOpenAI, + ActionsClientSimpleChatModel, +} from '@kbn/langchain/server/language_models'; +import { loggerMock } from '@kbn/logging-mocks'; +import { FakeLLM } from '@langchain/core/utils/testing'; +import type { IntegrationRetriever } from '../util/integration_retriever'; +import type { PrebuiltRulesMapByName } from '../util/prebuilt_rules'; +import type { RuleResourceRetriever } from '../util/rule_resource_retriever'; +import { getRuleMigrationAgent } from './graph'; + +describe('getRuleMigrationAgent', () => { + const model = new FakeLLM({ + response: JSON.stringify({}, null, 2), + }) as unknown as ActionsClientChatOpenAI | ActionsClientSimpleChatModel; + + const inferenceClient = {} as InferenceClient; + const connectorId = 'draw_graphs'; + const prebuiltRulesMap = {} as PrebuiltRulesMapByName; + const resourceRetriever = {} as RuleResourceRetriever; + const integrationRetriever = {} as IntegrationRetriever; + const logger = loggerMock.create(); + + it('Ensures that the graph compiles', async () => { + try { + await getRuleMigrationAgent({ + model, + inferenceClient, + prebuiltRulesMap, + resourceRetriever, + integrationRetriever, + connectorId, + logger, + }); + } catch (error) { + throw Error(`getRuleMigrationAgent threw an error: ${error}`); + } + }); +}); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.ts index 0ec705a9268d..4ce5e2d87a3f 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/graph.ts @@ -20,7 +20,7 @@ export function getRuleMigrationAgent({ connectorId, logger, }: MigrateRuleGraphParams) { - const matchPrebuiltRuleNode = getMatchPrebuiltRuleNode({ model, prebuiltRulesMap, logger }); + const matchPrebuiltRuleNode = getMatchPrebuiltRuleNode({ model, prebuiltRulesMap }); const translationSubGraph = getTranslateRuleGraph({ model, inferenceClient, @@ -30,16 +30,16 @@ export function getRuleMigrationAgent({ logger, }); - const translateRuleGraph = new StateGraph(migrateRuleState) + const siemMigrationAgentGraph = new StateGraph(migrateRuleState) // Nodes .addNode('matchPrebuiltRule', matchPrebuiltRuleNode) - .addNode('translation', translationSubGraph) + .addNode('translationSubGraph', translationSubGraph) // Edges .addEdge(START, 'matchPrebuiltRule') .addConditionalEdges('matchPrebuiltRule', matchedPrebuiltRuleConditional) - .addEdge('translation', END); + .addEdge('translationSubGraph', END); - const graph = translateRuleGraph.compile(); + const graph = siemMigrationAgentGraph.compile(); graph.name = 'Rule Migration Graph'; // Customizes the name displayed in LangSmith return graph; } @@ -48,5 +48,5 @@ const matchedPrebuiltRuleConditional = (state: MigrateRuleState) => { if (state.elastic_rule?.prebuilt_rule_id) { return END; } - return 'translation'; + return 'translationSubGraph'; }; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/match_prebuilt_rule.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/match_prebuilt_rule.ts index 4a0404acf653..8f0460165f29 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/match_prebuilt_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/match_prebuilt_rule.ts @@ -5,17 +5,20 @@ * 2.0. */ -import type { Logger } from '@kbn/core/server'; -import { StringOutputParser } from '@langchain/core/output_parsers'; +import { JsonOutputParser } from '@langchain/core/output_parsers'; +import { SiemMigrationRuleTranslationResult } from '../../../../../../../../common/siem_migrations/constants'; import type { ChatModel } from '../../../util/actions_client_chat'; -import type { GraphNode } from '../../types'; import { filterPrebuiltRules, type PrebuiltRulesMapByName } from '../../../util/prebuilt_rules'; +import type { GraphNode } from '../../types'; import { MATCH_PREBUILT_RULE_PROMPT } from './prompts'; interface GetMatchPrebuiltRuleNodeParams { model: ChatModel; prebuiltRulesMap: PrebuiltRulesMapByName; - logger: Logger; +} + +interface GetMatchedRuleResponse { + match: string; } export const getMatchPrebuiltRuleNode = @@ -25,34 +28,33 @@ export const getMatchPrebuiltRuleNode = if (!mitreAttackIds?.length) { return {}; } + const filteredPrebuiltRulesMap = filterPrebuiltRules(prebuiltRulesMap, mitreAttackIds); if (filteredPrebuiltRulesMap.size === 0) { return {}; } - const outputParser = new StringOutputParser(); + const outputParser = new JsonOutputParser(); const matchPrebuiltRule = MATCH_PREBUILT_RULE_PROMPT.pipe(model).pipe(outputParser); - const elasticSecurityRules = Array(filteredPrebuiltRulesMap.keys()).join('\n'); - const response = await matchPrebuiltRule.invoke({ + const elasticSecurityRules = [...filteredPrebuiltRulesMap.keys()].join('\n'); + const response = (await matchPrebuiltRule.invoke({ elasticSecurityRules, ruleTitle: state.original_rule.title, - }); - const cleanResponse = response.trim(); - if (cleanResponse === 'no_match') { - return {}; - } - - const result = filteredPrebuiltRulesMap.get(cleanResponse); - if (result != null) { - return { - elastic_rule: { - title: result.rule.name, - description: result.rule.description, - prebuilt_rule_id: result.rule.rule_id, - id: result.installedRuleId, - }, - }; + })) as GetMatchedRuleResponse; + if (response.match) { + const result = filteredPrebuiltRulesMap.get(response.match); + if (result != null) { + return { + elastic_rule: { + title: result.rule.name, + description: result.rule.description, + prebuilt_rule_id: result.rule.rule_id, + id: result.installedRuleId, + }, + translation_result: SiemMigrationRuleTranslationResult.FULL, + }; + } } return {}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/prompts.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/prompts.ts index 434636d0519b..ab5d7383e27d 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/prompts.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/nodes/match_prebuilt_rule/prompts.ts @@ -11,25 +11,39 @@ export const MATCH_PREBUILT_RULE_PROMPT = ChatPromptTemplate.fromMessages([ 'system', `You are an expert assistant in Cybersecurity, your task is to help migrating a SIEM detection rule, from Splunk Security to Elastic Security. You will be provided with a Splunk Detection Rule name by the user, your goal is to try find an Elastic Detection Rule that covers the same threat, if any. -The list of Elastic Detection Rules suggested is provided in the context below. +Here are some context for you to reference for your task, read it carefully as you will get questions about it later: -Guidelines: -If there is no Elastic rule in the list that covers the same threat, answer only with the string: no_match -If there is one Elastic rule in the list that covers the same threat, answer only with its name without any further explanation. -If there are multiple rules in the list that cover the same threat, answer with the most specific of them, for example: "Linux User Account Creation" is more specific than "User Account Creation". - -<ELASTIC_DETECTION_RULE_NAMES> +<context> +<elastic_detection_rule_names> {elasticSecurityRules} -</ELASTIC_DETECTION_RULE_NAMES> +</elastic_detection_rule_names> +</context> `, ], [ 'human', - `The Splunk Detection Rule is: -<<SPLUNK_RULE_TITLE>> + `See the below description of the relevant splunk rule and try to match it with any of the elastic detection rules with similar names. +<splunk_rule_name> {ruleTitle} -<<SPLUNK_RULE_TITLE>> +</splunk_rule_name> + +<guidelines> +- Always reply with a JSON object with the key "match" and the value being the most relevant matched elastic detection rule name. Do not reply with anything else. +- Only reply with exact matches, if you are unsure or do not find a very confident match, always reply with an empty string value in the match key, do not guess or reply with anything else. +- If there is one Elastic rule in the list that covers the same threat, set the name of the matching rule as a value of the match key. Do not reply with anything else. +- If there are multiple rules in the list that cover the same threat, answer with the most specific of them, for example: "Linux User Account Creation" is more specific than "User Account Creation". +</guidelines> + +<example_response> +U: <splunk_rule_name> +Linux Auditd Add User Account Type +</splunk_rule_name> +A: Please find the match JSON object below: +\`\`\`json +{{"match": "Linux User Account Creation"}} +\`\`\` +</example_response> `, ], - ['ai', 'Please find the answer below:'], + ['ai', 'Please find the match JSON object below:'], ]); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/graph.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/graph.ts index f986098e9deb..32f41e54619b 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/graph.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/graph.ts @@ -6,11 +6,18 @@ */ import { END, START, StateGraph } from '@langchain/langgraph'; +import { isEmpty } from 'lodash/fp'; +import { SiemMigrationRuleTranslationResult } from '../../../../../../../../common/siem_migrations/constants'; +import { getFixQueryErrorsNode } from './nodes/fix_query_errors'; import { getProcessQueryNode } from './nodes/process_query'; import { getRetrieveIntegrationsNode } from './nodes/retrieve_integrations'; import { getTranslateRuleNode } from './nodes/translate_rule'; +import { getValidationNode } from './nodes/validation'; import { translateRuleState } from './state'; -import type { TranslateRuleGraphParams } from './types'; +import type { TranslateRuleGraphParams, TranslateRuleState } from './types'; + +// How many times we will try to self-heal when validation fails, to prevent infinite graph recursions +const MAX_VALIDATION_ITERATIONS = 3; export function getTranslateRuleGraph({ model, @@ -35,19 +42,37 @@ export function getTranslateRuleGraph({ model, integrationRetriever, }); + const validationNode = getValidationNode({ logger }); + const fixQueryErrorsNode = getFixQueryErrorsNode({ inferenceClient, connectorId, logger }); const translateRuleGraph = new StateGraph(translateRuleState) // Nodes .addNode('processQuery', processQueryNode) .addNode('retrieveIntegrations', retrieveIntegrationsNode) .addNode('translateRule', translateRuleNode) + .addNode('validation', validationNode) + .addNode('fixQueryErrors', fixQueryErrorsNode) // Edges .addEdge(START, 'processQuery') .addEdge('processQuery', 'retrieveIntegrations') .addEdge('retrieveIntegrations', 'translateRule') - .addEdge('translateRule', END); + .addEdge('translateRule', 'validation') + .addEdge('fixQueryErrors', 'validation') + .addConditionalEdges('validation', validationRouter); const graph = translateRuleGraph.compile(); graph.name = 'Translate Rule Graph'; return graph; } + +const validationRouter = (state: TranslateRuleState) => { + if ( + state.validation_errors.iterations <= MAX_VALIDATION_ITERATIONS && + state.translation_result === SiemMigrationRuleTranslationResult.FULL + ) { + if (!isEmpty(state.validation_errors?.esql_errors)) { + return 'fixQueryErrors'; + } + } + return END; +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/fix_query_errors.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/fix_query_errors.ts new file mode 100644 index 000000000000..a21aceee70f9 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/fix_query_errors.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Logger } from '@kbn/core/server'; +import type { InferenceClient } from '@kbn/inference-plugin/server'; +import { getEsqlKnowledgeBase } from '../../../../../util/esql_knowledge_base_caller'; +import type { GraphNode } from '../../types'; +import { RESOLVE_ESQL_ERRORS_TEMPLATE } from './prompts'; + +interface GetFixQueryErrorsNodeParams { + inferenceClient: InferenceClient; + connectorId: string; + logger: Logger; +} + +export const getFixQueryErrorsNode = ({ + inferenceClient, + connectorId, + logger, +}: GetFixQueryErrorsNodeParams): GraphNode => { + const esqlKnowledgeBaseCaller = getEsqlKnowledgeBase({ inferenceClient, connectorId, logger }); + return async (state) => { + const rule = state.elastic_rule; + const prompt = await RESOLVE_ESQL_ERRORS_TEMPLATE.format({ + esql_errors: state.validation_errors.esql_errors, + esql_query: rule.query, + }); + const response = await esqlKnowledgeBaseCaller(prompt); + + const esqlQuery = response.match(/```esql\n([\s\S]*?)\n```/)?.[1] ?? ''; + rule.query = esqlQuery; + return { elastic_rule: rule }; + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/index.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/index.ts new file mode 100644 index 000000000000..a80533167538 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { getFixQueryErrorsNode } from './fix_query_errors'; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/prompts.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/prompts.ts new file mode 100644 index 000000000000..ca5fe67097d1 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/fix_query_errors/prompts.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ChatPromptTemplate } from '@langchain/core/prompts'; + +export const RESOLVE_ESQL_ERRORS_TEMPLATE = + ChatPromptTemplate.fromTemplate(`You are a helpful cybersecurity (SIEM) expert agent. Your task is to resolve the errors in the Elasticsearch Query Language (ES|QL) query provided by the user. + +Below is the relevant errors related to the ES|SQL query: + +<context> +<esql_errors> +{esql_errors} +</esql_errors> +<esql_query> +{esql_query} +</esql_query> +</context> + +<guidelines> +- You will be provided with the currentl ES|QL query and its related errors. +- Try to resolve the errors in the ES|QL query as best as you can to make it work. +- You must respond only with the modified query inside a \`\`\`esql code block, nothing else similar to the example response below. +</guidelines> + +<example_response> +A: Please find the modified ES|QL query below: +\`\`\`esql +FROM logs-endpoint.events.process-* +| WHERE process.executable LIKE \"%chown root%\" +| STATS count = COUNT(*), firstTime = MIN(@timestamp), lastTime = MAX(@timestamp) BY process.executable, + process.command_line, + host.name +| EVAL firstTime = TO_DATETIME(firstTime), lastTime = TO_DATETIME(lastTime) +\`\`\` +</example_response> + +`); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/process_query.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/process_query.ts index 0f90d74dafba..ae0e93ee0c4b 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/process_query.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/process_query.ts @@ -10,7 +10,7 @@ import { isEmpty } from 'lodash/fp'; import type { ChatModel } from '../../../../../util/actions_client_chat'; import type { RuleResourceRetriever } from '../../../../../util/rule_resource_retriever'; import type { GraphNode } from '../../types'; -import { getReplaceQueryResourcesPrompt } from './prompts'; +import { REPLACE_QUERY_RESOURCE_PROMPT, getResourcesContext } from './prompts'; interface GetProcessQueryNodeParams { model: ChatModel; @@ -25,9 +25,19 @@ export const getProcessQueryNode = ({ let query = state.original_rule.query; const resources = await resourceRetriever.getResources(state.original_rule); if (!isEmpty(resources)) { - const replaceQueryResourcesPrompt = getReplaceQueryResourcesPrompt(state, resources); - const stringParser = new StringOutputParser(); - query = await model.pipe(stringParser).invoke(replaceQueryResourcesPrompt); + const replaceQueryParser = new StringOutputParser(); + const replaceQueryResourcePrompt = + REPLACE_QUERY_RESOURCE_PROMPT.pipe(model).pipe(replaceQueryParser); + const resourceContext = getResourcesContext(resources); + const response = await replaceQueryResourcePrompt.invoke({ + query: state.original_rule.query, + macros: resourceContext.macros, + lookup_tables: resourceContext.lists, + }); + const splQuery = response.match(/```spl\n([\s\S]*?)\n```/)?.[1] ?? ''; + if (splQuery) { + query = splQuery; + } } return { inline_query: query }; }; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/prompts.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/prompts.ts index 5d2e6648c1d8..b4c6b0e74aaa 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/prompts.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/process_query/prompts.ts @@ -5,119 +5,153 @@ * 2.0. */ +import { ChatPromptTemplate } from '@langchain/core/prompts'; import type { RuleMigrationResources } from '../../../../../util/rule_resource_retriever'; -import type { TranslateRuleState } from '../../types'; -const getResourcesContext = (resources: RuleMigrationResources): string => { - const resourcesContext = []; +interface ResourceContext { + macros: string; + lists: string; +} + +export const getResourcesContext = (resources: RuleMigrationResources): ResourceContext => { + const result: ResourceContext = { macros: '', lists: '' }; + + // Process macros if (resources.macro?.length) { - const macrosSummary = resources.macro - .map((macro) => `\`${macro.name}\`: ${macro.content}`) - .join('\n'); - resourcesContext.push('<<MACROS>>', macrosSummary, '<</MACROS>>'); + const macrosMap = resources.macro.reduce((acc, macro) => { + acc[macro.name] = macro.content; + return acc; + }, {} as Record<string, string>); + + result.macros = JSON.stringify(macrosMap, null, 2); } + + // Process lists if (resources.list?.length) { - const lookupsSummary = resources.list - .map((list) => `lookup ${list.name}: ${list.content}`) - .join('\n'); - resourcesContext.push('<<LOOKUP_TABLES>>', lookupsSummary, '<</LOOKUP_TABLES>>'); + const listsMap = resources.list.reduce((acc, list) => { + acc[list.name] = list.content; + return acc; + }, {} as Record<string, string>); + + result.lists = JSON.stringify(listsMap, null, 2); } - return resourcesContext.join('\n'); + + return result; }; -export const getReplaceQueryResourcesPrompt = ( - state: TranslateRuleState, - resources: RuleMigrationResources -): string => { - const resourcesContext = getResourcesContext(resources); - return `You are an agent expert in Splunk SPL (Search Processing Language). +export const REPLACE_QUERY_RESOURCE_PROMPT = ChatPromptTemplate.fromMessages([ + [ + 'system', + `You are an agent expert in Splunk SPL (Search Processing Language). Your task is to inline a set of macros and lookup tables syntax using their values in a SPL query. +Here are some context for you to reference for your task, read it carefully as you will get questions about it later: -# Guidelines -- You will be provided with a SPL query and also the resources reference with the values of macros and lookup tables. -- You have to replace the macros and lookup tables syntax in the SPL query and use their values inline, if provided. -- The original and modified queries must be equivalent. - -# Process -- Go through the SPL query and identify all the macros and lookup tables that are used. Two scenarios may arise: - - The macro or lookup table is provided in the resources: Replace it using its actual content. - - The macro or lookup table is not provided in the resources: Do not replace it, keep it in the query as it is. +<context> +<macro_guidelines> -## Macros replacements - -### Notes: +Always follow the below guidelines when replacing macros: - Macros names have the number of arguments in parentheses, e.g., \`macroName(2)\`. You must replace the correct macro accounting for the number of arguments. -### Example: - Having the following macros: - \`someSource\`: sourcetype="somesource" - \`searchTitle(1)\`: search title="$value$" - \`searchTitle\`: search title=* - \`searchType\`: search type=* - And the following SPL query: - \`\`\`spl - \`someSource\` \`someFilter\` - | \`searchTitle("sometitle")\` - | \`searchType("sometype")\` - | table * - \`\`\` - The correct replacement would be: - \`\`\`spl - sourcetype="somesource" \`someFilter\` - | search title="sometitle" - | \`searchType("sometype")\` - | table * - \`\`\` - -## Lookups replacements - -### Notes: +Having the following macros: + \`someSource\`: sourcetype="somesource" + \`searchTitle(1)\`: search title="$value$" + \`searchTitle\`: search title=* + \`searchType\`: search type=* +And the following SPL query: + \`\`\`spl + \`someSource\` \`someFilter\` + | \`searchTitle("sometitle")\` + | \`searchType("sometype")\` + | table * + \`\`\` +The correct replacement would be: + \`\`\`spl + sourcetype="somesource" \`someFilter\` + | search title="sometitle" + | \`searchType("sometype")\` + | table * + \`\`\` +</macro_guidelines> + +<lookup_guidelines> +Always follow the below guidelines when replacing lookup tables: - OUTPUTNEW and OUTPUT fields should be replaced with the values from the lookup table. - Use the \`case\` function to evaluate conditions in the same order provided by the lookup table. - Ensure all lookup matching fields are correctly matched to their respective case conditions. - If there are more than one field to match, use the \`AND\` operator to combine them inside the \`case\` function. - The transformed SPL query should function equivalently to the original query with the \`lookup\` command. -### Example: - Having the following lookup table: - uid,username,department - 1066,Claudia Garcia,Engineering - 1690,Rutherford Sullivan,Engineering - 1815,Vanya Patel,IT - 1862,Wei Zhang,Engineering - 1916,Alex Martin,Personnel - And the following SPL query: - \`\`\`spl - ... | lookup users uid OUTPUTNEW username, department - \`\`\` - The correct replacement would be: - \`\`\`spl - ... | eval username=case(uid=1066, "Claudia Garcia", - uid=1690, "Rutherford Sullivan", - uid=1815, "Vanya Patel", - uid=1862, "Wei Zhang", - uid=1916, "Alex Martin", - true, null), - department=case(uid=1066, "Engineering", - uid=1690, "Engineering", - uid=1815, "IT", - uid=1862, "Engineering", - uid=1916, "Personnel", - true, null) - \`\`\` - - -## Important: You must respond only with the modified query inside a \`\`\`spl code block, nothing else. - -# Find the macros and lookup tables below: - -${resourcesContext} - -# Find the SPL query below: +Having the following lookup table: + uid,username,department + 1066,Claudia Garcia,Engineering + 1690,Rutherford Sullivan,Engineering + 1815,Vanya Patel,IT + 1862,Wei Zhang,Engineering + 1916,Alex Martin,Personnel +And the following SPL query: + \`\`\`spl + ... | lookup users uid OUTPUTNEW username, department + \`\`\` +The correct replacement would be: + \`\`\`spl + ... | eval username=case(uid=1066, "Claudia Garcia", + uid=1690, "Rutherford Sullivan", + uid=1815, "Vanya Patel", + uid=1862, "Wei Zhang", + uid=1916, "Alex Martin", + true, null), + department=case(uid=1066, "Engineering", + uid=1690, "Engineering", + uid=1815, "IT", + uid=1862, "Engineering", + uid=1916, "Personnel", + true, null) + \`\`\` +</lookup_guidelines> +</context>`, + ], + [ + 'human', + `Go through the SPL query and identify all the macros and lookup tables that are used. +<macros> +{macros} +</macros> +<lookup_tables> +{lookup_tables} +</lookup_tables> + +<spl_query> \`\`\`spl -${state.original_rule.query} +{query} \`\`\` +</spl_query> + +Divide the query up into separate section and go through each section one at a time to identify the macros and lookup tables used that need to be replaced using one of two scenarios: +- The macro or lookup table is provided in the resources: Replace it using its actual content. +- The macro or lookup table is not provided in the resources: Do not replace it, keep it in the query as it is. -`; -}; +<guidelines> +- You will be provided with a SPL query and also the resources reference with the values of macros and lookup tables. +- You have to replace the macros and lookup tables syntax in the SPL query and use their values inline, if provided. +- The original and modified queries must be equivalent. +- You must respond only with the modified query inside a \`\`\`spl code block, nothing else similar to the example response below. +</guidelines> + +<example_response> +A: Please find the modified SPL query below: +\`\`\`spl +sourcetype="linux:audit" \`linux_auditd_normalized_proctitle_process\` +| rename host as dest +| where LIKE (process_exec, "%chown root%") +| stats count min(_time) as firstTime max(_time) as lastTime by process_exec proctitle normalized_proctitle_delimiter dest +| convert timeformat="%Y-%m-%dT%H:%M:%S" ctime(firstTime) +| convert timeformat="%Y-%m-%dT%H:%M:%S" ctime(lastTime) +| search * +\`\`\` +</example_response> + +`, + ], + ['ai', 'Please find the modified SPL query below:'], +]); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/retrieve_integrations/prompts.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/retrieve_integrations/prompts.ts index 4d15ad71d679..962de190acd0 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/retrieve_integrations/prompts.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/retrieve_integrations/prompts.ts @@ -11,9 +11,9 @@ export const CREATE_SEMANTIC_QUERY_PROMPT = ChatPromptTemplate.fromMessages([ [ 'system', `You are a helpful assistant that helps in translating provided titles, descriptions and data sources into a single summary of keywords specifically crafted to be used as a semantic search query, which are usually short and includes keywords that are valid for the usecase. - The data provided are collected from SIEM detection rules, and it is trying to match the description of a list of data sources, so provide good keywords that match this usecase. - Try to also detect what sort of vendor, solution or technology is required and add these as keywords as well. - Some examples would be to identify if its cloud, which vendor, network, host, endpoint, etc.`, +The data provided are collected from SIEM detection rules, and it is trying to match the description of a list of data sources, so provide good keywords that match this usecase. +Try to also detect what sort of vendor, solution or technology is required and add these as keywords as well. +Some examples would be to identify if its cloud, which vendor, network, host, endpoint, etc.`, ], [ 'human', @@ -32,7 +32,7 @@ Go through the relevant title, description and data sources from the above query - Always reply with a JSON object with the key "query" and the value as the semantic search query inside three backticks as shown in the below example. </guidelines> -<example> +<example_response> U: <query> Title: Processes created by netsh Description: This search looks for processes launching netsh.exe to execute various commands via the netsh command-line utility. Netsh.exe is a command-line scripting utility that allows you to, either locally or remotely, display or modify the network configuration of a computer that is currently running. Netsh can be used as a persistence proxy technique to execute a helper .dll when netsh.exe is executed. In this search, we are looking for processes spawned by netsh.exe that are executing commands via the command line. Deprecated because we have another detection of the same type. @@ -42,7 +42,7 @@ A: Please find the query keywords JSON object below: \`\`\`json {{"query": "windows host endpoint netsh.exe process creation command-line utility network configuration persistence proxy dll execution sysmon event id 1"}} \`\`\` -</example>`, +</example_response>`, ], ['ai', 'Please find the query keywords JSON object below:'], ]); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/cim_ecs_map.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/cim_ecs_map.ts new file mode 100644 index 000000000000..3bafaf2fc651 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/cim_ecs_map.ts @@ -0,0 +1,181 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 SIEM_RULE_MIGRATION_CIM_ECS_MAP = ` +datamodel,object,source_field,ecs_field,data_type +Application_State,All_Application_State,dest,service.node.name,string +Application_State,All_Application_State,process,process.title,string +Application_State,All_Application_State,user,user.name,string +Application_State,Ports,dest_port,destination.port,number +Application_State,Ports,transport,network.transport,string +Application_State,Ports,transport_dest_port,destination.port,string +Application_State,Services,service,service.name,string +Application_State,Services,service_id,service.id,string +Application_State,Services,status,service.state,string +Authentication,Authentication,action,event.action,string +Authentication,Authentication,app,process.name,string +Authentication,Authentication,dest,host.name,string +Authentication,Authentication,duration,event.duration,number +Authentication,Authentication,signature,event.code,string +Authentication,Authentication,signature_id,event.reason,string +Authentication,Authentication,src,source.address,string +Authentication,Authentication,src_nt_domain,source.domain,string +Authentication,Authentication,user,user.name,string +Certificates,All_Certificates,dest_port,destination.port,number +Certificates,All_Certificates,duration,event.duration,number +Certificates,All_Certificates,src,source.address,string +Certificates,All_Certificates,src_port,source.port,number +Certificates,All_Certificates,transport,network.protocol,string +Certificates,SSL,ssl_end_time,tls.server.not_after,time +Certificates,SSL,ssl_hash,tls.server.hash,string +Certificates,SSL,ssl_issuer_common_name,tls.server.issuer,string +Certificates,SSL,ssl_issuer_locality,x509.issuer.locality,string +Certificates,SSL,ssl_issuer_organization,x509.issuer.organization,string +Certificates,SSL,ssl_issuer_state,x509.issuer.state_or_province,string +Certificates,SSL,ssl_issuer_unit,x509.issuer.organizational_unit,string +Certificates,SSL,ssl_publickey_algorithm,x509.public_key_algorithm,string +Certificates,SSL,ssl_serial,x509.serial_number,string +Certificates,SSL,ssl_signature_algorithm,x509.signature_algorithm,string +Certificates,SSL,ssl_start_time,x509.not_before,time +Certificates,SSL,ssl_subject,x509.subject.distinguished_name,string +Certificates,SSL,ssl_subject_common_name,x509.subject.common_name,string +Certificates,SSL,ssl_subject_locality,x509.subject.locality,string +Certificates,SSL,ssl_subject_organization,x509.subject.organization,string +Certificates,SSL,ssl_subject_state,x509.subject.state_or_province,string +Certificates,SSL,ssl_subject_unit,x509.subject.organizational_unit,string +Certificates,SSL,ssl_version,tls.version,string +Change,All_Changes,action,event.action,string +Change,Account_Management,dest_nt_domain,destination.domain,string +Change,Account_Management,src_nt_domain,source.domain,string +Change,Account_Management,src_user,source.user,string +Intrusion_Detection,IDS_Attacks,action,event.action,string +Intrusion_Detection,IDS_Attacks,dest,destination.address,string +Intrusion_Detection,IDS_Attacks,dest_port,destination.port,number +Intrusion_Detection,IDS_Attacks,dvc,observer.hostname,string +Intrusion_Detection,IDS_Attacks,severity,event.severity,string +Intrusion_Detection,IDS_Attacks,src,source.ip,string +Intrusion_Detection,IDS_Attacks,user,source.user,string +JVM,OS,os,host.os.name,string +JVM,OS,os_architecture,host.architecture,string +JVM,OS,os_version,host.os.version,string +Malware,Malware_Attacks,action,event.action,string +Malware,Malware_Attacks,date,event.created,string +Malware,Malware_Attacks,dest,host.hostname,string +Malware,Malware_Attacks,file_hash,file.hash.*,string +Malware,Malware_Attacks,file_name,file.name,string +Malware,Malware_Attacks,file_path,file.path,string +Malware,Malware_Attacks,Sender,source.user.email,string +Malware,Malware_Attacks,src,source.ip,string +Malware,Malware_Attacks,user,related.user,string +Malware,Malware_Attacks,url,rule.reference,string +Network_Resolution,DNS,answer,dns.answers,string +Network_Resolution,DNS,dest,destination.address,string +Network_Resolution,DNS,dest_port,destination.port,number +Network_Resolution,DNS,duration,event.duration,number +Network_Resolution,DNS,message_type,dns.type,string +Network_Resolution,DNS,name,dns.question.name,string +Network_Resolution,DNS,query,dns.question.name,string +Network_Resolution,DNS,query_type,dns.op_code,string +Network_Resolution,DNS,record_type,dns.question.type,string +Network_Resolution,DNS,reply_code,dns.response_code,string +Network_Resolution,DNS,reply_code_id,dns.id,number +Network_Resolution,DNS,response_time,event.duration,number +Network_Resolution,DNS,src,source.address,string +Network_Resolution,DNS,src_port,source.port,number +Network_Resolution,DNS,transaction_id,dns.id,number +Network_Resolution,DNS,transport,network.transport,string +Network_Resolution,DNS,ttl,dns.answers.ttl,number +Network_Sessions,All_Sessions,action,event.action,string +Network_Sessions,All_Sessions,dest_ip,destination.ip,string +Network_Sessions,All_Sessions,dest_mac,destination.mac,string +Network_Sessions,All_Sessions,duration,event.duration,number +Network_Sessions,All_Sessions,src_dns,source.registered_domain,string +Network_Sessions,All_Sessions,src_ip,source.ip,string +Network_Sessions,All_Sessions,src_mac,source.mac,string +Network_Sessions,All_Sessions,user,user.name,string +Network_Traffic,All_Traffic,action,event.action,string +Network_Traffic,All_Traffic,app,network.protocol,string +Network_Traffic,All_Traffic,bytes,network.bytes,number +Network_Traffic,All_Traffic,dest,destination.ip,string +Network_Traffic,All_Traffic,dest_ip,destination.ip,string +Network_Traffic,All_Traffic,dest_mac,destination.mac,string +Network_Traffic,All_Traffic,dest_port,destination.port,number +Network_Traffic,All_Traffic,dest_translated_ip,destination.nat.ip,string +Network_Traffic,All_Traffic,dest_translated_port,destination.nat.port,number +Network_Traffic,All_Traffic,direction,network.direction,string +Network_Traffic,All_Traffic,duration,event.duration,number +Network_Traffic,All_Traffic,dvc,observer.name,string +Network_Traffic,All_Traffic,dvc_ip,observer.ip,string +Network_Traffic,All_Traffic,dvc_mac,observer.mac,string +Network_Traffic,All_Traffic,dvc_zone,observer.egress.zone,string +Network_Traffic,All_Traffic,packets,network.packets,number +Network_Traffic,All_Traffic,packets_in,source.packets,number +Network_Traffic,All_Traffic,packets_out,destination.packets,number +Network_Traffic,All_Traffic,protocol,network.protocol,string +Network_Traffic,All_Traffic,rule,rule.name,string +Network_Traffic,All_Traffic,src,source.address,string +Network_Traffic,All_Traffic,src_ip,source.ip,string +Network_Traffic,All_Traffic,src_mac,source.mac,string +Network_Traffic,All_Traffic,src_port,source.port,number +Network_Traffic,All_Traffic,src_translated_ip,source.nat.ip,string +Network_Traffic,All_Traffic,src_translated_port,source.nat.port,number +Network_Traffic,All_Traffic,transport,network.transport,string +Network_Traffic,All_Traffic,vlan,vlan.name,string +Vulnerabilities,Vulnerabilities,category,vulnerability.category,string +Vulnerabilities,Vulnerabilities,cve,vulnerability.id,string +Vulnerabilities,Vulnerabilities,cvss,vulnerability.score.base,number +Vulnerabilities,Vulnerabilities,dest,host.name,string +Vulnerabilities,Vulnerabilities,dvc,vulnerability.scanner.vendor,string +Vulnerabilities,Vulnerabilities,severity,vulnerability.severity,string +Vulnerabilities,Vulnerabilities,url,vulnerability.reference,string +Vulnerabilities,Vulnerabilities,user,related.user,string +Vulnerabilities,Vulnerabilities,vendor_product,vulnerability.scanner.vendor,string +Endpoint,Ports,creation_time,@timestamp,timestamp +Endpoint,Ports,dest_port,destination.port,number +Endpoint,Ports,process_id,process.pid,string +Endpoint,Ports,transport,network.transport,string +Endpoint,Ports,transport_dest_port,destination.port,string +Endpoint,Processes,action,event.action,string +Endpoint,Processes,os,os.full,string +Endpoint,Processes,parent_process_exec,process.parent.name,string +Endpoint,Processes,parent_process_id,process.ppid,number +Endpoint,Processes,parent_process_guid,process.parent.entity_id,string +Endpoint,Processes,parent_process_path,process.parent.executable,string +Endpoint,Processes,process_current_directory,process.parent.working_directory, +Endpoint,Processes,process_exec,process.name,string +Endpoint,Processes,process_hash,process.hash.*,string +Endpoint,Processes,process_guid,process.entity_id,string +Endpoint,Processes,process_id,process.pid,number +Endpoint,Processes,process_path,process.executable,string +Endpoint,Processes,user_id,related.user,string +Endpoint,Services,description,service.name,string +Endpoint,Services,process_id,service.id,string +Endpoint,Services,service_dll,dll.name,string +Endpoint,Services,service_dll_path,dll.path,string +Endpoint,Services,service_dll_hash,dll.hash.*,string +Endpoint,Services,service_dll_signature_exists,dll.code_signature.exists,boolean +Endpoint,Services,service_dll_signature_verified,dll.code_signature.valid,boolean +Endpoint,Services,service_exec,service.name,string +Endpoint,Services,service_hash,hash.*,string +Endpoint,Filesystem,file_access_time,file.accessed,timestamp +Endpoint,Filesystem,file_create_time,file.created,timestamp +Endpoint,Filesystem,file_modify_time,file.mtime,timestamp +Endpoint,Filesystem,process_id,process.pid,string +Endpoint,Registry,process_id,process.id,string +Web,Web,action,event.action,string +Web,Web,app,observer.product,string +Web,Web,bytes_in,http.request.bytes,number +Web,Web,bytes_out,http.response.bytes,number +Web,Web,dest,destination.ip,string +Web,Web,duration,event.duration,number +Web,Web,http_method,http.request.method,string +Web,Web,http_referrer,http.request.referrer,string +Web,Web,http_user_agent,user_agent.name,string +Web,Web,status,http.response.status_code,string +Web,Web,url,url.full,string +Web,Web,user,url.username,string +Web,Web,vendor_product,observer.product,string`; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/prompts.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/prompts.ts index 3e77353bba8b..9749dfd96efb 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/prompts.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/prompts.ts @@ -5,14 +5,18 @@ * 2.0. */ -import type { TranslateRuleState } from '../../types'; +import { ChatPromptTemplate } from '@langchain/core/prompts'; -export const getEsqlTranslationPrompt = ( - state: TranslateRuleState, - indexPatterns: string -): string => { - return `You are a helpful cybersecurity (SIEM) expert agent. Your task is to migrate "detection rules" from Splunk to Elastic Security. +export const ESQL_TRANSLATION_PROMPT = + ChatPromptTemplate.fromTemplate(`You are a helpful cybersecurity (SIEM) expert agent. Your task is to migrate "detection rules" from Splunk to Elastic Security. Your goal is to translate the SPL query into an equivalent Elastic Security Query Language (ES|QL) query. +Below is the relevant context used when deciding which Elastic Common Schema field to use when translating from Splunk CIM fields: + +<context> +<cim_to_ecs_map> +{field_mapping} +</cim_to_ecs_map> +</context> ## Splunk rule Information provided: - Below you will find Splunk rule information: the title (<<TITLE>>), the description (<<DESCRIPTION>>), and the SPL (Search Processing Language) query (<<SPL_QUERY>>). @@ -22,7 +26,7 @@ Your goal is to translate the SPL query into an equivalent Elastic Security Quer ## Guidelines: - Analyze the SPL query and identify the key components. - Translate the SPL query into an equivalent ES|QL query using ECS (Elastic Common Schema) field names. -- Always start the generated ES|QL query by filtering FROM using these index patterns in the translated query: ${indexPatterns}. +- Always start the generated ES|QL query by filtering FROM using these index patterns in the translated query: {indexPatterns}. - If, in the SPL query, you find a lookup list or macro call, mention it in the summary and add a placeholder in the query with the format [macro:<macro_name>(argumentCount)] or [lookup:<lookup_name>] including the [] keys, - Examples: - \`get_duration(firstDate,secondDate)\` -> [macro:get_duration(2)] @@ -35,15 +39,14 @@ Your goal is to translate the SPL query into an equivalent Elastic Security Quer Find the Splunk rule information below: <<TITLE>> -${state.original_rule.title} +{title} <> <> -${state.original_rule.description} +{description} <> <> -${state.inline_query} +{inline_query} <> -`; -}; +`); diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/translate_rule.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/translate_rule.ts index 3fcd968b5565..6ba5edee11b2 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/translate_rule.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/translate_rule.ts @@ -9,10 +9,11 @@ import type { Logger } from '@kbn/core/server'; import type { InferenceClient } from '@kbn/inference-plugin/server'; import { SiemMigrationRuleTranslationResult } from '../../../../../../../../../../common/siem_migrations/constants'; import type { ChatModel } from '../../../../../util/actions_client_chat'; +import { getEsqlKnowledgeBase } from '../../../../../util/esql_knowledge_base_caller'; import type { RuleResourceRetriever } from '../../../../../util/rule_resource_retriever'; import type { GraphNode } from '../../types'; -import { getEsqlKnowledgeBase } from './esql_knowledge_base_caller'; -import { getEsqlTranslationPrompt } from './prompts'; +import { SIEM_RULE_MIGRATION_CIM_ECS_MAP } from './cim_ecs_map'; +import { ESQL_TRANSLATION_PROMPT } from './prompts'; interface GetTranslateRuleNodeParams { model: ChatModel; @@ -29,12 +30,20 @@ export const getTranslateRuleNode = ({ }: GetTranslateRuleNodeParams): GraphNode => { const esqlKnowledgeBaseCaller = getEsqlKnowledgeBase({ inferenceClient, connectorId, logger }); return async (state) => { - const indexPatterns = state.integrations.flatMap((integration) => - integration.data_streams.map((dataStream) => dataStream.index_pattern) - ); + const indexPatterns = state.integrations + .flatMap((integration) => + integration.data_streams.map((dataStream) => dataStream.index_pattern) + ) + .join(','); const integrationIds = state.integrations.map((integration) => integration.id); - const prompt = getEsqlTranslationPrompt(state, indexPatterns.join(' ')); + const prompt = await ESQL_TRANSLATION_PROMPT.format({ + title: state.original_rule.title, + description: state.original_rule.description, + field_mapping: SIEM_RULE_MIGRATION_CIM_ECS_MAP, + inline_query: state.inline_query, + indexPatterns, + }); const response = await esqlKnowledgeBaseCaller(prompt); const esqlQuery = response.match(/```esql\n([\s\S]*?)\n```/)?.[1] ?? ''; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/esql_query.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/esql_query.ts new file mode 100644 index 000000000000..a8c1d6acff40 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/esql_query.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ESQLAstQueryExpression, ESQLCommandOption, EditorError } from '@kbn/esql-ast'; +import { parse } from '@kbn/esql-ast'; +import { isColumnItem, isOptionItem } from '@kbn/esql-validation-autocomplete'; +import { isAggregatingQuery } from '@kbn/securitysolution-utils'; + +interface ParseEsqlQueryResult { + errors: EditorError[]; + isEsqlQueryAggregating: boolean; + hasMetadataOperator: boolean; +} + +function computeHasMetadataOperator(astExpression: ESQLAstQueryExpression): boolean { + // Check whether the `from` command has `metadata` operator + const metadataOption = getMetadataOption(astExpression); + if (!metadataOption) { + return false; + } + + // Check whether the `metadata` operator has `_id` argument + const idColumnItem = metadataOption.args.find( + (fromArg) => isColumnItem(fromArg) && fromArg.name === '_id' + ); + if (!idColumnItem) { + return false; + } + + return true; +} + +function getMetadataOption(astExpression: ESQLAstQueryExpression): ESQLCommandOption | undefined { + const fromCommand = astExpression.commands.find((x) => x.name === 'from'); + + if (!fromCommand?.args) { + return undefined; + } + + // Check whether the `from` command has `metadata` operator + for (const fromArg of fromCommand.args) { + if (isOptionItem(fromArg) && fromArg.name === 'metadata') { + return fromArg; + } + } + + return undefined; +} + +export const parseEsqlQuery = (query: string): ParseEsqlQueryResult => { + const { root, errors } = parse(query); + const isEsqlQueryAggregating = isAggregatingQuery(root); + return { + errors, + isEsqlQueryAggregating, + hasMetadataOperator: computeHasMetadataOperator(root), + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/index.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/index.ts new file mode 100644 index 000000000000..a8c0f55191e4 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor 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 { getValidationNode } from './validation'; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/validation.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/validation.ts new file mode 100644 index 000000000000..272aedfe4793 --- /dev/null +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/validation/validation.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { Logger } from '@kbn/core/server'; +import { isEmpty } from 'lodash/fp'; +import type { GraphNode } from '../../types'; +import { parseEsqlQuery } from './esql_query'; + +interface GetValidationNodeParams { + logger: Logger; +} + +/** + * This node runs all validation steps, and will redirect to the END of the graph if no errors are found. + * Any new validation steps should be added here. + */ +export const getValidationNode = ({ logger }: GetValidationNodeParams): GraphNode => { + return async (state) => { + const query = state.elastic_rule.query; + + // We want to prevent infinite loops, so we increment the iterations counter for each validation run. + const currentIteration = ++state.validation_errors.iterations; + let esqlErrors: string = ''; + if (!isEmpty(query)) { + const { errors, isEsqlQueryAggregating, hasMetadataOperator } = parseEsqlQuery(query); + if (!isEmpty(errors)) { + esqlErrors = JSON.stringify(errors); + } else if (!isEsqlQueryAggregating && !hasMetadataOperator) { + esqlErrors = + 'Queries that don’t use the STATS...BY function (non-aggregating queries) must include the "metadata _id, _version, _index" operator after the source command. For example: FROM logs* metadata _id, _version, _index.'; + } + } + if (esqlErrors) { + logger.debug(`ESQL query validation failed: ${esqlErrors}`); + } + + return { validation_errors: { iterations: currentIteration, esql_errors: esqlErrors } }; + }; +}; diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/state.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/state.ts index 8c8e9780aedf..391d7a54f9ea 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/state.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/state.ts @@ -14,6 +14,7 @@ import type { RuleMigration, } from '../../../../../../../../common/siem_migrations/model/rule_migration.gen'; import type { Integration } from '../../../../types'; +import type { TranslateRuleValidationErrors } from './types'; export const translateRuleState = Annotation.Root({ messages: Annotation({ @@ -33,6 +34,10 @@ export const translateRuleState = Annotation.Root({ reducer: (state, action) => ({ ...state, ...action }), default: () => ({} as ElasticRule), }), + validation_errors: Annotation({ + reducer: (current, value) => value ?? current, + default: () => ({ iterations: 0 } as TranslateRuleValidationErrors), + }), translation_result: Annotation({ reducer: (current, value) => value ?? current, default: () => SiemMigrationRuleTranslationResult.UNTRANSLATABLE, diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/types.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/types.ts index 42bf8e14c592..44a5750812be 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/types.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/types.ts @@ -23,3 +23,8 @@ export interface TranslateRuleGraphParams { integrationRetriever: IntegrationRetriever; logger: Logger; } + +export interface TranslateRuleValidationErrors { + iterations: number; + esql_errors?: string; +} diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/rule_migrations_task_client.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/rule_migrations_task_client.ts index b7cc545001f9..a6ea5c9040e1 100644 --- a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/rule_migrations_task_client.ts +++ b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/rule_migrations_task_client.ts @@ -8,11 +8,11 @@ import type { AuthenticatedUser, Logger } from '@kbn/core/server'; import { AbortError, abortSignalToPromise } from '@kbn/kibana-utils-plugin/server'; import type { RunnableConfig } from '@langchain/core/runnables'; -import { SiemMigrationStatus } from '../../../../../common/siem_migrations/constants'; -import type { - RuleMigrationAllTaskStats, - RuleMigrationTaskStats, -} from '../../../../../common/siem_migrations/model/rule_migration.gen'; +import { + SiemMigrationTaskStatus, + SiemMigrationStatus, +} from '../../../../../common/siem_migrations/constants'; +import type { RuleMigrationTaskStats } from '../../../../../common/siem_migrations/model/rule_migration.gen'; import type { RuleMigrationsDataClient } from '../data/rule_migrations_data_client'; import type { RuleMigrationDataStats } from '../data/rule_migrations_data_rules_client'; import { getRuleMigrationAgent } from './agent'; @@ -229,10 +229,10 @@ export class RuleMigrationsTaskClient { } /** Returns the stats of all migrations */ - async getAllStats(): Promise { + async getAllStats(): Promise { const allDataStats = await this.data.rules.getAllStats(); return allDataStats.map((dataStats) => { - const status = this.getTaskStatus(dataStats.migration_id, dataStats.rules); + const status = this.getTaskStatus(dataStats.id, dataStats.rules); return { status, ...dataStats }; }); } @@ -240,17 +240,17 @@ export class RuleMigrationsTaskClient { private getTaskStatus( migrationId: string, dataStats: RuleMigrationDataStats['rules'] - ): RuleMigrationTaskStats['status'] { + ): SiemMigrationTaskStatus { if (this.migrationsRunning.has(migrationId)) { - return 'running'; + return SiemMigrationTaskStatus.RUNNING; } if (dataStats.pending === dataStats.total) { - return 'ready'; + return SiemMigrationTaskStatus.READY; } if (dataStats.completed + dataStats.failed === dataStats.total) { - return 'finished'; + return SiemMigrationTaskStatus.FINISHED; } - return 'stopped'; + return SiemMigrationTaskStatus.STOPPED; } /** Stops one running migration */ diff --git a/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/esql_knowledge_base_caller.ts b/x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/util/esql_knowledge_base_caller.ts similarity index 100% rename from x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/agent/sub_graphs/translate_rule/nodes/translate_rule/esql_knowledge_base_caller.ts rename to x-pack/plugins/security_solution/server/lib/siem_migrations/rules/task/util/esql_knowledge_base_caller.ts diff --git a/x-pack/plugins/security_solution/server/plugin.ts b/x-pack/plugins/security_solution/server/plugin.ts index e2ec9d0e1b53..4b66d73c93b1 100644 --- a/x-pack/plugins/security_solution/server/plugin.ts +++ b/x-pack/plugins/security_solution/server/plugin.ts @@ -56,7 +56,11 @@ import { registerEndpointRoutes } from './endpoint/routes/metadata'; import { registerPolicyRoutes } from './endpoint/routes/policy'; import { registerActionRoutes } from './endpoint/routes/actions'; import { registerEndpointSuggestionsRoutes } from './endpoint/routes/suggestions'; -import { EndpointArtifactClient, ManifestManager } from './endpoint/services'; +import { + EndpointArtifactClient, + ManifestManager, + securityWorkflowInsightsService, +} from './endpoint/services'; import { EndpointAppContextService } from './endpoint/endpoint_app_context_services'; import type { EndpointAppContext } from './endpoint/types'; import { initUsageCollectors } from './usage'; @@ -391,7 +395,8 @@ export class Plugin implements ISecuritySolutionPlugin { core.getStartServices, securityRuleTypeOptions, previewRuleDataClient, - this.telemetryReceiver + this.telemetryReceiver, + this.pluginContext.env.packageInfo.buildFlavor === 'serverless' ); registerEndpointRoutes(router, this.endpointContext); @@ -519,6 +524,12 @@ export class Plugin implements ISecuritySolutionPlugin { featureUsageService.setup(plugins.licensing); + securityWorkflowInsightsService.setup({ + kibanaVersion: pluginContext.env.packageInfo.version, + logger: this.logger, + isFeatureEnabled: config.experimentalFeatures.defendInsights, + }); + return { setProductFeaturesConfigurator: productFeaturesService.setProductFeaturesConfigurator.bind(productFeaturesService), @@ -672,6 +683,12 @@ export class Plugin implements ISecuritySolutionPlugin { this.telemetryReceiver ); + securityWorkflowInsightsService + .start({ + esClient: core.elasticsearch.client.asInternalUser, + }) + .catch(() => {}); + const endpointPkgInstallationPromise = this.endpointContext.service .getInternalFleetServices() .packages.getInstallation(FLEET_ENDPOINT_PACKAGE); @@ -727,6 +744,7 @@ export class Plugin implements ISecuritySolutionPlugin { this.policyWatcher?.stop(); this.completeExternalResponseActionsTask.stop().catch(() => {}); this.siemMigrationsService.stop(); + securityWorkflowInsightsService.stop(); licenseService.stop(); } } diff --git a/x-pack/plugins/security_solution/server/plugin_contract.ts b/x-pack/plugins/security_solution/server/plugin_contract.ts index c178f0654d9b..b1e7d0b61380 100644 --- a/x-pack/plugins/security_solution/server/plugin_contract.ts +++ b/x-pack/plugins/security_solution/server/plugin_contract.ts @@ -12,10 +12,7 @@ import type { } from '@kbn/data-plugin/server'; import type { PluginStart as DataViewsPluginStart } from '@kbn/data-views-plugin/server'; import type { UsageCollectionSetup as UsageCollectionPluginSetup } from '@kbn/usage-collection-plugin/server'; -import type { - PluginSetupContract as AlertingPluginSetup, - PluginStartContract as AlertingPluginStart, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import type { PluginSetupContract as ActionsPluginSetup, PluginStartContract as ActionsPluginStartContract, @@ -50,7 +47,7 @@ import type { ProductFeaturesService } from './lib/product_features_service/prod import type { ExperimentalFeatures } from '../common'; export interface SecuritySolutionPluginSetupDependencies { - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; actions: ActionsPluginSetup; cases: CasesServerSetup; cloud: CloudSetup; @@ -73,7 +70,7 @@ export interface SecuritySolutionPluginSetupDependencies { } export interface SecuritySolutionPluginStartDependencies { - alerting: AlertingPluginStart; + alerting: AlertingServerStart; cases?: CasesServerStart; cloud: CloudSetup; data: DataPluginStart; diff --git a/x-pack/plugins/security_solution/server/request_context_factory.ts b/x-pack/plugins/security_solution/server/request_context_factory.ts index eb1fed582615..6b2718bac770 100644 --- a/x-pack/plugins/security_solution/server/request_context_factory.ts +++ b/x-pack/plugins/security_solution/server/request_context_factory.ts @@ -107,6 +107,8 @@ export class RequestContextFactory implements IRequestContextFactory { // time it is requested (see `getEndpointAuthz()` below) let endpointAuthz: Immutable; + const rulesClient = await startPlugins.alerting.getRulesClientWithRequest(request); + return { core: coreContext, @@ -146,8 +148,8 @@ export class RequestContextFactory implements IRequestContextFactory { }); return createDetectionRulesClient({ + rulesClient, actionsClient, - rulesClient: startPlugins.alerting.getRulesClientWithRequest(request), savedObjectsClient: coreContext.savedObjects.client, mlAuthz, }); @@ -155,7 +157,7 @@ export class RequestContextFactory implements IRequestContextFactory { getDetectionEngineHealthClient: memoize(() => ruleMonitoringService.createDetectionEngineHealthClient({ - rulesClient: startPlugins.alerting.getRulesClientWithRequest(request), + rulesClient, eventLogClient: startPlugins.eventLog.getClient(request), currentSpaceId: getSpaceId(), }) diff --git a/x-pack/plugins/security_solution/server/routes/index.ts b/x-pack/plugins/security_solution/server/routes/index.ts index f7d5ce7afb3d..ff1166413b9f 100644 --- a/x-pack/plugins/security_solution/server/routes/index.ts +++ b/x-pack/plugins/security_solution/server/routes/index.ts @@ -77,7 +77,8 @@ export const initRoutes = ( getStartServices: StartServicesAccessor, securityRuleTypeOptions: CreateSecurityRuleTypeWrapperProps, previewRuleDataClient: IRuleDataClient, - previewTelemetryReceiver: ITelemetryReceiver + previewTelemetryReceiver: ITelemetryReceiver, + isServerless: boolean ) => { registerFleetIntegrationsRoutes(router); registerLegacyRuleActionsRoutes(router, logger); @@ -95,7 +96,8 @@ export const initRoutes = ( securityRuleTypeOptions, previewRuleDataClient, getStartServices, - logger + logger, + isServerless ); registerResolverRoutes(router, getStartServices, config); diff --git a/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts b/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts index f44ad77e6792..d80be5f4a421 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/helpers/format_response_object_values.ts @@ -7,9 +7,7 @@ import { mapValues, isObject, isArray } from 'lodash/fp'; import { set } from '@kbn/safer-lodash-set'; - -import { toArray } from '../../../common/utils/to_array'; -import { isGeoField } from '../../../common/utils/field_formatters'; +import { toArray, isGeoField } from '@kbn/timelines-plugin/common'; export const mapObjectValuesToStringArray = (object: object): object => mapValues((o) => { diff --git a/x-pack/plugins/security_solution/server/search_strategy/helpers/get_flattened_fields.ts b/x-pack/plugins/security_solution/server/search_strategy/helpers/get_flattened_fields.ts index f40edfc5914d..baed5b3c3560 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/helpers/get_flattened_fields.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/helpers/get_flattened_fields.ts @@ -6,7 +6,7 @@ */ import { set } from '@kbn/safer-lodash-set'; import { get, isEmpty } from 'lodash/fp'; -import { toObjectArrayOfStrings } from '../../../common/utils/to_array'; +import { toObjectArrayOfStrings } from '@kbn/timelines-plugin/common'; export function getFlattenedFields( fields: string[], diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts index 8707f10ed01c..61ab1c5bca58 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/all/helpers.ts @@ -8,12 +8,12 @@ import { set } from '@kbn/safer-lodash-set/fp'; import { get, has } from 'lodash/fp'; import { hostFieldsMap } from '@kbn/securitysolution-ecs'; +import { toObjectArrayOfStrings } from '@kbn/timelines-plugin/common'; import type { HostAggEsItem, HostsEdges, HostValue, } from '../../../../../../common/search_strategy/security_solution/hosts'; -import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array'; export const HOSTS_FIELDS: readonly string[] = [ '_id', diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts index 94d45b2b63e0..cc1a084f6b5a 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/hosts/details/helpers.ts @@ -13,6 +13,7 @@ import type { SavedObjectsClientContract, } from '@kbn/core/server'; import { hostFieldsMap } from '@kbn/securitysolution-ecs'; +import { toObjectArrayOfStrings } from '@kbn/timelines-plugin/common'; import { Direction } from '../../../../../../common/search_strategy/common'; import type { AggregationRequest, @@ -22,7 +23,6 @@ import type { HostItem, HostValue, } from '../../../../../../common/search_strategy/security_solution/hosts'; -import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array'; import type { EndpointAppContext } from '../../../../../endpoint/types'; import { getPendingActionsSummary } from '../../../../../endpoint/services'; diff --git a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts index 06452c915009..b92b67f244eb 100644 --- a/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts +++ b/x-pack/plugins/security_solution/server/search_strategy/security_solution/factory/users/authentications/helpers.ts @@ -8,7 +8,7 @@ import { get, getOr, isEmpty } from 'lodash/fp'; import { set } from '@kbn/safer-lodash-set/fp'; import { sourceFieldsMap, hostFieldsMap } from '@kbn/securitysolution-ecs'; -import { toObjectArrayOfStrings } from '../../../../../../common/utils/to_array'; +import { toObjectArrayOfStrings } from '@kbn/timelines-plugin/common'; import type { AuthenticationsEdges, AuthenticationHit, diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 4a00ef93abe6..4ed7e1cbdd35 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -15,7 +15,11 @@ "public/**/*.json", "../../../typings/**/*" ], - "exclude": ["target/**/*", "**/cypress/**", "public/management/cypress.config.ts"], + "exclude": [ + "target/**/*", + "**/cypress/**", + "public/management/cypress.config.ts" + ], "kbn_references": [ "@kbn/core", { @@ -228,6 +232,7 @@ "@kbn/core-lifecycle-server", "@kbn/core-user-profile-common", "@kbn/langchain", + "@kbn/discover-shared-plugin", "@kbn/react-hooks", "@kbn/index-adapter", "@kbn/core-http-server-utils" diff --git a/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/enablement_modal_callout.tsx b/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/enablement_modal_callout.tsx new file mode 100644 index 000000000000..0048a0547ecf --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/enablement_modal_callout.tsx @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import { EuiText } from '@elastic/eui'; +import { ADDITIONAL_CHARGES_MESSAGE } from '../../upselling/translations'; + +export const EnablementModalCallout: React.FC = () => { + return ( +
        + {ADDITIONAL_CHARGES_MESSAGE} +
        + ); +}; + +// eslint-disable-next-line import/no-default-export +export default EnablementModalCallout; diff --git a/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/index.tsx b/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/index.tsx new file mode 100644 index 000000000000..0bc65a33d653 --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/index.tsx @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import type { Services } from '../../common/services'; +import { ServicesProvider } from '../../common/services'; +import { EnablementModalCallout } from './lazy'; + +export const getEnablementModalCallout = (services: Services): React.ComponentType => + function EnablementModalCalloutComponent() { + return ( + + + + ); + }; diff --git a/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/lazy.tsx b/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/lazy.tsx new file mode 100644 index 000000000000..547a15fc535e --- /dev/null +++ b/x-pack/plugins/security_solution_serverless/public/components/enablement_modal_callout/lazy.tsx @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { lazy, Suspense } from 'react'; +import { EuiLoadingSpinner } from '@elastic/eui'; + +const EnablementModalCalloutLazy = lazy(() => import('./enablement_modal_callout')); + +export const EnablementModalCallout = () => ( + }> + + +); diff --git a/x-pack/plugins/security_solution_serverless/public/plugin.ts b/x-pack/plugins/security_solution_serverless/public/plugin.ts index 4d94a11500d5..30e0f86ccdac 100644 --- a/x-pack/plugins/security_solution_serverless/public/plugin.ts +++ b/x-pack/plugins/security_solution_serverless/public/plugin.ts @@ -23,6 +23,7 @@ import { type ExperimentalFeatures, } from '../common/experimental_features'; import { setOnboardingSettings } from './onboarding'; +import { getEnablementModalCallout } from './components/enablement_modal_callout'; export class SecuritySolutionServerlessPlugin implements @@ -69,6 +70,7 @@ export class SecuritySolutionServerlessPlugin securitySolution.setComponents({ DashboardsLandingCallout: getDashboardsLandingCallout(services), + EnablementModalCallout: getEnablementModalCallout(services), }); setOnboardingSettings(services); diff --git a/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts b/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts index 971873ca7783..f70a36f90348 100644 --- a/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts +++ b/x-pack/plugins/security_solution_serverless/public/upselling/translations.ts @@ -18,3 +18,11 @@ export const UPGRADE_PRODUCT_MESSAGE = (requiredProduct: string) => }, } ); + +export const ADDITIONAL_CHARGES_MESSAGE = i18n.translate( + 'xpack.securitySolutionServerless.entityStoreEnablementCallout.additionalChargesMessage', + { + defaultMessage: + 'Please be aware that activating these features may incur additional charges depending on your subscription plan. Review your plan details carefully to avoid unexpected costs before proceeding.', + } +); diff --git a/x-pack/plugins/serverless_observability/kibana.jsonc b/x-pack/plugins/serverless_observability/kibana.jsonc index fce943c44865..ad2c1f76ce56 100644 --- a/x-pack/plugins/serverless_observability/kibana.jsonc +++ b/x-pack/plugins/serverless_observability/kibana.jsonc @@ -25,7 +25,9 @@ "discover", "security" ], - "optionalPlugins": [], + "optionalPlugins": [ + "streams" + ], "requiredBundles": [] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/serverless_observability/public/navigation_tree.ts b/x-pack/plugins/serverless_observability/public/navigation_tree.ts index 7501a75abe87..e6fb3c910730 100644 --- a/x-pack/plugins/serverless_observability/public/navigation_tree.ts +++ b/x-pack/plugins/serverless_observability/public/navigation_tree.ts @@ -8,374 +8,387 @@ import { i18n } from '@kbn/i18n'; import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; -export const navigationTree: NavigationTreeDefinition = { - body: [ - { type: 'recentlyAccessed' }, - { - type: 'navGroup', - id: 'observability_project_nav', - title: 'Observability', - icon: 'logoObservability', - defaultIsCollapsed: false, - isCollapsible: false, - breadcrumbStatus: 'hidden', - children: [ - { - title: i18n.translate('xpack.serverlessObservability.nav.discover', { - defaultMessage: 'Discover', - }), - link: 'last-used-logs-viewer', - // avoid duplicate "Discover" breadcrumbs - breadcrumbStatus: 'hidden', - renderAs: 'item', - children: [ - { - link: 'discover', - children: [ - { - link: 'observability-logs-explorer', - }, - ], - }, - ], - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { - defaultMessage: 'Dashboards', - }), - link: 'dashboards', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dashboards')); +export const createNavigationTree = ({ + streamsAvailable, +}: { + streamsAvailable?: boolean; +}): NavigationTreeDefinition => { + return { + body: [ + { type: 'recentlyAccessed' }, + { + type: 'navGroup', + id: 'observability_project_nav', + title: 'Observability', + icon: 'logoObservability', + defaultIsCollapsed: false, + isCollapsible: false, + breadcrumbStatus: 'hidden', + children: [ + { + title: i18n.translate('xpack.serverlessObservability.nav.discover', { + defaultMessage: 'Discover', + }), + link: 'last-used-logs-viewer', + // avoid duplicate "Discover" breadcrumbs + breadcrumbStatus: 'hidden', + renderAs: 'item', + children: [ + { + link: 'discover', + children: [ + { + link: 'observability-logs-explorer', + }, + ], + }, + ], }, - }, - { - link: 'observability-overview:alerts', - }, - { - link: 'observability-overview:cases', - renderAs: 'item', - children: [ - { - link: 'observability-overview:cases_configure', - }, - { - link: 'observability-overview:cases_create', - }, - ], - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.slo', { - defaultMessage: 'SLOs', - }), - link: 'slo', - }, - { - link: 'observabilityAIAssistant', - title: i18n.translate('xpack.serverlessObservability.nav.aiAssistant', { - defaultMessage: 'AI Assistant', - }), - }, - { link: 'inventory', spaceBefore: 'm' }, - { - id: 'apm', - title: i18n.translate('xpack.serverlessObservability.nav.applications', { - defaultMessage: 'Applications', - }), - renderAs: 'panelOpener', - children: [ - { - children: [ - { - link: 'apm:services', - title: i18n.translate('xpack.serverlessObservability.nav.apm.services', { - defaultMessage: 'Service inventory', - }), - }, - { link: 'apm:traces' }, - { link: 'apm:dependencies' }, - { link: 'apm:settings' }, - { - id: 'synthetics', - title: i18n.translate('xpack.serverlessObservability.nav.synthetics', { - defaultMessage: 'Synthetics', - }), - children: [ - { - title: i18n.translate( - 'xpack.serverlessObservability.nav.synthetics.overviewItem', - { - defaultMessage: 'Overview', - } - ), - id: 'synthetics-overview', - link: 'synthetics:overview', - breadcrumbStatus: 'hidden', - }, - { - link: 'synthetics:certificates', - title: i18n.translate( - 'xpack.serverlessObservability.nav.synthetics.certificatesItem', - { - defaultMessage: 'TLS certificates', - } - ), - id: 'synthetics-certificates', - breadcrumbStatus: 'hidden', - }, - ], - }, - ], + { + title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { + defaultMessage: 'Dashboards', + }), + link: 'dashboards', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); }, - ], - }, - { - id: 'metrics', - title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { - defaultMessage: 'Infrastructure', - }), - renderAs: 'panelOpener', - children: [ - { - children: [ - { - link: 'metrics:inventory', - title: i18n.translate( - 'xpack.serverlessObservability.nav.infrastructureInventory', - { - defaultMessage: 'Infrastructure inventory', - } - ), - }, - { link: 'metrics:hosts' }, - { link: 'metrics:settings' }, - { link: 'metrics:assetDetails' }, - ], - }, - ], - }, - { - id: 'machine_learning-landing', - renderAs: 'panelOpener', - title: i18n.translate('xpack.serverlessObservability.nav.machineLearning', { - defaultMessage: 'Machine learning', - }), - children: [ - { - children: [ - { - link: 'ml:overview', - }, - { - link: 'ml:notifications', - }, - { - link: 'ml:memoryUsage', - title: i18n.translate( - 'xpack.serverlessObservability.nav.machineLearning.memoryUsage', - { - defaultMessage: 'Memory usage', - } - ), - }, - ], - }, - { - id: 'category-anomaly_detection', - title: i18n.translate('xpack.serverlessObservability.nav.ml.anomaly_detection', { - defaultMessage: 'Anomaly detection', - }), - breadcrumbStatus: 'hidden', - children: [ - { - link: 'ml:anomalyDetection', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.anomaly_detection.jobs', - { - defaultMessage: 'Jobs', - } - ), - }, - { - link: 'ml:anomalyExplorer', - }, - { - link: 'ml:singleMetricViewer', - }, - { - link: 'ml:settings', - }, - { - link: 'ml:suppliedConfigurations', - }, - ], - }, - { - id: 'category-data_frame analytics', - title: i18n.translate('xpack.serverlessObservability.nav.ml.data_frame_analytics', { - defaultMessage: 'Data frame analytics', - }), - breadcrumbStatus: 'hidden', - children: [ - { - link: 'ml:dataFrameAnalytics', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.data_frame_analytics.jobs', - { - defaultMessage: 'Jobs', - } - ), - }, - { - link: 'ml:resultExplorer', - }, - { - link: 'ml:analyticsMap', - }, - ], - }, - { - id: 'category-model_management', - title: i18n.translate('xpack.serverlessObservability.nav.ml.model_management', { - defaultMessage: 'Model management', - }), - breadcrumbStatus: 'hidden', - children: [ - { - link: 'ml:nodesOverview', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.model_management.trainedModels', - { - defaultMessage: 'Trained models', - } - ), - }, - ], - }, - { - id: 'category-data_visualizer', - title: i18n.translate('xpack.serverlessObservability.nav.ml.data_visualizer', { - defaultMessage: 'Data visualizer', - }), - breadcrumbStatus: 'hidden', - children: [ - { - link: 'ml:fileUpload', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.data_visualizer.file_data_visualizer', - { - defaultMessage: 'File data visualizer', - } - ), - }, - { - link: 'ml:indexDataVisualizer', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.data_visualizer.data_view_data_visualizer', - { - defaultMessage: 'Data view data visualizer', - } - ), - }, - { - link: 'ml:dataDrift', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.data_visualizer.data_drift', - { - defaultMessage: 'Data drift', - } - ), - }, - ], - }, - { - id: 'category-aiops_labs', - title: i18n.translate('xpack.serverlessObservability.nav.ml.aiops_labs', { - defaultMessage: 'Aiops labs', - }), - breadcrumbStatus: 'hidden', - children: [ - { - link: 'ml:logRateAnalysis', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.aiops_labs.log_rate_analysis', - { - defaultMessage: 'Log rate analysis', - } - ), - }, - { - link: 'ml:logPatternAnalysis', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.aiops_labs.log_pattern_analysis', - { - defaultMessage: 'Log pattern analysis', - } - ), - }, + }, + { + link: 'observability-overview:alerts', + }, + { + link: 'observability-overview:cases', + renderAs: 'item', + children: [ + { + link: 'observability-overview:cases_configure', + }, + { + link: 'observability-overview:cases_create', + }, + ], + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.slo', { + defaultMessage: 'SLOs', + }), + link: 'slo', + }, + { + link: 'observabilityAIAssistant', + title: i18n.translate('xpack.serverlessObservability.nav.aiAssistant', { + defaultMessage: 'AI Assistant', + }), + }, + { link: 'inventory', spaceBefore: 'm' }, + ...(streamsAvailable + ? [ { - link: 'ml:changePointDetections', - title: i18n.translate( - 'xpack.serverlessObservability.nav.ml.aiops_labs.change_point_detection', - { - defaultMessage: 'Change point detection', - } - ), + link: 'streams' as const, }, - ], - }, - ], - }, - ], - }, - ], - footer: [ - { - type: 'navItem', - title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { - defaultMessage: 'Add data', - }), - link: 'observabilityOnboarding', - icon: 'launch', - }, - { - type: 'navItem', - id: 'devTools', - title: i18n.translate('xpack.serverlessObservability.nav.devTools', { - defaultMessage: 'Developer tools', - }), - link: 'dev_tools', - icon: 'editorCodeBlock', - }, - { - type: 'navGroup', - id: 'project_settings_project_nav', - title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { - defaultMessage: 'Project settings', - }), - icon: 'gear', - breadcrumbStatus: 'hidden', - children: [ - { - link: 'management', - title: i18n.translate('xpack.serverlessObservability.nav.mngt', { - defaultMessage: 'Management', - }), - }, - { - link: 'integrations', - }, - { - link: 'fleet', - }, - { - id: 'cloudLinkUserAndRoles', - cloudLink: 'userAndRoles', - }, - { - id: 'cloudLinkBilling', - cloudLink: 'billingAndSub', - }, - ], - }, - ], + ] + : []), + { + id: 'apm', + title: i18n.translate('xpack.serverlessObservability.nav.applications', { + defaultMessage: 'Applications', + }), + renderAs: 'panelOpener', + children: [ + { + children: [ + { + link: 'apm:services', + title: i18n.translate('xpack.serverlessObservability.nav.apm.services', { + defaultMessage: 'Service inventory', + }), + }, + { link: 'apm:traces' }, + { link: 'apm:dependencies' }, + { link: 'apm:settings' }, + { + id: 'synthetics', + title: i18n.translate('xpack.serverlessObservability.nav.synthetics', { + defaultMessage: 'Synthetics', + }), + children: [ + { + title: i18n.translate( + 'xpack.serverlessObservability.nav.synthetics.overviewItem', + { + defaultMessage: 'Overview', + } + ), + id: 'synthetics-overview', + link: 'synthetics:overview', + breadcrumbStatus: 'hidden', + }, + { + link: 'synthetics:certificates', + title: i18n.translate( + 'xpack.serverlessObservability.nav.synthetics.certificatesItem', + { + defaultMessage: 'TLS certificates', + } + ), + id: 'synthetics-certificates', + breadcrumbStatus: 'hidden', + }, + ], + }, + ], + }, + ], + }, + { + id: 'metrics', + title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { + defaultMessage: 'Infrastructure', + }), + renderAs: 'panelOpener', + children: [ + { + children: [ + { + link: 'metrics:inventory', + title: i18n.translate( + 'xpack.serverlessObservability.nav.infrastructureInventory', + { + defaultMessage: 'Infrastructure inventory', + } + ), + }, + { link: 'metrics:hosts' }, + { link: 'metrics:settings' }, + { link: 'metrics:assetDetails' }, + ], + }, + ], + }, + { + id: 'machine_learning-landing', + renderAs: 'panelOpener', + title: i18n.translate('xpack.serverlessObservability.nav.machineLearning', { + defaultMessage: 'Machine learning', + }), + children: [ + { + children: [ + { + link: 'ml:overview', + }, + { + link: 'ml:notifications', + }, + { + link: 'ml:memoryUsage', + title: i18n.translate( + 'xpack.serverlessObservability.nav.machineLearning.memoryUsage', + { + defaultMessage: 'Memory usage', + } + ), + }, + ], + }, + { + id: 'category-anomaly_detection', + title: i18n.translate('xpack.serverlessObservability.nav.ml.anomaly_detection', { + defaultMessage: 'Anomaly detection', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:anomalyDetection', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.anomaly_detection.jobs', + { + defaultMessage: 'Jobs', + } + ), + }, + { + link: 'ml:anomalyExplorer', + }, + { + link: 'ml:singleMetricViewer', + }, + { + link: 'ml:settings', + }, + { + link: 'ml:suppliedConfigurations', + }, + ], + }, + { + id: 'category-data_frame analytics', + title: i18n.translate('xpack.serverlessObservability.nav.ml.data_frame_analytics', { + defaultMessage: 'Data frame analytics', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:dataFrameAnalytics', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_frame_analytics.jobs', + { + defaultMessage: 'Jobs', + } + ), + }, + { + link: 'ml:resultExplorer', + }, + { + link: 'ml:analyticsMap', + }, + ], + }, + { + id: 'category-model_management', + title: i18n.translate('xpack.serverlessObservability.nav.ml.model_management', { + defaultMessage: 'Model management', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:nodesOverview', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.model_management.trainedModels', + { + defaultMessage: 'Trained models', + } + ), + }, + ], + }, + { + id: 'category-data_visualizer', + title: i18n.translate('xpack.serverlessObservability.nav.ml.data_visualizer', { + defaultMessage: 'Data visualizer', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:fileUpload', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_visualizer.file_data_visualizer', + { + defaultMessage: 'File data visualizer', + } + ), + }, + { + link: 'ml:indexDataVisualizer', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_visualizer.data_view_data_visualizer', + { + defaultMessage: 'Data view data visualizer', + } + ), + }, + { + link: 'ml:dataDrift', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.data_visualizer.data_drift', + { + defaultMessage: 'Data drift', + } + ), + }, + ], + }, + { + id: 'category-aiops_labs', + title: i18n.translate('xpack.serverlessObservability.nav.ml.aiops_labs', { + defaultMessage: 'Aiops labs', + }), + breadcrumbStatus: 'hidden', + children: [ + { + link: 'ml:logRateAnalysis', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.aiops_labs.log_rate_analysis', + { + defaultMessage: 'Log rate analysis', + } + ), + }, + { + link: 'ml:logPatternAnalysis', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.aiops_labs.log_pattern_analysis', + { + defaultMessage: 'Log pattern analysis', + } + ), + }, + { + link: 'ml:changePointDetections', + title: i18n.translate( + 'xpack.serverlessObservability.nav.ml.aiops_labs.change_point_detection', + { + defaultMessage: 'Change point detection', + } + ), + }, + ], + }, + ], + }, + ], + }, + ], + footer: [ + { + type: 'navItem', + title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { + defaultMessage: 'Add data', + }), + link: 'observabilityOnboarding', + icon: 'launch', + }, + { + type: 'navItem', + id: 'devTools', + title: i18n.translate('xpack.serverlessObservability.nav.devTools', { + defaultMessage: 'Developer tools', + }), + link: 'dev_tools', + icon: 'editorCodeBlock', + }, + { + type: 'navGroup', + id: 'project_settings_project_nav', + title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { + defaultMessage: 'Project settings', + }), + icon: 'gear', + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management', + title: i18n.translate('xpack.serverlessObservability.nav.mngt', { + defaultMessage: 'Management', + }), + }, + { + link: 'integrations', + }, + { + link: 'fleet', + }, + { + id: 'cloudLinkUserAndRoles', + cloudLink: 'userAndRoles', + }, + { + id: 'cloudLinkBilling', + cloudLink: 'billingAndSub', + }, + ], + }, + ], + }; }; diff --git a/x-pack/plugins/serverless_observability/public/plugin.ts b/x-pack/plugins/serverless_observability/public/plugin.ts index 05d598b2b3a7..d4df07673e87 100644 --- a/x-pack/plugins/serverless_observability/public/plugin.ts +++ b/x-pack/plugins/serverless_observability/public/plugin.ts @@ -8,8 +8,8 @@ import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { appCategories, appIds } from '@kbn/management-cards-navigation'; -import { of } from 'rxjs'; -import { navigationTree } from './navigation_tree'; +import { map, of } from 'rxjs'; +import { createNavigationTree } from './navigation_tree'; import { createObservabilityDashboardRegistration } from './logs_signal/overview_registration'; import { ServerlessObservabilityPublicSetup, @@ -50,7 +50,11 @@ export class ServerlessObservabilityPlugin setupDeps: ServerlessObservabilityPublicStartDependencies ): ServerlessObservabilityPublicStart { const { serverless, management, security } = setupDeps; - const navigationTree$ = of(navigationTree); + const navigationTree$ = (setupDeps.streams?.status$ || of({ status: 'disabled' })).pipe( + map(({ status }) => { + return createNavigationTree({ streamsAvailable: status === 'enabled' }); + }) + ); serverless.setProjectHome('/app/observability/landing'); serverless.initNavigation('oblt', navigationTree$, { dataTestSubj: 'svlObservabilitySideNav' }); const aiAssistantIsEnabled = core.application.capabilities.observabilityAIAssistant?.show; @@ -59,7 +63,7 @@ export class ServerlessObservabilityPlugin observabilityAiAssistantManagement: { category: appCategories.OTHER, title: i18n.translate('xpack.serverlessObservability.aiAssistantManagementTitle', { - defaultMessage: 'AI Assistant for Observability and Search Settings', + defaultMessage: 'AI Assistant Settings', }), description: i18n.translate( 'xpack.serverlessObservability.aiAssistantManagementDescription', diff --git a/x-pack/plugins/serverless_observability/public/types.ts b/x-pack/plugins/serverless_observability/public/types.ts index c93865f0f596..23da6c12637d 100644 --- a/x-pack/plugins/serverless_observability/public/types.ts +++ b/x-pack/plugins/serverless_observability/public/types.ts @@ -8,13 +8,14 @@ import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; import type { DiscoverSetup } from '@kbn/discover-plugin/public'; import type { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; -import { ObservabilityPublicSetup } from '@kbn/observability-plugin/public'; -import { +import type { ObservabilityPublicSetup } from '@kbn/observability-plugin/public'; +import type { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public'; -import { SecurityPluginStart } from '@kbn/security-plugin/public'; -import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import type { SecurityPluginStart } from '@kbn/security-plugin/public'; +import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import type { StreamsPluginStart, StreamsPluginSetup } from '@kbn/streams-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessObservabilityPublicSetup {} @@ -28,6 +29,7 @@ export interface ServerlessObservabilityPublicSetupDependencies { serverless: ServerlessPluginSetup; management: ManagementSetup; discover: DiscoverSetup; + streams?: StreamsPluginSetup; } export interface ServerlessObservabilityPublicStartDependencies { @@ -36,4 +38,5 @@ export interface ServerlessObservabilityPublicStartDependencies { management: ManagementStart; data: DataPublicPluginStart; security: SecurityPluginStart; + streams?: StreamsPluginStart; } diff --git a/x-pack/plugins/serverless_observability/tsconfig.json b/x-pack/plugins/serverless_observability/tsconfig.json index 3d909bf88b65..5aa97143107a 100644 --- a/x-pack/plugins/serverless_observability/tsconfig.json +++ b/x-pack/plugins/serverless_observability/tsconfig.json @@ -30,5 +30,6 @@ "@kbn/discover-plugin", "@kbn/security-plugin", "@kbn/search-types", + "@kbn/streams-plugin", ] } diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx index 3e2b04987e46..1a25b1d3c3df 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connection_details_panel.tsx @@ -5,15 +5,7 @@ * 2.0. */ -import { - EuiPanel, - EuiTitle, - EuiCode, - EuiSpacer, - EuiFlexGroup, - EuiFlexItem, - EuiText, -} from '@elastic/eui'; +import { EuiPanel, EuiTitle, EuiCode, EuiSpacer, EuiText, EuiCodeBlock } from '@elastic/eui'; import { ConnectorStatus } from '@kbn/search-connectors'; import React from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -31,6 +23,14 @@ export const ConnectionDetails: React.FC = ({ status, }) => { const { elasticsearchUrl } = useElasticsearchUrl(); + const codeBlock = `connectors: +- + connector_id: ${connectorId} + service_type: ${serviceType} + api_key: +elasticsearch: + host: ${elasticsearchUrl} + api_key:`; return ( @@ -43,38 +43,19 @@ export const ConnectionDetails: React.FC = ({ - - - - connector_id - - - - {connectorId} - - + + api_key, + }} + /> + - - - - service_type - - - - {Boolean(serviceType) && {serviceType}} - - - - - - - elasticsearch.host - - - - {elasticsearchUrl} - - + + {codeBlock} + ); }; diff --git a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx index 29bbc55d4cd7..53b2c41f04ca 100644 --- a/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/connectors/connector_config/connector_link.tsx @@ -87,11 +87,28 @@ export const ConnectorLinkElasticsearch: React.FC - - - + {Boolean(serviceType) ? ( + + + + ) : ( + + + + )} - {status === ConnectorStatus.CREATED ? ( + {Boolean(serviceType) && + (status === ConnectorStatus.CREATED || status === ConnectorStatus.NEEDS_CONFIGURATION) ? ( = ({ connector, isDisabled }) => { const { http } = useKibanaServices(); const connectorTypes = useConnectorTypes(); @@ -52,11 +57,43 @@ export const EditServiceType: React.FC = ({ connector, isD await http.post(`/internal/serverless_search/connectors/${connector.id}/service_type`, { body: JSON.stringify(body), }); - return inputServiceType; + + // if name is empty, auto generate it and a similar index name + const results: Record = await http.post( + `/internal/serverless_search/connectors/${connector.id}/generate_name`, + { + body: JSON.stringify({ + name: connector.name, + is_native: connector.is_native, + service_type: inputServiceType, + }), + } + ); + + const connectorName = results.result.connectorName; + const indexName = results.result.indexName; + + // save the generated connector name + await http.post(`/internal/serverless_search/connectors/${connector.id}/name`, { + body: JSON.stringify({ name: connectorName || '' }), + }); + + // save the generated index name (this does not create an index) + try { + // this can fail if another connector has an identical index_name value despite no index being created yet. + // in this case we just won't update the index_name, the user can do that manually when they reach that step. + await http.post(`/internal/serverless_search/connectors/${connector.id}/index_name`, { + body: JSON.stringify({ index_name: indexName }), + }); + } catch { + // do nothing + } + + return { serviceType: inputServiceType, name: connectorName }; }, onSuccess: (successData) => { queryClient.setQueryData(queryKey, { - connector: { ...connector, service_type: successData }, + connector: { ...connector, service_type: successData.serviceType, name: successData.name }, }); queryClient.invalidateQueries(queryKey); }, diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index 3c24211d2a52..1b804e4bab30 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -13,7 +13,7 @@ import { Plugin, } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { appIds } from '@kbn/management-cards-navigation'; +import { appCategories, appIds } from '@kbn/management-cards-navigation'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { QueryClient, MutationCache, QueryCache } from '@tanstack/react-query'; import { of } from 'rxjs'; @@ -168,12 +168,31 @@ export class ServerlessSearchPlugin ): ServerlessSearchPluginStart { const { serverless, management, indexManagement, security } = services; serverless.setProjectHome(services.searchIndices.startRoute); + const aiAssistantIsEnabled = core.application.capabilities.observabilityAIAssistant?.show; const navigationTree$ = of(navigationTree(core.application)); serverless.initNavigation('es', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); const extendCardNavDefinitions = serverless.getNavigationCards( - security.authz.isRoleManagementEnabled() + security.authz.isRoleManagementEnabled(), + aiAssistantIsEnabled + ? { + observabilityAiAssistantManagement: { + category: appCategories.OTHER, + title: i18n.translate('xpack.serverlessSearch.aiAssistantManagementTitle', { + defaultMessage: 'AI Assistant Settings', + }), + description: i18n.translate( + 'xpack.serverlessSearch.aiAssistantManagementDescription', + { + defaultMessage: + 'Manage knowledge base and control assistant behavior, including response language.', + } + ), + icon: 'sparkles', + }, + } + : undefined ); management.setupCardsNavigation({ diff --git a/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts b/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts index 09896a1808e4..7c507ca4c7b2 100644 --- a/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts +++ b/x-pack/plugins/serverless_search/server/routes/connectors_routes.ts @@ -12,6 +12,7 @@ import { fetchConnectorById, fetchConnectors, fetchSyncJobs, + generateConnectorName, IngestPipelineParams, startConnectorSync, updateConnectorConfiguration, @@ -353,4 +354,36 @@ export const registerConnectorsRoutes = ({ logger, http, router }: RouteDependen return response.ok(); }) ); + + router.post( + { + path: '/internal/serverless_search/connectors/{connectorId}/generate_name', + validate: { + body: schema.object({ + name: schema.string(), + is_native: schema.boolean(), + service_type: schema.string(), + }), + params: schema.object({ + connectorId: schema.string(), + }), + }, + }, + errorHandler(logger)(async (context, request, response) => { + const { client } = (await context.core).elasticsearch; + const result = await generateConnectorName( + client.asCurrentUser, + request.body.service_type, + request.body.is_native, + request.body.name + ); + + return response.ok({ + body: { + result, + }, + headers: { 'content-type': 'application/json' }, + }); + }) + ); }; diff --git a/x-pack/plugins/session_view/server/routes/alert_status_route.test.ts b/x-pack/plugins/session_view/server/routes/alert_status_route.test.ts index 646c0cbca96b..d38b83747181 100644 --- a/x-pack/plugins/session_view/server/routes/alert_status_route.test.ts +++ b/x-pack/plugins/session_view/server/routes/alert_status_route.test.ts @@ -13,7 +13,7 @@ import { import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { searchAlertByUuid } from './alert_status_route'; import { mockAlerts } from '../../common/mocks/constants/session_view_process.mock'; -import { getAlertsClientMockInstance, resetAlertingAuthMock } from './alerts_client_mock.test'; +import { getAlertsClientMockInstance } from './alerts_client_mock.test'; const getEmptyResponse = async () => { return { @@ -54,7 +54,6 @@ const getResponse = async () => { describe('alert_status_route.ts', () => { beforeEach(() => { jest.resetAllMocks(); - resetAlertingAuthMock(); }); describe('searchAlertByUuid(client, alertUuid)', () => { diff --git a/x-pack/plugins/session_view/server/routes/alert_status_route.ts b/x-pack/plugins/session_view/server/routes/alert_status_route.ts index 64192198b5e4..0a1976456ef1 100644 --- a/x-pack/plugins/session_view/server/routes/alert_status_route.ts +++ b/x-pack/plugins/session_view/server/routes/alert_status_route.ts @@ -11,6 +11,7 @@ import type { AlertsClient, RuleRegistryPluginStartContract, } from '@kbn/rule-registry-plugin/server'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; import { ALERT_STATUS_ROUTE, ALERT_UUID_PROPERTY, @@ -65,9 +66,9 @@ export const registerAlertStatusRoute = ( }; export const searchAlertByUuid = async (client: AlertsClient, alertUuid: string) => { - const indices = (await client.getAuthorizedAlertsIndices(['siem']))?.filter( - (index) => index !== PREVIEW_ALERTS_INDEX - ); + const indices = ( + await client.getAuthorizedAlertsIndices(SECURITY_SOLUTION_RULE_TYPE_IDS) + )?.filter((index) => index !== PREVIEW_ALERTS_INDEX); if (!indices) { return { events: [] }; diff --git a/x-pack/plugins/session_view/server/routes/alerts_client_mock.test.ts b/x-pack/plugins/session_view/server/routes/alerts_client_mock.test.ts index ff7631477602..dcc1f06b0f2e 100644 --- a/x-pack/plugins/session_view/server/routes/alerts_client_mock.test.ts +++ b/x-pack/plugins/session_view/server/routes/alerts_client_mock.test.ts @@ -13,7 +13,6 @@ import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { loggingSystemMock } from '@kbn/core/server/mocks'; import { alertingAuthorizationMock } from '@kbn/alerting-plugin/server/authorization/alerting_authorization.mock'; import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks'; -import { AlertingAuthorizationEntity } from '@kbn/alerting-plugin/server'; import { ruleDataServiceMock } from '@kbn/rule-registry-plugin/server/rule_data_plugin_service/rule_data_plugin_service.mock'; import type { ElasticsearchClient } from '@kbn/core/server'; import { @@ -24,11 +23,6 @@ import { } from '@kbn/rule-data-utils'; import { mockAlerts } from '../../common/mocks/constants/session_view_process.mock'; -export const alertingAuthMock = alertingAuthorizationMock.create(); -const auditLogger = auditLoggerMock.create(); - -const DEFAULT_SPACE = 'test_default_space_id'; - const getResponse = async () => { return { hits: { @@ -56,73 +50,62 @@ const getResponse = async () => { }; }; -const esClientMock = elasticsearchServiceMock.createElasticsearchClient(getResponse()); -const getAlertIndicesAliasMock = jest.fn(); -const alertsClientParams: jest.Mocked = { - logger: loggingSystemMock.create().get(), - authorization: alertingAuthMock, - auditLogger, - ruleDataService: ruleDataServiceMock.create(), - esClient: esClientMock, - getRuleType: jest.fn(), - getRuleList: jest.fn(), - getAlertIndicesAlias: getAlertIndicesAliasMock, -}; - -export function getAlertsClientMockInstance(esClient?: ElasticsearchClient) { - esClient = esClient || elasticsearchServiceMock.createElasticsearchClient(getResponse()); - - const alertsClient = new AlertsClient({ ...alertsClientParams, esClient }); - - return alertsClient; -} +const createAlertsClientParams = () => { + const getAlertIndicesAliasMock = jest.fn(); + const alertingAuthMock = alertingAuthorizationMock.create(); -export function resetAlertingAuthMock() { - alertingAuthMock.getSpaceId.mockImplementation(() => DEFAULT_SPACE); - // @ts-expect-error - alertingAuthMock.getAuthorizationFilter.mockImplementation(async () => - Promise.resolve({ filter: [] }) - ); - // @ts-expect-error - alertingAuthMock.getAugmentedRuleTypesWithAuthorization.mockImplementation(async () => { - const authorizedRuleTypes = new Set(); - authorizedRuleTypes.add({ producer: 'apm' }); - return Promise.resolve({ authorizedRuleTypes }); - }); - // @ts-expect-error - alertingAuthMock.getAuthorizedRuleTypes.mockImplementation(async () => { - const authorizedRuleTypes = [ + const authorizedRuleTypes = new Map([ + [ + 'apm.error_rate', { producer: 'apm', id: 'apm.error_rate', alerts: { context: 'observability.apm', }, + authorizedConsumers: {}, }, - ]; - return Promise.resolve(authorizedRuleTypes); + ], + ]); + + alertingAuthMock.getSpaceId.mockImplementation(() => 'test_default_space_id'); + alertingAuthMock.getAllAuthorizedRuleTypes.mockResolvedValue({ + hasAllRequested: true, + authorizedRuleTypes, }); + + alertingAuthMock.getAllAuthorizedRuleTypesFindOperation.mockResolvedValue(authorizedRuleTypes); getAlertIndicesAliasMock.mockReturnValue(['.alerts-observability.apm-default']); - alertingAuthMock.ensureAuthorized.mockImplementation( - // @ts-expect-error - async ({ - ruleTypeId, - consumer, - operation, - entity, - }: { - ruleTypeId: string; - consumer: string; - operation: string; - entity: typeof AlertingAuthorizationEntity.Alert; - }) => { - if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { - return Promise.resolve(); - } - return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + alertingAuthMock.ensureAuthorized.mockImplementation(async ({ ruleTypeId, consumer }) => { + if (ruleTypeId === 'apm.error_rate' && consumer === 'apm') { + return Promise.resolve(); } - ); + return Promise.reject(new Error(`Unauthorized for ${ruleTypeId} and ${consumer}`)); + }); + + const auditLogger = auditLoggerMock.create(); + const esClientMock = elasticsearchServiceMock.createElasticsearchClient(getResponse()); + const alertsClientParams: jest.Mocked = { + logger: loggingSystemMock.create().get(), + authorization: alertingAuthMock, + auditLogger, + ruleDataService: ruleDataServiceMock.create(), + esClient: esClientMock, + getRuleType: jest.fn(), + getRuleList: jest.fn(), + getAlertIndicesAlias: getAlertIndicesAliasMock, + }; + + return alertsClientParams; +}; + +export function getAlertsClientMockInstance(esClient?: ElasticsearchClient) { + esClient = esClient || elasticsearchServiceMock.createElasticsearchClient(getResponse()); + + const alertsClient = new AlertsClient({ ...createAlertsClientParams(), esClient }); + + return alertsClient; } // this is only here because the above imports complain if they aren't declared as part of a test file. diff --git a/x-pack/plugins/session_view/server/routes/alerts_route.test.ts b/x-pack/plugins/session_view/server/routes/alerts_route.test.ts index 12300b8946a7..b8ba3f5d45a0 100644 --- a/x-pack/plugins/session_view/server/routes/alerts_route.test.ts +++ b/x-pack/plugins/session_view/server/routes/alerts_route.test.ts @@ -7,7 +7,7 @@ import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import { searchAlerts } from './alerts_route'; import { mockAlerts } from '../../common/mocks/constants/session_view_process.mock'; -import { getAlertsClientMockInstance, resetAlertingAuthMock } from './alerts_client_mock.test'; +import { getAlertsClientMockInstance } from './alerts_client_mock.test'; const getEmptyResponse = async () => { return { @@ -20,9 +20,7 @@ const getEmptyResponse = async () => { describe('alerts_route.ts', () => { beforeEach(() => { - jest.resetAllMocks(); - - resetAlertingAuthMock(); + jest.clearAllMocks(); }); describe('searchAlerts(client, sessionEntityId)', () => { diff --git a/x-pack/plugins/session_view/server/routes/alerts_route.ts b/x-pack/plugins/session_view/server/routes/alerts_route.ts index c875236989ef..c4aa91333430 100644 --- a/x-pack/plugins/session_view/server/routes/alerts_route.ts +++ b/x-pack/plugins/session_view/server/routes/alerts_route.ts @@ -11,6 +11,7 @@ import type { AlertsClient, RuleRegistryPluginStartContract, } from '@kbn/rule-registry-plugin/server'; +import { SECURITY_SOLUTION_RULE_TYPE_IDS } from '@kbn/securitysolution-rules'; import { ALERTS_ROUTE, ALERTS_PER_PAGE, @@ -88,9 +89,9 @@ export const searchAlerts = async ( range?: string[], cursor?: string ) => { - const indices = (await client.getAuthorizedAlertsIndices(['siem']))?.filter( - (index) => index !== PREVIEW_ALERTS_INDEX - ); + const indices = ( + await client.getAuthorizedAlertsIndices(SECURITY_SOLUTION_RULE_TYPE_IDS) + )?.filter((index) => index !== PREVIEW_ALERTS_INDEX); if (!indices) { return { events: [] }; diff --git a/x-pack/plugins/session_view/server/routes/process_events_route.test.ts b/x-pack/plugins/session_view/server/routes/process_events_route.test.ts index 034cab178af2..aaba035c7496 100644 --- a/x-pack/plugins/session_view/server/routes/process_events_route.test.ts +++ b/x-pack/plugins/session_view/server/routes/process_events_route.test.ts @@ -12,7 +12,7 @@ import { mockEvents, mockAlerts, } from '../../common/mocks/constants/session_view_process.mock'; -import { getAlertsClientMockInstance, resetAlertingAuthMock } from './alerts_client_mock.test'; +import { getAlertsClientMockInstance } from './alerts_client_mock.test'; import type { ProcessEvent } from '../../common'; const getEmptyResponse = async () => { @@ -38,8 +38,6 @@ const getResponse = async () => { describe('process_events_route.ts', () => { beforeEach(() => { jest.resetAllMocks(); - - resetAlertingAuthMock(); }); describe('fetchEventsAndScopedAlerts(client, entityId, cursor, forward)', () => { diff --git a/x-pack/plugins/session_view/tsconfig.json b/x-pack/plugins/session_view/tsconfig.json index 20a1f5234d9f..412de8355943 100644 --- a/x-pack/plugins/session_view/tsconfig.json +++ b/x-pack/plugins/session_view/tsconfig.json @@ -38,6 +38,7 @@ "@kbn/shared-ux-router", "@kbn/usage-collection-plugin", "@kbn/analytics", + "@kbn/securitysolution-rules", ], "exclude": [ "target/**/*", diff --git a/x-pack/plugins/snapshot_restore/public/application/components/collapsible_lists/use_collapsible_list.test.ts b/x-pack/plugins/snapshot_restore/public/application/components/collapsible_lists/use_collapsible_list.test.ts index 72bfa570df5c..dcc9fe1932f5 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/collapsible_lists/use_collapsible_list.test.ts +++ b/x-pack/plugins/snapshot_restore/public/application/components/collapsible_lists/use_collapsible_list.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useCollapsibleList } from './use_collapsible_list'; diff --git a/x-pack/plugins/spaces/public/management/components/customize_space/__snapshots__/customize_space.test.tsx.snap b/x-pack/plugins/spaces/public/management/components/customize_space/__snapshots__/customize_space.test.tsx.snap index fe9692a971d3..78cbe099ac92 100644 --- a/x-pack/plugins/spaces/public/management/components/customize_space/__snapshots__/customize_space.test.tsx.snap +++ b/x-pack/plugins/spaces/public/management/components/customize_space/__snapshots__/customize_space.test.tsx.snap @@ -82,6 +82,7 @@ exports[`renders correctly 1`] = ` > { />
        - {editingExistingSpace ? null : ( - - } - helpText={ - - } - {...this.props.validator.validateURLIdentifier(this.props.space)} - fullWidth - > - - - )} + } + helpText={ + + } + {...this.props.validator.validateURLIdentifier(this.props.space)} + fullWidth + > + + ); diff --git a/x-pack/plugins/spaces/public/management/edit_space/edit_space_content_tab.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/edit_space_content_tab.test.tsx index 3e7e04c18a7b..6f668b79756c 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/edit_space_content_tab.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/edit_space_content_tab.test.tsx @@ -114,7 +114,7 @@ describe('EditSpaceContentTab', () => { ); - await waitFor(() => null); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(getSpaceContentSpy).toHaveBeenCalledTimes(1); expect(getSpaceContentSpy).toHaveBeenCalledWith(space.id); diff --git a/x-pack/plugins/spaces/public/management/edit_space/provider/edit_space_provider.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/provider/edit_space_provider.test.tsx index 9e091514f7df..4da9806b0dee 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/provider/edit_space_provider.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/provider/edit_space_provider.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import type { PropsWithChildren } from 'react'; import React from 'react'; @@ -88,10 +88,8 @@ describe('EditSpaceProvider', () => { }); it('throws when the hook is used within a tree that does not have the provider', () => { - const { result } = renderHook(useEditSpaceServices); - expect(result.error).toBeDefined(); - expect(result.error?.message).toEqual( - expect.stringMatching('EditSpaceService Context is missing.') + expect(() => renderHook(useEditSpaceServices)).toThrow( + /EditSpaceService Context is missing./ ); }); }); @@ -109,12 +107,7 @@ describe('EditSpaceProvider', () => { }); it('throws when the hook is used within a tree that does not have the provider', () => { - const { result } = renderHook(useEditSpaceStore); - - expect(result.error).toBeDefined(); - expect(result.error?.message).toEqual( - expect.stringMatching('EditSpaceStore Context is missing.') - ); + expect(() => renderHook(useEditSpaceStore)).toThrow(/EditSpaceStore Context is missing./); }); }); }); diff --git a/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx b/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx index d35bdbee4b8b..5b1e263e20f1 100644 --- a/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx +++ b/x-pack/plugins/spaces/public/management/edit_space/roles/component/space_assign_role_privilege_form.test.tsx @@ -157,7 +157,7 @@ describe('PrivilegesRolesForm', () => { renderPrivilegeRolesForm(); - await waitFor(() => null); + await waitFor(() => new Promise((resolve) => resolve(null))); ['all', 'read', 'custom'].forEach((privilege) => { expect(screen.queryByTestId(`${privilege}-privilege-button`)).not.toBeInTheDocument(); @@ -174,9 +174,9 @@ describe('PrivilegesRolesForm', () => { renderPrivilegeRolesForm(); - await waitFor(() => null); - - expect(screen.getByTestId('space-assign-role-create-roles-privilege-button')).toBeDisabled(); + await waitFor(() => + expect(screen.getByTestId('space-assign-role-create-roles-privilege-button')).toBeDisabled() + ); }); it('makes a request to refetch available roles if page transitions back from a user interaction page visibility change', () => { @@ -208,7 +208,7 @@ describe('PrivilegesRolesForm', () => { preSelectedRoles: roles, }); - await waitFor(() => null); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(screen.getByTestId(`${FEATURE_PRIVILEGES_READ}-privilege-button`)).toHaveAttribute( 'aria-pressed', @@ -234,11 +234,11 @@ describe('PrivilegesRolesForm', () => { ], }); - await waitFor(() => null); - - expect(screen.getByTestId(`${FEATURE_PRIVILEGES_ALL}-privilege-button`)).toHaveAttribute( - 'aria-pressed', - String(true) + await waitFor(() => + expect(screen.getByTestId(`${FEATURE_PRIVILEGES_ALL}-privilege-button`)).toHaveAttribute( + 'aria-pressed', + String(true) + ) ); }); @@ -256,7 +256,7 @@ describe('PrivilegesRolesForm', () => { preSelectedRoles: roles, }); - await waitFor(() => null); + await waitFor(() => new Promise((resolve) => resolve(null))); expect(screen.getByTestId(`${FEATURE_PRIVILEGES_READ}-privilege-button`)).toHaveAttribute( 'aria-pressed', @@ -290,9 +290,9 @@ describe('PrivilegesRolesForm', () => { preSelectedRoles: roles, }); - await waitFor(() => null); - - expect(screen.getByTestId('privilege-conflict-callout')).toBeInTheDocument(); + await waitFor(() => + expect(screen.getByTestId('privilege-conflict-callout')).toBeInTheDocument() + ); }); it('does not display the permission conflict message when roles with the same privilege levels are selected', async () => { @@ -312,9 +312,9 @@ describe('PrivilegesRolesForm', () => { preSelectedRoles: roles, }); - await waitFor(() => null); - - expect(screen.queryByTestId('privilege-conflict-callout')).not.toBeInTheDocument(); + await waitFor(() => + expect(screen.queryByTestId('privilege-conflict-callout')).not.toBeInTheDocument() + ); }); }); @@ -348,7 +348,7 @@ describe('PrivilegesRolesForm', () => { preSelectedRoles: roles, }); - await waitFor(() => null); + await waitFor(() => new Promise((resolve) => resolve(null))); await userEvent.click(screen.getByTestId('custom-privilege-button')); diff --git a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx index 10bbde47a106..1a92aa7ba551 100644 --- a/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx +++ b/x-pack/plugins/spaces/public/management/spaces_grid/spaces_grid_page.tsx @@ -34,7 +34,7 @@ import { reactRouterNavigate } from '@kbn/kibana-react-plugin/public'; import { addSpaceIdToPath, type Space } from '../../../common'; import { isReservedSpace } from '../../../common'; -import { DEFAULT_SPACE_ID, ENTER_SPACE_PATH } from '../../../common/constants'; +import { ENTER_SPACE_PATH } from '../../../common/constants'; import { getSpacesFeatureDescription } from '../../constants'; import { getSpaceAvatarComponent } from '../../space_avatar'; import { SpaceSolutionBadge } from '../../space_solution_badge'; @@ -317,24 +317,9 @@ export class SpacesGridPage extends Component { }), sortable: true, truncateText: true, - width: '40%', }, ]; - config.push({ - field: 'id', - name: i18n.translate('xpack.spaces.management.spacesGridPage.identifierColumnName', { - defaultMessage: 'Identifier', - }), - sortable: true, - render(id: string) { - if (id === DEFAULT_SPACE_ID) { - return ''; - } - return id; - }, - }); - if (this.props.allowSolutionVisibility) { config.push({ field: 'solution', @@ -345,7 +330,7 @@ export class SpacesGridPage extends Component { render: (solution: Space['solution'], record: Space) => ( ), - width: '10%', + width: '18%', }); } @@ -431,6 +416,7 @@ export class SpacesGridPage extends Component { 'data-test-subj': (rowRecord) => `${rowRecord.id}-deleteSpace`, }, ], + width: '18%', }); return config; diff --git a/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.test.ts b/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.test.ts index 6b1127db821b..b1a88f6bd645 100644 --- a/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.test.ts +++ b/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.test.ts @@ -129,6 +129,60 @@ describe('PUT /internal/spaces/space/{id}/solution', () => { }); }); + it('should update the solution_type when it is search', async () => { + const payload = { + solution_type: 'search', + }; + + const { routeHandler, savedObjectsRepositoryMock } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'a-space', + }, + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(200); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledTimes(1); + expect(savedObjectsRepositoryMock.update).toHaveBeenCalledWith('space', 'a-space', { + solution: 'es', + name: 'a space', + color: undefined, + description: undefined, + disabledFeatures: [], + imageUrl: undefined, + initials: undefined, + }); + }); + + it('should failed when the solution_type is not the expected one', async () => { + const payload = { + solution_type: 'searchXoXo', + }; + + const { routeHandler } = await setup(); + + const request = httpServerMock.createKibanaRequest({ + params: { + id: 'a-space', + }, + body: payload, + method: 'post', + }); + + const response = await routeHandler(mockRouteContext, request, kibanaResponseFactory); + + const { status } = response; + + expect(status).toEqual(500); + }); + it('should not allow a new space to be created', async () => { const payload = { solution: 'oblt', diff --git a/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts b/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts index cfe14705a4e2..24508f6173bb 100644 --- a/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts +++ b/x-pack/plugins/spaces/server/routes/api/internal/set_solution_space.ts @@ -21,6 +21,7 @@ const spaceSolutionSchema = schema.oneOf([ schema.literal('security'), schema.literal('observability'), schema.literal('elasticsearch'), + schema.literal('search'), ]), }), ]); diff --git a/x-pack/plugins/stack_alerts/public/rule_types/components/data_view_select_popover.tsx b/x-pack/plugins/stack_alerts/public/rule_types/components/data_view_select_popover.tsx index acb65de2a9a1..988afb8d2182 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/components/data_view_select_popover.tsx +++ b/x-pack/plugins/stack_alerts/public/rule_types/components/data_view_select_popover.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; +import { css } from '@emotion/react'; import { EuiButtonEmpty, EuiButtonIcon, @@ -19,6 +20,7 @@ import { EuiPopoverTitle, EuiText, useEuiPaddingCSS, + useIsWithinBreakpoints, } from '@elastic/eui'; import { DataViewEditorStart } from '@kbn/data-view-editor-plugin/public'; import type { @@ -30,6 +32,9 @@ import { DataViewSelector } from '@kbn/unified-search-plugin/public'; import type { DataViewListItemEnhanced } from '@kbn/unified-search-plugin/public/dataview_picker/dataview_list'; import { EsQueryRuleMetaData } from '../es_query/types'; +const DESKTOP_WIDTH = 450; +const MOBILE_WIDTH = 350; + export interface DataViewSelectPopoverProps { dependencies: { dataViews: DataViewsPublicPluginStart; @@ -61,6 +66,8 @@ export const DataViewSelectPopover: React.FunctionComponent([]); const [dataViewPopoverOpen, setDataViewPopoverOpen] = useState(false); + const isMobile = useIsWithinBreakpoints(['xs']); + const closeDataViewEditor = useRef<() => void | undefined>(); const allDataViewItems = useMemo( @@ -179,9 +186,14 @@ export const DataViewSelectPopover: React.FunctionComponent -
        +
        - + {i18n.translate('xpack.stackAlerts.components.ui.alertParams.dataViewPopoverTitle', { defaultMessage: 'Data view', diff --git a/x-pack/plugins/stack_alerts/public/rule_types/es_query/test_query_row/use_test_query.test.ts b/x-pack/plugins/stack_alerts/public/rule_types/es_query/test_query_row/use_test_query.test.ts index f476d7d896b6..b22c1a81537c 100644 --- a/x-pack/plugins/stack_alerts/public/rule_types/es_query/test_query_row/use_test_query.test.ts +++ b/x-pack/plugins/stack_alerts/public/rule_types/es_query/test_query_row/use_test_query.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { act } from 'react-test-renderer'; import { useTestQuery } from './use_test_query'; diff --git a/x-pack/plugins/stack_alerts/server/feature.test.ts b/x-pack/plugins/stack_alerts/server/feature.test.ts index 769fad5172d6..deb1a317eed5 100644 --- a/x-pack/plugins/stack_alerts/server/feature.test.ts +++ b/x-pack/plugins/stack_alerts/server/feature.test.ts @@ -27,36 +27,145 @@ describe('Stack Alerts Feature Privileges', () => { const featuresSetup = featuresPluginMock.createSetup(); plugin.setup(coreSetup, { alerting: alertingSetup, features: featuresSetup }); - expect(BUILT_IN_ALERTS_FEATURE.alerting).toMatchInlineSnapshot(` + const ruleTypeAlerting = BUILT_IN_ALERTS_FEATURE.alerting ?? []; + const ruleTypeAll = BUILT_IN_ALERTS_FEATURE.privileges?.all?.alerting?.rule?.all ?? []; + const ruleTypeRead = BUILT_IN_ALERTS_FEATURE.privileges?.read?.alerting?.rule?.read ?? []; + + expect(ruleTypeAlerting).toMatchInlineSnapshot(` Array [ - ".index-threshold", - ".geo-containment", - ".es-query", - "transform_health", - "observability.rules.custom_threshold", - "xpack.ml.anomaly_detection_alert", + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": ".index-threshold", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": ".geo-containment", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": "transform_health", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + "discover", + ], + "ruleTypeId": ".es-query", + }, + Object { + "consumers": Array [ + "stackAlerts", + ], + "ruleTypeId": "xpack.ml.anomaly_detection_alert", + }, + Object { + "consumers": Array [ + "stackAlerts", + ], + "ruleTypeId": "observability.rules.custom_threshold", + }, ] `); - expect(BUILT_IN_ALERTS_FEATURE.privileges?.all?.alerting?.rule?.all).toMatchInlineSnapshot(` + expect(ruleTypeAll).toMatchInlineSnapshot(` Array [ - ".index-threshold", - ".geo-containment", - ".es-query", - "transform_health", - "observability.rules.custom_threshold", - "xpack.ml.anomaly_detection_alert", + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": ".index-threshold", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": ".geo-containment", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": "transform_health", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + "discover", + ], + "ruleTypeId": ".es-query", + }, + Object { + "consumers": Array [ + "stackAlerts", + ], + "ruleTypeId": "xpack.ml.anomaly_detection_alert", + }, + Object { + "consumers": Array [ + "stackAlerts", + ], + "ruleTypeId": "observability.rules.custom_threshold", + }, ] `); - expect(BUILT_IN_ALERTS_FEATURE.privileges?.read?.alerting?.rule?.read).toMatchInlineSnapshot(` + expect(ruleTypeRead).toMatchInlineSnapshot(` Array [ - ".index-threshold", - ".geo-containment", - ".es-query", - "transform_health", - "observability.rules.custom_threshold", - "xpack.ml.anomaly_detection_alert", + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": ".index-threshold", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": ".geo-containment", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + ], + "ruleTypeId": "transform_health", + }, + Object { + "consumers": Array [ + "stackAlerts", + "alerts", + "discover", + ], + "ruleTypeId": ".es-query", + }, + Object { + "consumers": Array [ + "stackAlerts", + ], + "ruleTypeId": "xpack.ml.anomaly_detection_alert", + }, + Object { + "consumers": Array [ + "stackAlerts", + ], + "ruleTypeId": "observability.rules.custom_threshold", + }, ] `); }); diff --git a/x-pack/plugins/stack_alerts/server/feature.ts b/x-pack/plugins/stack_alerts/server/feature.ts index fcb7aba3947a..fa98c155b6ba 100644 --- a/x-pack/plugins/stack_alerts/server/feature.ts +++ b/x-pack/plugins/stack_alerts/server/feature.ts @@ -15,11 +15,59 @@ import { STACK_ALERTS_FEATURE_ID, } from '@kbn/rule-data-utils'; import { ES_QUERY_ID as ElasticsearchQuery } from '@kbn/rule-data-utils'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { ID as IndexThreshold } from './rule_types/index_threshold/rule_type'; import { GEO_CONTAINMENT_ID as GeoContainment } from './rule_types/geo_containment'; const TransformHealth = TRANSFORM_RULE_TYPE.TRANSFORM_HEALTH; +const DISCOVER_CONSUMER = 'discover'; + +const basicAlertingFeatures = [IndexThreshold, GeoContainment, TransformHealth].map( + (ruleTypeId) => ({ + ruleTypeId, + consumers: [STACK_ALERTS_FEATURE_ID, ALERTING_FEATURE_ID], + }) +); + +/** + * We need to add the discover consumer + * to support legacy ES rules that were + * created with the discover consumer. + * + * Issue: https://github.com/elastic/kibana/issues/184595 + */ +const esQueryAlertingFeature = { + ruleTypeId: ElasticsearchQuery, + consumers: [STACK_ALERTS_FEATURE_ID, ALERTING_FEATURE_ID, DISCOVER_CONSUMER], +}; + +/** + * Only the stackAlerts consumer is valid + * for the stackAlerts feature ID for the + * xpack.ml.anomaly_detection_alert rule type. + */ +const mlAnomalyDetectionAlertingFeature = { + ruleTypeId: ML_ANOMALY_DETECTION_RULE_TYPE_ID, + consumers: [STACK_ALERTS_FEATURE_ID], +}; + +/** + * Only the stackAlerts consumer is valid + * for the stackAlerts feature ID for the + * observability.rules.custom_threshold rule type. + */ +const observabilityThresholdAlertingFeature = { + ruleTypeId: OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, + consumers: [STACK_ALERTS_FEATURE_ID], +}; + +const alertingFeatures = [ + ...basicAlertingFeatures, + esQueryAlertingFeature, + mlAnomalyDetectionAlertingFeature, + observabilityThresholdAlertingFeature, +]; export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { id: STACK_ALERTS_FEATURE_ID, @@ -32,14 +80,7 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { management: { insightsAndAlerting: ['triggersActions'], }, - alerting: [ - IndexThreshold, - GeoContainment, - ElasticsearchQuery, - TransformHealth, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - ], + alerting: alertingFeatures, privileges: { all: { app: [], @@ -49,24 +90,10 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { }, alerting: { rule: { - all: [ - IndexThreshold, - GeoContainment, - ElasticsearchQuery, - TransformHealth, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - ], + all: alertingFeatures, }, alert: { - all: [ - IndexThreshold, - GeoContainment, - ElasticsearchQuery, - TransformHealth, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - ], + all: alertingFeatures, }, }, savedObject: { @@ -84,24 +111,10 @@ export const BUILT_IN_ALERTS_FEATURE: KibanaFeatureConfig = { }, alerting: { rule: { - read: [ - IndexThreshold, - GeoContainment, - ElasticsearchQuery, - TransformHealth, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - ], + read: alertingFeatures, }, alert: { - read: [ - IndexThreshold, - GeoContainment, - ElasticsearchQuery, - TransformHealth, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - ], + read: alertingFeatures, }, }, savedObject: { diff --git a/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts index afcccecfef94..7473ae361977 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/es_query/rule_type.test.ts @@ -957,5 +957,6 @@ async function invokeExecutor({ const date = new Date(Date.now()).toISOString(); return { dateStart: date, dateEnd: date }; }, + isServerless: false, }); } diff --git a/x-pack/plugins/stack_alerts/server/rule_types/index_threshold/rule_type.test.ts b/x-pack/plugins/stack_alerts/server/rule_types/index_threshold/rule_type.test.ts index 546ab5239561..e94340cd049c 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/index_threshold/rule_type.test.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/index_threshold/rule_type.test.ts @@ -231,6 +231,7 @@ describe('ruleType', () => { logger, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(alertServices.alertsClient.report).toHaveBeenCalledWith({ @@ -327,6 +328,7 @@ describe('ruleType', () => { logger, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(customAlertServices.alertFactory.create).not.toHaveBeenCalled(); @@ -397,6 +399,7 @@ describe('ruleType', () => { logger, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(customAlertServices.alertFactory.create).not.toHaveBeenCalled(); @@ -466,6 +469,7 @@ describe('ruleType', () => { logger, flappingSettings: DEFAULT_FLAPPING_SETTINGS, getTimeRange, + isServerless: false, }); expect(data.timeSeriesQuery).toHaveBeenCalledWith( diff --git a/x-pack/plugins/stack_alerts/server/rule_types/types.ts b/x-pack/plugins/stack_alerts/server/rule_types/types.ts index e06553233e77..876a3c472e3a 100644 --- a/x-pack/plugins/stack_alerts/server/rule_types/types.ts +++ b/x-pack/plugins/stack_alerts/server/rule_types/types.ts @@ -7,12 +7,12 @@ import { StackAlert } from '@kbn/alerts-as-data-utils'; import { CoreSetup, Logger } from '@kbn/core/server'; -import { AlertingSetup, StackAlertsStartDeps } from '../types'; +import { AlertingServerSetup, StackAlertsStartDeps } from '../types'; export interface RegisterRuleTypesParams { logger: Logger; data: Promise; - alerting: AlertingSetup; + alerting: AlertingServerSetup; core: CoreSetup; } diff --git a/x-pack/plugins/stack_alerts/server/types.ts b/x-pack/plugins/stack_alerts/server/types.ts index ce148fb8c043..1f4d2d291486 100644 --- a/x-pack/plugins/stack_alerts/server/types.ts +++ b/x-pack/plugins/stack_alerts/server/types.ts @@ -6,20 +6,19 @@ */ import { PluginStartContract as TriggersActionsUiStartContract } from '@kbn/triggers-actions-ui-plugin/server'; -import { PluginSetupContract as AlertingSetup } from '@kbn/alerting-plugin/server'; - export type { - PluginSetupContract as AlertingSetup, RuleType, RuleParamsAndRefs, RuleExecutorOptions, RuleTypeParams, + AlertingServerSetup, } from '@kbn/alerting-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server'; // this plugin's dependendencies export interface StackAlertsDeps { - alerting: AlertingSetup; + alerting: AlertingServerSetup; features: FeaturesPluginSetup; } diff --git a/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts b/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts index c221d74c3b8a..c5186edf4a37 100644 --- a/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts +++ b/x-pack/plugins/stack_connectors/common/crowdstrike/constants.ts @@ -13,4 +13,5 @@ export enum SUB_ACTION { GET_AGENT_DETAILS = 'getAgentDetails', HOST_ACTIONS = 'hostActions', GET_AGENT_ONLINE_STATUS = 'getAgentOnlineStatus', + EXECUTE_RTR_COMMAND = 'executeRTRCommand', } diff --git a/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts b/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts index 4e3d6464821b..d5e8cd693af9 100644 --- a/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts +++ b/x-pack/plugins/stack_connectors/common/crowdstrike/schema.ts @@ -17,7 +17,9 @@ export const CrowdstrikeSecretsSchema = schema.object({ clientSecret: schema.string(), }); -export const RelaxedCrowdstrikeBaseApiResponseSchema = schema.object({}, { unknowns: 'allow' }); +export const RelaxedCrowdstrikeBaseApiResponseSchema = schema.maybe( + schema.object({}, { unknowns: 'allow' }) +); export const CrowdstrikeBaseApiResponseSchema = schema.object( { resources: schema.arrayOf(schema.any()), @@ -231,6 +233,8 @@ export const CrowdstrikeHostActionsResponseSchema = schema.object( { unknowns: 'allow' } ); +// TODO temporary any value +export const CrowdstrikeRTRCommandParamsSchema = schema.any(); export const CrowdstrikeHostActionsParamsSchema = schema.object({ command: schema.oneOf([schema.literal('contain'), schema.literal('lift_containment')]), actionParameters: schema.maybe(schema.object({}, { unknowns: 'allow' })), @@ -261,3 +265,45 @@ export const CrowdstrikeHostActionsSchema = schema.object({ }); export const CrowdstrikeActionParamsSchema = schema.oneOf([CrowdstrikeHostActionsSchema]); + +export const CrowdstrikeInitRTRResponseSchema = schema.object( + { + meta: schema.maybe( + schema.object( + { + query_time: schema.maybe(schema.number()), + powered_by: schema.maybe(schema.string()), + trace_id: schema.maybe(schema.string()), + }, + { unknowns: 'allow' } + ) + ), + batch_id: schema.maybe(schema.string()), + resources: schema.maybe( + schema.recordOf( + schema.string(), + schema.object( + { + session_id: schema.maybe(schema.string()), + task_id: schema.maybe(schema.string()), + complete: schema.maybe(schema.boolean()), + stdout: schema.maybe(schema.string()), + stderr: schema.maybe(schema.string()), + base_command: schema.maybe(schema.string()), + aid: schema.maybe(schema.string()), + errors: schema.maybe(schema.arrayOf(schema.any())), + query_time: schema.maybe(schema.number()), + offline_queued: schema.maybe(schema.boolean()), + }, + { unknowns: 'allow' } + ) + ) + ), + errors: schema.maybe(schema.arrayOf(schema.any())), + }, + { unknowns: 'allow' } +); + +export const CrowdstrikeInitRTRParamsSchema = schema.object({ + endpoint_ids: schema.arrayOf(schema.string()), +}); diff --git a/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts b/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts index c0f98ee1b90a..3c9cc15ea167 100644 --- a/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts +++ b/x-pack/plugins/stack_connectors/common/crowdstrike/types.ts @@ -17,6 +17,8 @@ import { CrowdstrikeGetTokenResponseSchema, CrowdstrikeGetAgentsResponseSchema, RelaxedCrowdstrikeBaseApiResponseSchema, + CrowdstrikeInitRTRResponseSchema, + CrowdstrikeInitRTRParamsSchema, } from './schema'; export type CrowdstrikeConfig = TypeOf; @@ -33,7 +35,9 @@ export type CrowdstrikeGetAgentOnlineStatusResponse = TypeOf< typeof CrowdstrikeGetAgentOnlineStatusResponseSchema >; export type CrowdstrikeGetTokenResponse = TypeOf; +export type CrowdstrikeInitRTRResponse = TypeOf; export type CrowdstrikeHostActionsParams = TypeOf; export type CrowdstrikeActionParams = TypeOf; +export type CrowdstrikeInitRTRParams = TypeOf; diff --git a/x-pack/plugins/stack_connectors/common/experimental_features.ts b/x-pack/plugins/stack_connectors/common/experimental_features.ts index 9c81371b4b45..56f3ba247554 100644 --- a/x-pack/plugins/stack_connectors/common/experimental_features.ts +++ b/x-pack/plugins/stack_connectors/common/experimental_features.ts @@ -16,6 +16,7 @@ export const allowedExperimentalValues = Object.freeze({ sentinelOneConnectorOn: true, crowdstrikeConnectorOn: true, inferenceConnectorOn: false, + crowdstrikeConnectorRTROn: false, }); export type ExperimentalConfigKeys = Array; diff --git a/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts b/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts index d9dde5773d79..7daf615e01d3 100644 --- a/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts +++ b/x-pack/plugins/stack_connectors/common/sentinelone/schema.ts @@ -16,7 +16,9 @@ export const SentinelOneSecretsSchema = schema.object({ token: schema.string(), }); -export const SentinelOneBaseApiResponseSchema = schema.object({}, { unknowns: 'allow' }); +export const SentinelOneBaseApiResponseSchema = schema.maybe( + schema.object({}, { unknowns: 'allow' }) +); export const SentinelOneGetAgentsResponseSchema = schema.object( { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/email/use_email_config.test.ts b/x-pack/plugins/stack_connectors/public/connector_types/email/use_email_config.test.ts index ee5ba95bf577..0830b68fc1d5 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/email/use_email_config.test.ts +++ b/x-pack/plugins/stack_connectors/public/connector_types/email/use_email_config.test.ts @@ -6,7 +6,7 @@ */ import { httpServiceMock, notificationServiceMock } from '@kbn/core/public/mocks'; -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useEmailConfig } from './use_email_config'; const http = httpServiceMock.createStartContract(); @@ -16,6 +16,12 @@ const renderUseEmailConfigHook = (currentService?: string) => renderHook(() => useEmailConfig({ http, toasts })); describe('useEmailConfig', () => { + let res: ReturnType['getEmailServiceConfig']> extends Promise< + infer R + > + ? R + : never; + beforeEach(() => jest.clearAllMocks()); it('should return the correct result when requesting the config of a service', async () => { @@ -26,14 +32,16 @@ describe('useEmailConfig', () => { }); const { result } = renderUseEmailConfigHook(); + await act(async () => { - const res = await result.current.getEmailServiceConfig('gmail'); - expect(http.get).toHaveBeenCalledWith('/internal/stack_connectors/_email_config/gmail'); - expect(res).toEqual({ - host: 'smtp.gmail.com', - port: 465, - secure: true, - }); + res = await result.current.getEmailServiceConfig('gmail'); + }); + + expect(http.get).toHaveBeenCalledWith('/internal/stack_connectors/_email_config/gmail'); + expect(res).toEqual({ + host: 'smtp.gmail.com', + port: 465, + secure: true, }); }); @@ -44,14 +52,16 @@ describe('useEmailConfig', () => { }); const { result } = renderUseEmailConfigHook(); + await act(async () => { - const res = await result.current.getEmailServiceConfig('gmail'); - expect(http.get).toHaveBeenCalledWith('/internal/stack_connectors/_email_config/gmail'); - expect(res).toEqual({ - host: 'smtp.gmail.com', - port: 465, - secure: false, - }); + res = await result.current.getEmailServiceConfig('gmail'); + }); + + expect(http.get).toHaveBeenCalledWith('/internal/stack_connectors/_email_config/gmail'); + expect(res).toEqual({ + host: 'smtp.gmail.com', + port: 465, + secure: false, }); }); @@ -60,13 +70,14 @@ describe('useEmailConfig', () => { const { result } = renderUseEmailConfigHook(); await act(async () => { - const res = await result.current.getEmailServiceConfig('foo'); - expect(http.get).toHaveBeenCalledWith('/internal/stack_connectors/_email_config/foo'); - expect(res).toEqual({ - host: '', - port: 0, - secure: false, - }); + res = await result.current.getEmailServiceConfig('foo'); + }); + + expect(http.get).toHaveBeenCalledWith('/internal/stack_connectors/_email_config/foo'); + expect(res).toEqual({ + host: '', + port: 0, + secure: false, }); }); @@ -75,13 +86,13 @@ describe('useEmailConfig', () => { throw new Error('no!'); }); - const { result, waitForNextUpdate } = renderUseEmailConfigHook(); + const { result } = renderUseEmailConfigHook(); await act(async () => { result.current.getEmailServiceConfig('foo'); - await waitForNextUpdate(); - expect(toasts.addDanger).toHaveBeenCalled(); }); + + await waitFor(() => expect(toasts.addDanger).toHaveBeenCalled()); }); it('should not make an API call if the service is empty', async () => { diff --git a/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx b/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx index 7a3b1abfd800..fad8ed2f6597 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/inference/additional_options_fields.tsx @@ -111,7 +111,7 @@ export const AdditionalOptionsConnectorFields: React.FC { ])( 'fetches the %p dashboard and sets the dashboard URL with %p', async (selectedProvider, urlKey) => { - const { result, waitForNextUpdate } = renderHook(() => - useGetDashboard({ ...defaultArgs, selectedProvider }) - ); - await waitForNextUpdate(); - expect(mockDashboard).toHaveBeenCalledWith( - expect.objectContaining({ - connectorId, + const { result } = renderHook(() => useGetDashboard({ ...defaultArgs, selectedProvider })); + await waitFor(() => { + expect(mockDashboard).toHaveBeenCalledWith( + expect.objectContaining({ + connectorId, + dashboardId: `generative-ai-token-usage-${urlKey}-space`, + }) + ); + expect(mockGetRedirectUrl).toHaveBeenCalledWith({ + query: { + language: 'kuery', + query: `kibana.saved_objects: { id : ${connectorId} }`, + }, dashboardId: `generative-ai-token-usage-${urlKey}-space`, - }) - ); - expect(mockGetRedirectUrl).toHaveBeenCalledWith({ - query: { - language: 'kuery', - query: `kibana.saved_objects: { id : ${connectorId} }`, - }, - dashboardId: `generative-ai-token-usage-${urlKey}-space`, + }); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe( + `http://localhost:5601/app/dashboards#/view/generative-ai-token-usage-${urlKey}-space` + ); }); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe( - `http://localhost:5601/app/dashboards#/view/generative-ai-token-usage-${urlKey}-space` - ); } ); it('handles the case where the dashboard is not available.', async () => { mockDashboard.mockResolvedValue({ data: { available: false } }); - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard(defaultArgs)); - await waitForNextUpdate(); - expect(mockDashboard).toHaveBeenCalledWith( - expect.objectContaining({ - connectorId, - dashboardId: 'generative-ai-token-usage-openai-space', - }) - ); - expect(mockGetRedirectUrl).not.toHaveBeenCalled(); + const { result } = renderHook(() => useGetDashboard(defaultArgs)); + await waitFor(() => { + expect(mockDashboard).toHaveBeenCalledWith( + expect.objectContaining({ + connectorId, + dashboardId: 'generative-ai-token-usage-openai-space', + }) + ); + expect(mockGetRedirectUrl).not.toHaveBeenCalled(); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); }); it('handles the case where the spaces API is not available.', async () => { @@ -111,34 +111,35 @@ describe('useGetDashboard', () => { }); it('handles the case where connectorId is empty string', async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetDashboard({ ...defaultArgs, connectorId: '' }) - ); - await waitForNextUpdate(); - expect(mockDashboard).not.toHaveBeenCalled(); - expect(mockGetRedirectUrl).not.toHaveBeenCalled(); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); + const { result } = renderHook(() => useGetDashboard({ ...defaultArgs, connectorId: '' })); + await waitFor(() => { + expect(mockDashboard).not.toHaveBeenCalled(); + expect(mockGetRedirectUrl).not.toHaveBeenCalled(); + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); }); it('handles the case where the dashboard locator is not available.', async () => { mockKibana.mockReturnValue({ services: { ...mockServices, dashboard: {} }, }); - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard(defaultArgs)); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(false); - expect(result.current.dashboardUrl).toBe(null); + const { result } = renderHook(() => useGetDashboard(defaultArgs)); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(result.current.dashboardUrl).toBe(null); + }); }); it('correctly handles errors and displays the appropriate toast messages.', async () => { mockDashboard.mockRejectedValue(new Error('Error fetching dashboard')); - const { result, waitForNextUpdate } = renderHook(() => useGetDashboard(defaultArgs)); - await waitForNextUpdate(); - expect(result.current.isLoading).toBe(false); - expect(mockToasts.addDanger).toHaveBeenCalledWith({ - title: 'Error finding OpenAI Token Usage Dashboard.', - text: 'Error fetching dashboard', + const { result } = renderHook(() => useGetDashboard(defaultArgs)); + await waitFor(() => { + expect(result.current.isLoading).toBe(false); + expect(mockToasts.addDanger).toHaveBeenCalledWith({ + title: 'Error finding OpenAI Token Usage Dashboard.', + text: 'Error fetching dashboard', + }); }); }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_choices.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_choices.test.tsx index 721897ece726..3033cebd3ccf 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_choices.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_choices.test.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public/types'; -import { useChoices, UseChoices, UseChoicesProps } from './use_choices'; +import { useChoices } from './use_choices'; import { getChoices } from './api'; jest.mock('./api'); @@ -73,7 +73,7 @@ describe('UseChoices', () => { const fields = ['category']; it('init', async () => { - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useChoices({ http: services.http, actionConnector, @@ -82,13 +82,11 @@ describe('UseChoices', () => { }) ); - await waitForNextUpdate(); - - expect(result.current).toEqual(useChoicesResponse); + await waitFor(() => expect(result.current).toEqual(useChoicesResponse)); }); it('returns an empty array if the field is not in response', async () => { - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useChoices({ http: services.http, actionConnector, @@ -97,16 +95,16 @@ describe('UseChoices', () => { }) ); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - isLoading: false, - choices: { priority: [], category: getChoicesResponse }, - }); + await waitFor(() => + expect(result.current).toEqual({ + isLoading: false, + choices: { priority: [], category: getChoicesResponse }, + }) + ); }); it('returns an empty array when connector is not presented', async () => { - const { result } = renderHook(() => + const { result } = renderHook(() => useChoices({ http: services.http, actionConnector: undefined, @@ -127,7 +125,7 @@ describe('UseChoices', () => { serviceMessage: 'An error occurred', }); - const { waitForNextUpdate } = renderHook(() => + renderHook(() => useChoices({ http: services.http, actionConnector, @@ -136,12 +134,12 @@ describe('UseChoices', () => { }) ); - await waitForNextUpdate(); - - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - text: 'An error occurred', - title: 'Unable to get choices', - }); + await waitFor(() => + expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ + text: 'An error occurred', + title: 'Unable to get choices', + }) + ); }); it('it displays an error when http throws an error', async () => { @@ -149,7 +147,7 @@ describe('UseChoices', () => { throw new Error('An error occurred'); }); - renderHook(() => + renderHook(() => useChoices({ http: services.http, actionConnector, @@ -158,9 +156,11 @@ describe('UseChoices', () => { }) ); - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - text: 'An error occurred', - title: 'Unable to get choices', - }); + await waitFor(() => + expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ + text: 'An error occurred', + title: 'Unable to get choices', + }) + ); }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_app_info.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_app_info.test.tsx index c8c061c9d07f..c4cf65a59133 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_app_info.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_app_info.test.tsx @@ -5,9 +5,9 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; -import { useGetAppInfo, UseGetAppInfo, UseGetAppInfoProps } from './use_get_app_info'; +import { useGetAppInfo } from './use_get_app_info'; import { getAppInfo } from './api'; import { ServiceNowActionConnector } from './types'; import { httpServiceMock } from '@kbn/core/public/mocks'; @@ -50,7 +50,7 @@ describe('useGetAppInfo', () => { }); it('init', async () => { - const { result } = renderHook(() => + const { result } = renderHook(() => useGetAppInfo({ actionTypeId, http, @@ -64,7 +64,7 @@ describe('useGetAppInfo', () => { }); it('returns the application information', async () => { - const { result } = renderHook(() => + const { result } = renderHook(() => useGetAppInfo({ actionTypeId, http, @@ -86,7 +86,7 @@ describe('useGetAppInfo', () => { throw new Error('An error occurred'); }); - const { result } = renderHook(() => + const { result } = renderHook(() => useGetAppInfo({ actionTypeId, http, @@ -108,7 +108,7 @@ describe('useGetAppInfo', () => { throw error; }); - const { result } = renderHook(() => + const { result } = renderHook(() => useGetAppInfo({ actionTypeId, http, diff --git a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_choices.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_choices.test.tsx index 38ea6d55b4e1..fd9808139b8b 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_choices.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/lib/servicenow/use_get_choices.test.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public'; import { ActionConnector } from '@kbn/triggers-actions-ui-plugin/public/types'; -import { useGetChoices, UseGetChoices, UseGetChoicesProps } from './use_get_choices'; +import { useGetChoices } from './use_get_choices'; import { getChoices } from './api'; jest.mock('./api'); @@ -69,7 +69,7 @@ describe('useGetChoices', () => { const fields = ['priority']; it('init', async () => { - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useGetChoices({ http: services.http, actionConnector, @@ -79,16 +79,16 @@ describe('useGetChoices', () => { }) ); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - isLoading: false, - choices: getChoicesResponse, - }); + await waitFor(() => + expect(result.current).toEqual({ + isLoading: false, + choices: getChoicesResponse, + }) + ); }); it('returns an empty array when connector is not presented', async () => { - const { result } = renderHook(() => + const { result } = renderHook(() => useGetChoices({ http: services.http, actionConnector: undefined, @@ -105,7 +105,7 @@ describe('useGetChoices', () => { }); it('it calls onSuccess', async () => { - const { waitForNextUpdate } = renderHook(() => + renderHook(() => useGetChoices({ http: services.http, actionConnector, @@ -115,9 +115,7 @@ describe('useGetChoices', () => { }) ); - await waitForNextUpdate(); - - expect(onSuccess).toHaveBeenCalledWith(getChoicesResponse); + await waitFor(() => expect(onSuccess).toHaveBeenCalledWith(getChoicesResponse)); }); it('it displays an error when service fails', async () => { @@ -126,7 +124,7 @@ describe('useGetChoices', () => { serviceMessage: 'An error occurred', }); - const { waitForNextUpdate } = renderHook(() => + renderHook(() => useGetChoices({ http: services.http, actionConnector, @@ -136,12 +134,12 @@ describe('useGetChoices', () => { }) ); - await waitForNextUpdate(); - - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - text: 'An error occurred', - title: 'Unable to get choices', - }); + await waitFor(() => + expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ + text: 'An error occurred', + title: 'Unable to get choices', + }) + ); }); it('it displays an error when http throws an error', async () => { @@ -149,7 +147,7 @@ describe('useGetChoices', () => { throw new Error('An error occurred'); }); - renderHook(() => + renderHook(() => useGetChoices({ http: services.http, actionConnector, @@ -159,10 +157,12 @@ describe('useGetChoices', () => { }) ); - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - text: 'An error occurred', - title: 'Unable to get choices', - }); + await waitFor(() => + expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ + text: 'An error occurred', + title: 'Unable to get choices', + }) + ); }); it('returns an empty array if the response is not an array', async () => { @@ -171,7 +171,7 @@ describe('useGetChoices', () => { data: {}, }); - const { result } = renderHook(() => + const { result } = renderHook(() => useGetChoices({ http: services.http, actionConnector: undefined, @@ -181,9 +181,11 @@ describe('useGetChoices', () => { }) ); - expect(result.current).toEqual({ - isLoading: false, - choices: [], + await waitFor(() => { + expect(result.current).toEqual({ + isLoading: false, + choices: [], + }); }); }); }); diff --git a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/use_get_application.test.tsx b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/use_get_application.test.tsx index 82e514ec51fd..db33c7aa6801 100644 --- a/x-pack/plugins/stack_connectors/public/connector_types/swimlane/use_get_application.test.tsx +++ b/x-pack/plugins/stack_connectors/public/connector_types/swimlane/use_get_application.test.tsx @@ -5,11 +5,11 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'; import { getApplication } from './api'; -import { useGetApplication, UseGetApplication } from './use_get_application'; +import { useGetApplication } from './use_get_application'; jest.mock('./api'); jest.mock('@kbn/triggers-actions-ui-plugin/public/common/lib/kibana'); @@ -43,87 +43,86 @@ describe('useGetApplication', () => { }); it('init', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetApplication({ - toastNotifications: services.notifications.toasts, - }) - ); - - await waitForNextUpdate(); - expect(result.current).toEqual({ - isLoading: false, - getApplication: result.current.getApplication, - }); + const { result } = renderHook(() => + useGetApplication({ + toastNotifications: services.notifications.toasts, + }) + ); + + expect(result.current).toEqual({ + isLoading: false, + getApplication: result.current.getApplication, }); }); it('calls getApplication with correct arguments', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetApplication({ - toastNotifications: services.notifications.toasts, - }) - ); + const { result } = renderHook(() => + useGetApplication({ + toastNotifications: services.notifications.toasts, + }) + ); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); + act(() => { result.current.getApplication({ appId: action.config.appId, apiToken: action.secrets.apiToken, apiUrl: action.config.apiUrl, }); + }); - await waitForNextUpdate(); + await waitFor(() => expect(getApplicationMock).toBeCalledWith({ signal: abortCtrl.signal, appId: action.config.appId, apiToken: action.secrets.apiToken, url: action.config.apiUrl, - }); - }); + }) + ); }); it('get application', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetApplication({ - toastNotifications: services.notifications.toasts, - }) - ); - - await waitForNextUpdate(); + const { result } = renderHook(() => + useGetApplication({ + toastNotifications: services.notifications.toasts, + }) + ); + + await waitFor(() => new Promise((resolve) => resolve(null))); + act(() => { result.current.getApplication({ appId: action.config.appId, apiToken: action.secrets.apiToken, apiUrl: action.config.apiUrl, }); - await waitForNextUpdate(); - + }); + await waitFor(() => expect(result.current).toEqual({ isLoading: false, getApplication: result.current.getApplication, - }); - }); + }) + ); }); it('set isLoading to true when getting the application', async () => { - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetApplication({ - toastNotifications: services.notifications.toasts, - }) - ); - - await waitForNextUpdate(); + const { result } = renderHook(() => + useGetApplication({ + toastNotifications: services.notifications.toasts, + }) + ); + + await waitFor(() => new Promise((resolve) => resolve(null))); + + act(() => { result.current.getApplication({ appId: action.config.appId, apiToken: action.secrets.apiToken, apiUrl: action.config.apiUrl, }); - - expect(result.current.isLoading).toBe(true); }); + + expect(result.current.isLoading).toBe(true); }); it('it displays an error when http throws an error', async () => { @@ -131,52 +130,52 @@ describe('useGetApplication', () => { throw new Error('Something went wrong'); }); - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetApplication({ - toastNotifications: services.notifications.toasts, - }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => + useGetApplication({ + toastNotifications: services.notifications.toasts, + }) + ); + await waitFor(() => new Promise((resolve) => resolve(null))); + act(() => { result.current.getApplication({ appId: action.config.appId, apiToken: action.secrets.apiToken, apiUrl: action.config.apiUrl, }); + }); - expect(result.current).toEqual({ - isLoading: false, - getApplication: result.current.getApplication, - }); + expect(result.current).toEqual({ + isLoading: false, + getApplication: result.current.getApplication, + }); - expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ - title: 'Unable to get application with id bcq16kdTbz5jlwM6h', - text: 'Something went wrong', - }); + expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ + title: 'Unable to get application with id bcq16kdTbz5jlwM6h', + text: 'Something went wrong', }); }); it('it displays an error when the response does not contain the correct fields', async () => { getApplicationMock.mockResolvedValue({}); - await act(async () => { - const { result, waitForNextUpdate } = renderHook(() => - useGetApplication({ - toastNotifications: services.notifications.toasts, - }) - ); - await waitForNextUpdate(); + const { result } = renderHook(() => + useGetApplication({ + toastNotifications: services.notifications.toasts, + }) + ); + await waitFor(() => new Promise((resolve) => resolve(null))); + act(() => { result.current.getApplication({ appId: action.config.appId, apiToken: action.secrets.apiToken, apiUrl: action.config.apiUrl, }); - await waitForNextUpdate(); - + }); + await waitFor(() => expect(services.notifications.toasts.addDanger).toHaveBeenCalledWith({ title: 'Unable to get application with id bcq16kdTbz5jlwM6h', text: 'Unable to get application fields', - }); - }); + }) + ); }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts index 0c3d851981fd..eec431d8a4dc 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.test.ts @@ -18,14 +18,18 @@ const onlineStatusPath = 'https://api.crowdstrike.com/devices/entities/online-st const actionsPath = 'https://api.crowdstrike.com/devices/entities/devices-actions/v2'; describe('CrowdstrikeConnector', () => { const logger = loggingSystemMock.createLogger(); - const connector = new CrowdstrikeConnector({ - configurationUtilities: actionsConfigMock.create(), - connector: { id: '1', type: CROWDSTRIKE_CONNECTOR_ID }, - config: { url: 'https://api.crowdstrike.com' }, - secrets: { clientId: '123', clientSecret: 'secret' }, - logger, - services: actionsMock.createServices(), - }); + const connector = new CrowdstrikeConnector( + { + configurationUtilities: actionsConfigMock.create(), + connector: { id: '1', type: CROWDSTRIKE_CONNECTOR_ID }, + config: { url: 'https://api.crowdstrike.com' }, + secrets: { clientId: '123', clientSecret: 'secret' }, + logger, + services: actionsMock.createServices(), + }, + // @ts-expect-error passing a true value just for testing purposes + { crowdstrikeConnectorRTROn: true } + ); let mockedRequest: jest.Mock; let connectorUsageCollector: ConnectorUsageCollector; @@ -341,4 +345,70 @@ describe('CrowdstrikeConnector', () => { expect(mockedRequest).toHaveBeenCalledTimes(3); }); }); + describe('batchInitRTRSession', () => { + it('should make a POST request to the correct URL with correct data', async () => { + const mockResponse = { data: { batch_id: 'testBatchId' } }; + mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); + mockedRequest.mockResolvedValueOnce(mockResponse); + + await connector.batchInitRTRSession( + { endpoint_ids: ['id1', 'id2'] }, + connectorUsageCollector + ); + + expect(mockedRequest).toHaveBeenNthCalledWith( + 1, + expect.objectContaining({ + headers: { + accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + authorization: expect.any(String), + }, + method: 'post', + responseSchema: expect.any(Object), + url: tokenPath, + }), + connectorUsageCollector + ); + expect(mockedRequest).toHaveBeenNthCalledWith( + 2, + expect.objectContaining({ + url: 'https://api.crowdstrike.com/real-time-response/combined/batch-init-session/v1', + method: 'post', + data: { host_ids: ['id1', 'id2'] }, + paramsSerializer: expect.any(Function), + responseSchema: expect.any(Object), + }), + connectorUsageCollector + ); + // @ts-expect-error private static - but I still want to test it + expect(CrowdstrikeConnector.currentBatchId).toBe('testBatchId'); + }); + + it('should handle error when fetching batch init session', async () => { + mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); + mockedRequest.mockRejectedValueOnce(new Error('Failed to fetch batch init session')); + + await expect( + connector.batchInitRTRSession({ endpoint_ids: ['id1', 'id2'] }, connectorUsageCollector) + ).rejects.toThrow('Failed to fetch batch init session'); + }); + + it('should retry once if token is invalid', async () => { + const mockResponse = { data: { batch_id: 'testBatchId' } }; + mockedRequest.mockResolvedValueOnce({ data: { access_token: 'testToken' } }); + mockedRequest.mockRejectedValueOnce({ code: 401 }); + mockedRequest.mockResolvedValueOnce({ data: { access_token: 'newTestToken' } }); + mockedRequest.mockResolvedValueOnce(mockResponse); + + await connector.batchInitRTRSession( + { endpoint_ids: ['id1', 'id2'] }, + connectorUsageCollector + ); + + expect(mockedRequest).toHaveBeenCalledTimes(4); + // @ts-expect-error private static - but I still want to test it + expect(CrowdstrikeConnector.currentBatchId).toBe('testBatchId'); + }); + }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts index a4fc84ae6a49..bd1f6613d5f0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/crowdstrike.ts @@ -10,6 +10,8 @@ import { ServiceParams, SubActionConnector } from '@kbn/actions-plugin/server'; import type { AxiosError } from 'axios'; import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; +import { CrowdStrikeSessionManager } from './rtr_session_manager'; +import { ExperimentalFeatures } from '../../../common/experimental_features'; import { isAggregateError, NodeSystemError } from './types'; import type { CrowdstrikeConfig, @@ -20,6 +22,7 @@ import type { CrowdstrikeGetTokenResponse, CrowdstrikeGetAgentOnlineStatusResponse, RelaxedCrowdstrikeBaseApiResponse, + CrowdstrikeInitRTRParams, } from '../../../common/crowdstrike/types'; import { CrowdstrikeHostActionsParamsSchema, @@ -27,6 +30,8 @@ import { CrowdstrikeGetTokenResponseSchema, CrowdstrikeHostActionsResponseSchema, RelaxedCrowdstrikeBaseApiResponseSchema, + CrowdstrikeInitRTRResponseSchema, + CrowdstrikeRTRCommandParamsSchema, } from '../../../common/crowdstrike/schema'; import { SUB_ACTION } from '../../../common/crowdstrike/constants'; import { CrowdstrikeError } from './error'; @@ -51,21 +56,34 @@ export class CrowdstrikeConnector extends SubActionConnector< > { private static token: string | null; private static tokenExpiryTimeout: NodeJS.Timeout; + // @ts-expect-error not used at the moment, will be used in a follow up PR + private static currentBatchId: string | undefined; private static base64encodedToken: string; + private experimentalFeatures: ExperimentalFeatures; + + private crowdStrikeSessionManager: CrowdStrikeSessionManager; private urls: { getToken: string; agents: string; hostAction: string; agentStatus: string; + batchInitRTRSession: string; + batchRefreshRTRSession: string; }; - constructor(params: ServiceParams) { + constructor( + params: ServiceParams, + experimentalFeatures: ExperimentalFeatures + ) { super(params); + this.experimentalFeatures = experimentalFeatures; this.urls = { getToken: `${this.config.url}/oauth2/token`, hostAction: `${this.config.url}/devices/entities/devices-actions/v2`, agents: `${this.config.url}/devices/entities/devices/v2`, agentStatus: `${this.config.url}/devices/entities/online-state/v1`, + batchInitRTRSession: `${this.config.url}/real-time-response/combined/batch-init-session/v1`, + batchRefreshRTRSession: `${this.config.url}/real-time-response/combined/batch-refresh-session/v1`, }; if (!CrowdstrikeConnector.base64encodedToken) { @@ -74,6 +92,10 @@ export class CrowdstrikeConnector extends SubActionConnector< ).toString('base64'); } + this.crowdStrikeSessionManager = new CrowdStrikeSessionManager( + this.urls, + this.crowdstrikeApiRequest + ); this.registerSubActions(); } @@ -95,6 +117,14 @@ export class CrowdstrikeConnector extends SubActionConnector< method: 'getAgentOnlineStatus', schema: CrowdstrikeGetAgentsParamsSchema, }); + + if (this.experimentalFeatures.crowdstrikeConnectorRTROn) { + this.registerSubAction({ + name: SUB_ACTION.EXECUTE_RTR_COMMAND, + method: 'executeRTRCommand', + schema: CrowdstrikeRTRCommandParamsSchema, // Define a proper schema for the command + }); + } } public async executeHostActions( @@ -206,6 +236,11 @@ export class CrowdstrikeConnector extends SubActionConnector< const response = await this.request( { ...req, + // We don't validate responses from Crowdstrike API's because we do not want failures for cases + // where the external system might add/remove/change values in the response that we have no + // control over. + responseSchema: + RelaxedCrowdstrikeBaseApiResponseSchema as unknown as SubActionRequestParams['responseSchema'], headers: { ...req.headers, Authorization: `Bearer ${CrowdstrikeConnector.token}`, @@ -224,6 +259,39 @@ export class CrowdstrikeConnector extends SubActionConnector< } } + public async batchInitRTRSession( + payload: CrowdstrikeInitRTRParams, + connectorUsageCollector: ConnectorUsageCollector + ) { + const response = await this.crowdstrikeApiRequest( + { + url: this.urls.batchInitRTRSession, + method: 'post', + data: { + host_ids: payload.endpoint_ids, + }, + paramsSerializer, + responseSchema: CrowdstrikeInitRTRResponseSchema, + }, + connectorUsageCollector + ); + + CrowdstrikeConnector.currentBatchId = response.batch_id; + } + + // TODO: WIP - just to have session init logic in place + public async executeRTRCommand( + payload: { command: string; endpoint_ids: string[] }, + connectorUsageCollector: ConnectorUsageCollector + ) { + const batchId = await this.crowdStrikeSessionManager.initializeSession( + { endpoint_ids: payload.endpoint_ids }, + connectorUsageCollector + ); + + return Promise.resolve({ batchId }); + } + protected getResponseErrorMessage( error: AxiosError<{ errors: Array<{ message: string; code: number }> }> ): string { diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/index.ts index f7c50478979c..0617822837c0 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/index.ts @@ -11,6 +11,7 @@ import { } from '@kbn/actions-plugin/server/sub_action_framework/types'; import { SecurityConnectorFeatureId } from '@kbn/actions-plugin/common'; import { urlAllowListValidator } from '@kbn/actions-plugin/server'; +import { ExperimentalFeatures } from '../../../common/experimental_features'; import { CROWDSTRIKE_CONNECTOR_ID, CROWDSTRIKE_TITLE } from '../../../common/crowdstrike/constants'; import { CrowdstrikeConfigSchema, @@ -19,13 +20,12 @@ import { import { CrowdstrikeConfig, CrowdstrikeSecrets } from '../../../common/crowdstrike/types'; import { CrowdstrikeConnector } from './crowdstrike'; -export const getCrowdstrikeConnectorType = (): SubActionConnectorType< - CrowdstrikeConfig, - CrowdstrikeSecrets -> => ({ +export const getCrowdstrikeConnectorType = ( + experimentalFeatures: ExperimentalFeatures +): SubActionConnectorType => ({ id: CROWDSTRIKE_CONNECTOR_ID, name: CROWDSTRIKE_TITLE, - getService: (params) => new CrowdstrikeConnector(params), + getService: (params) => new CrowdstrikeConnector(params, experimentalFeatures), schema: { config: CrowdstrikeConfigSchema, secrets: CrowdstrikeSecretsSchema, diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/rtr_session_manager.test.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/rtr_session_manager.test.ts new file mode 100644 index 000000000000..c5ba7b112c94 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/rtr_session_manager.test.ts @@ -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 { CrowdStrikeSessionManager } from './rtr_session_manager'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; +import { CrowdstrikeInitRTRResponseSchema } from '../../../common/crowdstrike/schema'; + +// There is a lot of logic in private fields/methods of CrowdStrikeSessionManager that we need to test. +class TestableCrowdStrikeSessionManager extends CrowdStrikeSessionManager { + // Expose private fields + public getCurrentBatchId(): string | null { + return this.currentBatchId; + } + + public getRefreshInterval(): NodeJS.Timeout | null { + return this.refreshInterval; + } + + public getCloseSessionTimeout(): NodeJS.Timeout | null { + return this.closeSessionTimeout; + } + + // Expose private methods + public callStartRefreshInterval(connectorUsageCollector: ConnectorUsageCollector): void { + this.startRefreshInterval(connectorUsageCollector); + } + + public callResetCloseSessionTimeout(): void { + this.resetCloseSessionTimeout(); + } + + public async callRefreshSession(connectorUsageCollector: ConnectorUsageCollector): Promise { + await this.refreshSession(connectorUsageCollector); + } + + public async callTerminateSession(): Promise { + await this.terminateSession(); + } +} + +jest.useFakeTimers(); + +describe('CrowdstrikeSessionManager', () => { + const mockUrls = { + batchInitRTRSession: 'https://api.example.com/init', + batchRefreshRTRSession: 'https://api.example.com/refresh', + }; + + let mockApiRequest: jest.Mock; + let mockConnectorUsageCollector: ConnectorUsageCollector; + let sessionManager: TestableCrowdStrikeSessionManager; + + beforeEach(() => { + jest.clearAllMocks(); // Clear mocks to reset timer calls + + mockApiRequest = jest.fn(); + mockConnectorUsageCollector = {} as ConnectorUsageCollector; + + sessionManager = new TestableCrowdStrikeSessionManager(mockUrls, mockApiRequest); + }); + + describe('initializeSession', () => { + it('should initialize a session if no current batch ID exists', async () => { + const mockResponse = { batch_id: 'mock-batch-id' }; + mockApiRequest.mockResolvedValueOnce(mockResponse); + + const payload = { endpoint_ids: ['endpoint1', 'endpoint2'] }; + const result = await sessionManager.initializeSession(payload, mockConnectorUsageCollector); + + expect(mockApiRequest).toHaveBeenCalledWith( + { + url: mockUrls.batchInitRTRSession, + method: 'post', + data: { host_ids: payload.endpoint_ids }, + responseSchema: CrowdstrikeInitRTRResponseSchema, + }, + mockConnectorUsageCollector + ); + + expect(result).toEqual('mock-batch-id'); + expect(sessionManager.getCurrentBatchId()).toEqual('mock-batch-id'); + }); + + it('should reset the close session timeout after initialization', async () => { + const mockResponse = { batch_id: 'mock-batch-id' }; + mockApiRequest.mockResolvedValueOnce(mockResponse); + + const payload = { endpoint_ids: ['endpoint1', 'endpoint2'] }; + await sessionManager.initializeSession(payload, mockConnectorUsageCollector); + + // Advance timers to simulate the timeout trigger + jest.advanceTimersByTime(10 * 60 * 1000); // 10 minutes + + expect(sessionManager.getCloseSessionTimeout()).toBeNull(); + }); + }); + + describe('terminateSession', () => { + it('should clear refresh interval and close session timeout', async () => { + sessionManager.callResetCloseSessionTimeout(); + sessionManager.callStartRefreshInterval(mockConnectorUsageCollector); + + await sessionManager.callTerminateSession(); + + // Verify both timers were cleared + expect(sessionManager.getRefreshInterval()).toBeNull(); + expect(sessionManager.getCloseSessionTimeout()).toBeNull(); + }); + }); + + describe('startRefreshInterval', () => { + it('should start a new refresh interval', () => { + sessionManager.callStartRefreshInterval(mockConnectorUsageCollector); + + // Simulate timer triggering + jest.advanceTimersByTime(5 * 60 * 1000); // 5 minutes + + // Validate that `refreshSession` was called + expect(mockApiRequest).toHaveBeenCalledWith( + { + url: mockUrls.batchRefreshRTRSession, + method: 'post', + data: { batch_id: null }, + responseSchema: CrowdstrikeInitRTRResponseSchema, + }, + mockConnectorUsageCollector + ); + }); + + it('should clear any existing refresh interval before starting a new one', () => { + // Spy on clearInterval to verify it was called + const clearIntervalSpy = jest.spyOn(global, 'clearInterval'); + + expect(sessionManager.getRefreshInterval()).toBeNull(); + + // Start the first interval + sessionManager.callStartRefreshInterval(mockConnectorUsageCollector); + const firstInterval = sessionManager.getRefreshInterval(); + expect(firstInterval).not.toBeNull(); + + // Start another interval + sessionManager.callStartRefreshInterval(mockConnectorUsageCollector); + const secondInterval = sessionManager.getRefreshInterval(); + + // Ensure a new interval was set + expect(secondInterval).not.toBeNull(); + expect(secondInterval).not.toBe(firstInterval); // Verify the interval changed + + // Verify clearInterval was called with the first interval + expect(clearIntervalSpy).toHaveBeenCalledWith(firstInterval); + }); + }); + + describe('resetCloseSessionTimeout', () => { + it('should set a timeout to terminate the session after 10 minutes of inactivity', () => { + sessionManager.callResetCloseSessionTimeout(); + + // Fast forward time to simulate timeout execution + jest.advanceTimersByTime(10 * 60 * 1000); // 10 minutes + + // Ensure timeout was triggered + expect(sessionManager.getCloseSessionTimeout()).toBeNull(); + }); + + it('should clear any existing timeout before setting a new one', () => { + // Set the first timeout + sessionManager.callResetCloseSessionTimeout(); + + const firstTimeout = sessionManager.getCloseSessionTimeout(); + expect(firstTimeout).not.toBeNull(); + + // Set another timeout, which should replace the first one + sessionManager.callResetCloseSessionTimeout(); + + const secondTimeout = sessionManager.getCloseSessionTimeout(); + expect(secondTimeout).not.toBe(firstTimeout); + + // Simulate timeout expiration + jest.advanceTimersByTime(10 * 60 * 1000); // 10 minutes + expect(sessionManager.getCloseSessionTimeout()).toBeNull(); + }); + }); +}); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/rtr_session_manager.ts b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/rtr_session_manager.ts new file mode 100644 index 000000000000..6830049f2e51 --- /dev/null +++ b/x-pack/plugins/stack_connectors/server/connector_types/crowdstrike/rtr_session_manager.ts @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SubActionRequestParams } from '@kbn/actions-plugin/server/sub_action_framework/types'; +import { ConnectorUsageCollector } from '@kbn/actions-plugin/server/types'; +import { CrowdstrikeInitRTRResponseSchema } from '../../../common/crowdstrike/schema'; +import { + CrowdstrikeInitRTRParams, + RelaxedCrowdstrikeBaseApiResponse, +} from '../../../common/crowdstrike/types'; + +export class CrowdStrikeSessionManager { + protected currentBatchId: string | null = null; + protected refreshInterval: NodeJS.Timeout | null = null; + protected closeSessionTimeout: NodeJS.Timeout | null = null; + + constructor( + private urls: { batchInitRTRSession: string; batchRefreshRTRSession: string }, + private apiRequest: ( + req: SubActionRequestParams, + connectorUsageCollector: ConnectorUsageCollector, + retried?: boolean + ) => Promise + ) {} + + async initializeSession( + payload: CrowdstrikeInitRTRParams, + connectorUsageCollector: ConnectorUsageCollector + ): Promise { + if (!this.currentBatchId) { + // Make a request to initialize the session + const response = await this.apiRequest( + { + url: this.urls.batchInitRTRSession, + method: 'post', + data: { + host_ids: payload.endpoint_ids, + }, + responseSchema: CrowdstrikeInitRTRResponseSchema, + }, + connectorUsageCollector + ); + + this.currentBatchId = response.batch_id!; + + // Start the refresh interval + this.startRefreshInterval(connectorUsageCollector); + } + + // Reset the close session timeout + this.resetCloseSessionTimeout(); + + return this.currentBatchId; + } + + protected startRefreshInterval(connectorUsageCollector: ConnectorUsageCollector) { + if (this.refreshInterval) { + clearInterval(this.refreshInterval); + } + + this.refreshInterval = setInterval(() => { + this.refreshSession(connectorUsageCollector).catch(() => {}); + }, 5 * 60 * 1000); // Refresh every 5 minutes + } + + protected async refreshSession(connectorUsageCollector: ConnectorUsageCollector): Promise { + await this.apiRequest( + { + url: this.urls.batchRefreshRTRSession, + method: 'post', + data: { + batch_id: this.currentBatchId, + }, + responseSchema: CrowdstrikeInitRTRResponseSchema, + }, + connectorUsageCollector + ); + } + + protected resetCloseSessionTimeout() { + if (this.closeSessionTimeout) { + clearTimeout(this.closeSessionTimeout); + } + + this.closeSessionTimeout = setTimeout(() => { + this.terminateSession().catch(() => {}); + }, 10 * 60 * 1000); // Close session after 10 minutes of inactivity + } + + protected async terminateSession(): Promise { + // Clear intervals and timeouts + if (this.refreshInterval) { + clearInterval(this.refreshInterval); + this.refreshInterval = null; + } + + if (this.closeSessionTimeout) { + clearTimeout(this.closeSessionTimeout); + this.closeSessionTimeout = null; + } + } +} diff --git a/x-pack/plugins/stack_connectors/server/connector_types/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/index.ts index 09d8a44c2a28..08b0331f1cf2 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/index.ts @@ -63,6 +63,7 @@ export { ConnectorTypeId as WebhookConnectorTypeId } from './webhook'; export type { ActionParamsType as WebhookActionParams } from './webhook/types'; export { ConnectorTypeId as XmattersConnectorTypeId } from './xmatters'; export type { ActionParamsType as XmattersActionParams } from './xmatters'; +export { OpsgenieConnectorTypeId } from './opsgenie'; export type { OpsgenieActionConfig, @@ -117,7 +118,7 @@ export function registerConnectorTypes({ actions.registerSubActionConnectorType(getSentinelOneConnectorType()); } if (experimentalFeatures.crowdstrikeConnectorOn) { - actions.registerSubActionConnectorType(getCrowdstrikeConnectorType()); + actions.registerSubActionConnectorType(getCrowdstrikeConnectorType(experimentalFeatures)); } if (experimentalFeatures.inferenceConnectorOn) { actions.registerSubActionConnectorType(getInferenceConnectorType()); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/index.ts b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/index.ts index 7e92a3b7f333..9570e0033f53 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/index.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/opsgenie/index.ts @@ -39,6 +39,8 @@ export const getOpsgenieConnectorType = (): SubActionConnectorType { params: { APIToken: 'token-abc', }, - responseSchema: SentinelOneGetActivitiesResponseSchema, + responseSchema: expect.any(Object), }); }); diff --git a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts index dd73bafae8d2..42d946edbc78 100644 --- a/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts +++ b/x-pack/plugins/stack_connectors/server/connector_types/sentinelone/sentinelone.ts @@ -43,6 +43,7 @@ import { SentinelOneGetRemoteScriptResultsParamsSchema, SentinelOneDownloadRemoteScriptResultsParamsSchema, SentinelOneDownloadRemoteScriptResultsResponseSchema, + SentinelOneBaseApiResponseSchema, } from '../../../common/sentinelone/schema'; import { SUB_ACTION } from '../../../common/sentinelone/constants'; import { @@ -400,6 +401,11 @@ export class SentinelOneConnector extends SubActionConnector< const response = await this.request( { ...req, + // We don't validate responses from SentinelOne API's because we do not want failures for cases + // where the external system might add/remove/change values in the response that we have no + // control over. + responseSchema: + SentinelOneBaseApiResponseSchema as unknown as SubActionRequestParams['responseSchema'], params: { ...req.params, APIToken: this.secrets.token, diff --git a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/index.ts b/x-pack/plugins/streams/common/index.ts similarity index 82% rename from x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/index.ts rename to x-pack/plugins/streams/common/index.ts index 59ac4e0e37ef..3a7306e46cae 100644 --- a/x-pack/plugins/enterprise_search/public/applications/enterprise_search_overview/components/error_connecting/index.ts +++ b/x-pack/plugins/streams/common/index.ts @@ -5,4 +5,4 @@ * 2.0. */ -export { ErrorConnecting } from './error_connecting'; +export type { StreamDefinition } from './types'; diff --git a/x-pack/plugins/streams/common/types.ts b/x-pack/plugins/streams/common/types.ts index 6cdb2f923f6f..c2d99d4ba1d8 100644 --- a/x-pack/plugins/streams/common/types.ts +++ b/x-pack/plugins/streams/common/types.ts @@ -9,13 +9,25 @@ import { z } from '@kbn/zod'; const stringOrNumberOrBoolean = z.union([z.string(), z.number(), z.boolean()]); -export const filterConditionSchema = z.object({ +export const binaryConditionSchema = z.object({ field: z.string(), operator: z.enum(['eq', 'neq', 'lt', 'lte', 'gt', 'gte', 'contains', 'startsWith', 'endsWith']), value: stringOrNumberOrBoolean, }); +export const unaryFilterConditionSchema = z.object({ + field: z.string(), + operator: z.enum(['exists', 'notExists']), +}); + +export const filterConditionSchema = z.discriminatedUnion('operator', [ + unaryFilterConditionSchema, + binaryConditionSchema, +]); + export type FilterCondition = z.infer; +export type BinaryFilterCondition = z.infer; +export type UnaryFilterCondition = z.infer; export interface AndCondition { and: Condition[]; @@ -72,7 +84,7 @@ export const streamWithoutIdDefinitonSchema = z.object({ .array( z.object({ id: z.string(), - condition: conditionSchema, + condition: z.optional(conditionSchema), }) ) .default([]), @@ -82,6 +94,15 @@ export type StreamWithoutIdDefinition = z.infer; export const streamDefinitonSchema = streamWithoutIdDefinitonSchema.extend({ id: z.string(), + managed: z.boolean().default(true), + unmanaged_elasticsearch_assets: z.optional( + z.array( + z.object({ + type: z.enum(['ingest_pipeline', 'component_template', 'index_template', 'data_stream']), + id: z.string(), + }) + ) + ), }); export type StreamDefinition = z.infer; diff --git a/x-pack/plugins/streams/public/api/index.ts b/x-pack/plugins/streams/public/api/index.ts new file mode 100644 index 000000000000..f64fc7f2fdce --- /dev/null +++ b/x-pack/plugins/streams/public/api/index.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreSetup, CoreStart, HttpFetchOptions } from '@kbn/core/public'; +import type { + ClientRequestParamsOf, + ReturnOf, + RouteRepositoryClient, +} from '@kbn/server-route-repository'; +import { createRepositoryClient } from '@kbn/server-route-repository-client'; +import type { StreamsRouteRepository } from '../../server'; + +type FetchOptions = Omit & { + body?: any; +}; + +export type StreamsRepositoryClientOptions = Omit< + FetchOptions, + 'query' | 'body' | 'pathname' | 'signal' +> & { + signal: AbortSignal | null; +}; + +export type StreamsRepositoryClient = RouteRepositoryClient< + StreamsRouteRepository, + StreamsRepositoryClientOptions +>; + +export type AutoAbortedStreamsRepositoryClient = RouteRepositoryClient< + StreamsRouteRepository, + Omit +>; + +export type StreamsRepositoryEndpoint = keyof StreamsRouteRepository; + +export type APIReturnType = ReturnOf< + StreamsRouteRepository, + TEndpoint +>; + +export type StreamsAPIClientRequestParamsOf = + ClientRequestParamsOf; + +export function createStreamsRepositoryClient( + core: CoreStart | CoreSetup +): StreamsRepositoryClient { + return createRepositoryClient(core); +} diff --git a/x-pack/plugins/streams/public/index.ts b/x-pack/plugins/streams/public/index.ts index 5b83ea1d297d..bc90fb0f4006 100644 --- a/x-pack/plugins/streams/public/index.ts +++ b/x-pack/plugins/streams/public/index.ts @@ -7,7 +7,12 @@ import { PluginInitializer, PluginInitializerContext } from '@kbn/core/public'; import { Plugin } from './plugin'; +import { StreamsPluginSetup, StreamsPluginStart } from './types'; -export const plugin: PluginInitializer<{}, {}> = (context: PluginInitializerContext) => { +export type { StreamsPluginSetup, StreamsPluginStart }; + +export const plugin: PluginInitializer = ( + context: PluginInitializerContext +) => { return new Plugin(context); }; diff --git a/x-pack/plugins/streams/public/plugin.ts b/x-pack/plugins/streams/public/plugin.ts index f35d18e06ff7..5a2ae3e06684 100644 --- a/x-pack/plugins/streams/public/plugin.ts +++ b/x-pack/plugins/streams/public/plugin.ts @@ -8,25 +8,55 @@ import { CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/public'; import { Logger } from '@kbn/logging'; +import { createRepositoryClient } from '@kbn/server-route-repository-client'; +import { from, shareReplay, startWith } from 'rxjs'; +import { once } from 'lodash'; import type { StreamsPublicConfig } from '../common/config'; import { StreamsPluginClass, StreamsPluginSetup, StreamsPluginStart } from './types'; +import { StreamsRepositoryClient } from './api'; export class Plugin implements StreamsPluginClass { public config: StreamsPublicConfig; public logger: Logger; + private repositoryClient!: StreamsRepositoryClient; + constructor(context: PluginInitializerContext<{}>) { this.config = context.config.get(); this.logger = context.logger.get(); } - setup(core: CoreSetup, pluginSetup: StreamsPluginSetup) { - return {}; + setup(core: CoreSetup<{}>, pluginSetup: {}): StreamsPluginSetup { + this.repositoryClient = createRepositoryClient(core); + return { + status$: createStatusObservable(this.logger, this.repositoryClient), + }; } - start(core: CoreStart) { - return {}; + start(core: CoreStart, pluginsStart: {}): StreamsPluginStart { + return { + streamsRepositoryClient: this.repositoryClient, + status$: createStatusObservable(this.logger, this.repositoryClient), + }; } stop() {} } + +const createStatusObservable = once((logger: Logger, repositoryClient: StreamsRepositoryClient) => { + return from( + repositoryClient + .fetch('GET /api/streams/_status', { + signal: new AbortController().signal, + }) + .then( + (response) => ({ + status: response.enabled ? ('enabled' as const) : ('disabled' as const), + }), + (error) => { + logger.error(error); + return { status: 'unknown' as const }; + } + ) + ).pipe(startWith({ status: 'unknown' as const }), shareReplay(1)); +}); diff --git a/x-pack/plugins/streams/public/types.ts b/x-pack/plugins/streams/public/types.ts index 61e5fa94098f..fc88f2a6c20f 100644 --- a/x-pack/plugins/streams/public/types.ts +++ b/x-pack/plugins/streams/public/types.ts @@ -6,11 +6,16 @@ */ import type { Plugin as PluginClass } from '@kbn/core/public'; +import { Observable } from 'rxjs'; +import type { StreamsRepositoryClient } from './api'; -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface StreamsPluginSetup {} +export interface StreamsPluginSetup { + status$: Observable<{ status: 'unknown' | 'enabled' | 'disabled' }>; +} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface StreamsPluginStart {} +export interface StreamsPluginStart { + streamsRepositoryClient: StreamsRepositoryClient; + status$: Observable<{ status: 'unknown' | 'enabled' | 'disabled' }>; +} -export type StreamsPluginClass = PluginClass<{}, {}, StreamsPluginSetup, StreamsPluginStart>; +export type StreamsPluginClass = PluginClass; diff --git a/x-pack/plugins/streams/server/index.ts b/x-pack/plugins/streams/server/index.ts index bd8aee304ad1..9ef13c62d6b7 100644 --- a/x-pack/plugins/streams/server/index.ts +++ b/x-pack/plugins/streams/server/index.ts @@ -17,3 +17,5 @@ export const plugin = async (context: PluginInitializerContext) = const { StreamsPlugin } = await import('./plugin'); return new StreamsPlugin(context); }; + +export type { ListStreamResponse } from './lib/streams/stream_crud'; diff --git a/x-pack/plugins/streams/server/lib/streams/component_templates/generate_layer.ts b/x-pack/plugins/streams/server/lib/streams/component_templates/generate_layer.ts index 82c89c9ab917..69da4c5d8287 100644 --- a/x-pack/plugins/streams/server/lib/streams/component_templates/generate_layer.ts +++ b/x-pack/plugins/streams/server/lib/streams/component_templates/generate_layer.ts @@ -7,6 +7,7 @@ import { ClusterPutComponentTemplateRequest, + MappingDateProperty, MappingProperty, } from '@elastic/elasticsearch/lib/api/types'; import { StreamDefinition } from '../../../../common/types'; @@ -21,16 +22,22 @@ export function generateLayer( ): ClusterPutComponentTemplateRequest { const properties: Record = {}; definition.fields.forEach((field) => { - properties[field.name] = { + const property: MappingProperty = { type: field.type, }; + if (field.name === '@timestamp') { + // @timestamp can't ignore malformed dates as it's used for sorting in logsdb + (property as MappingDateProperty).ignore_malformed = false; + } + properties[field.name] = property; }); return { name: getComponentTemplateName(id), template: { settings: isRoot(definition.id) ? logsSettings : {}, mappings: { - subobjects: false, + subobjects: true, // TODO set to false once this works on Elasticsearch side - right now fields are not properly indexed. + dynamic: false, properties, }, }, diff --git a/x-pack/plugins/streams/server/lib/streams/data_streams/manage_data_streams.ts b/x-pack/plugins/streams/server/lib/streams/data_streams/manage_data_streams.ts index 812739db56c7..a9b667906fdf 100644 --- a/x-pack/plugins/streams/server/lib/streams/data_streams/manage_data_streams.ts +++ b/x-pack/plugins/streams/server/lib/streams/data_streams/manage_data_streams.ts @@ -6,6 +6,7 @@ */ import { ElasticsearchClient, Logger } from '@kbn/core/server'; +import { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types'; import { retryTransientEsErrors } from '../helpers/retry'; interface DataStreamManagementOptions { @@ -23,6 +24,7 @@ interface DeleteDataStreamOptions { interface RolloverDataStreamOptions { esClient: ElasticsearchClient; name: string; + mappings: MappingTypeMapping['properties'] | undefined; logger: Logger; } @@ -56,38 +58,37 @@ export async function rolloverDataStreamIfNecessary({ esClient, name, logger, + mappings, }: RolloverDataStreamOptions) { const dataStreams = await esClient.indices.getDataStream({ name: `${name},${name}.*` }); for (const dataStream of dataStreams.data_streams) { - const currentMappings = - Object.values( - await esClient.indices.getMapping({ - index: dataStream.indices.at(-1)?.index_name, - }) - )[0].mappings.properties || {}; - const simulatedIndex = await esClient.indices.simulateIndexTemplate({ name: dataStream.name }); - const simulatedMappings = simulatedIndex.template.mappings.properties || {}; - - // check whether the same fields and same types are listed (don't check for other mapping attributes) - const isDifferent = - Object.values(simulatedMappings).length !== Object.values(currentMappings).length || - Object.entries(simulatedMappings || {}).some(([fieldName, { type }]) => { - const currentType = currentMappings[fieldName]?.type; - return currentType !== type; - }); - - if (!isDifferent) { + const writeIndex = dataStream.indices.at(-1); + if (!writeIndex) { continue; } - try { - await retryTransientEsErrors(() => esClient.indices.rollover({ alias: dataStream.name }), { - logger, - }); - logger.debug(() => `Rolled over data stream: ${dataStream.name}`); + await retryTransientEsErrors( + () => esClient.indices.putMapping({ index: writeIndex.index_name, properties: mappings }), + { + logger, + } + ); } catch (error: any) { - logger.error(`Error rolling over data stream: ${error.message}`); - throw error; + if ( + typeof error.message !== 'string' || + !error.message.includes('illegal_argument_exception') + ) { + throw error; + } + try { + await retryTransientEsErrors(() => esClient.indices.rollover({ alias: dataStream.name }), { + logger, + }); + logger.debug(() => `Rolled over data stream: ${dataStream.name}`); + } catch (rolloverError: any) { + logger.error(`Error rolling over data stream: ${error.message}`); + throw error; + } } } } diff --git a/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.test.ts b/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.test.ts index aab7f27f12d1..db0a5eaea8ef 100644 --- a/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.test.ts +++ b/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.test.ts @@ -7,48 +7,56 @@ import { conditionToPainless } from './condition_to_painless'; -const operatorConditionAndResutls = [ +const operatorConditionAndResults = [ { condition: { field: 'log.logger', operator: 'eq' as const, value: 'nginx_proxy' }, - result: 'ctx.log?.logger == "nginx_proxy"', + result: '(ctx.log?.logger !== null && ctx.log?.logger == "nginx_proxy")', }, { condition: { field: 'log.logger', operator: 'neq' as const, value: 'nginx_proxy' }, - result: 'ctx.log?.logger != "nginx_proxy"', + result: '(ctx.log?.logger !== null && ctx.log?.logger != "nginx_proxy")', }, { condition: { field: 'http.response.status_code', operator: 'lt' as const, value: 500 }, - result: 'ctx.http?.response?.status_code < 500', + result: '(ctx.http?.response?.status_code !== null && ctx.http?.response?.status_code < 500)', }, { condition: { field: 'http.response.status_code', operator: 'lte' as const, value: 500 }, - result: 'ctx.http?.response?.status_code <= 500', + result: '(ctx.http?.response?.status_code !== null && ctx.http?.response?.status_code <= 500)', }, { condition: { field: 'http.response.status_code', operator: 'gt' as const, value: 500 }, - result: 'ctx.http?.response?.status_code > 500', + result: '(ctx.http?.response?.status_code !== null && ctx.http?.response?.status_code > 500)', }, { condition: { field: 'http.response.status_code', operator: 'gte' as const, value: 500 }, - result: 'ctx.http?.response?.status_code >= 500', + result: '(ctx.http?.response?.status_code !== null && ctx.http?.response?.status_code >= 500)', }, { condition: { field: 'log.logger', operator: 'startsWith' as const, value: 'nginx' }, - result: 'ctx.log?.logger.startsWith("nginx")', + result: '(ctx.log?.logger !== null && ctx.log?.logger.startsWith("nginx"))', }, { condition: { field: 'log.logger', operator: 'endsWith' as const, value: 'proxy' }, - result: 'ctx.log?.logger.endsWith("proxy")', + result: '(ctx.log?.logger !== null && ctx.log?.logger.endsWith("proxy"))', }, { condition: { field: 'log.logger', operator: 'contains' as const, value: 'proxy' }, - result: 'ctx.log?.logger.contains("proxy")', + result: '(ctx.log?.logger !== null && ctx.log?.logger.contains("proxy"))', + }, + { + condition: { field: 'log.logger', operator: 'exists' as const }, + result: 'ctx.log?.logger !== null', + }, + { + condition: { field: 'log.logger', operator: 'notExists' as const }, + result: 'ctx.log?.logger == null', }, ]; describe('conditionToPainless', () => { describe('operators', () => { - operatorConditionAndResutls.forEach((setup) => { + operatorConditionAndResults.forEach((setup) => { test(`${setup.condition.operator}`, () => { expect(conditionToPainless(setup.condition)).toEqual(setup.result); }); @@ -65,7 +73,7 @@ describe('conditionToPainless', () => { }; expect( expect(conditionToPainless(condition)).toEqual( - 'ctx.log?.logger == "nginx_proxy" && ctx.log?.level == "error"' + '(ctx.log?.logger !== null && ctx.log?.logger == "nginx_proxy") && (ctx.log?.level !== null && ctx.log?.level == "error")' ) ); }); @@ -81,7 +89,7 @@ describe('conditionToPainless', () => { }; expect( expect(conditionToPainless(condition)).toEqual( - 'ctx.log?.logger == "nginx_proxy" || ctx.log?.level == "error"' + '(ctx.log?.logger !== null && ctx.log?.logger == "nginx_proxy") || (ctx.log?.level !== null && ctx.log?.level == "error")' ) ); }); @@ -102,7 +110,7 @@ describe('conditionToPainless', () => { }; expect( expect(conditionToPainless(condition)).toEqual( - 'ctx.log?.logger == "nginx_proxy" && (ctx.log?.level == "error" || ctx.log?.level == "ERROR")' + '(ctx.log?.logger !== null && ctx.log?.logger == "nginx_proxy") && ((ctx.log?.level !== null && ctx.log?.level == "error") || (ctx.log?.level !== null && ctx.log?.level == "ERROR"))' ) ); }); @@ -125,7 +133,7 @@ describe('conditionToPainless', () => { }; expect( expect(conditionToPainless(condition)).toEqual( - '(ctx.log?.logger == "nginx_proxy" || ctx.service?.name == "nginx") && (ctx.log?.level == "error" || ctx.log?.level == "ERROR")' + '((ctx.log?.logger !== null && ctx.log?.logger == "nginx_proxy") || (ctx.service?.name !== null && ctx.service?.name == "nginx")) && ((ctx.log?.level !== null && ctx.log?.level == "error") || (ctx.log?.level !== null && ctx.log?.level == "ERROR"))' ) ); }); diff --git a/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.ts b/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.ts index 539ad3603535..dccc15b2ec8f 100644 --- a/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.ts +++ b/x-pack/plugins/streams/server/lib/streams/helpers/condition_to_painless.ts @@ -8,11 +8,13 @@ import { isBoolean, isString } from 'lodash'; import { AndCondition, + BinaryFilterCondition, Condition, conditionSchema, FilterCondition, filterConditionSchema, RerouteOrCondition, + UnaryFilterCondition, } from '../../../../common/types'; function isFilterCondition(subject: any): subject is FilterCondition { @@ -44,7 +46,7 @@ function encodeValue(value: string | number | boolean) { return value; } -function toPainless(condition: FilterCondition) { +function binaryToPainless(condition: BinaryFilterCondition) { switch (condition.operator) { case 'neq': return `${safePainlessField(condition)} != ${encodeValue(condition.value)}`; @@ -67,9 +69,25 @@ function toPainless(condition: FilterCondition) { } } +function unaryToPainless(condition: UnaryFilterCondition) { + switch (condition.operator) { + case 'notExists': + return `${safePainlessField(condition)} == null`; + default: + return `${safePainlessField(condition)} !== null`; + } +} + +function isUnaryFilterCondition(subject: FilterCondition): subject is UnaryFilterCondition { + return !('value' in subject); +} + export function conditionToPainless(condition: Condition, nested = false): string { if (isFilterCondition(condition)) { - return toPainless(condition); + if (isUnaryFilterCondition(condition)) { + return unaryToPainless(condition); + } + return `(${safePainlessField(condition)} !== null && ${binaryToPainless(condition)})`; } if (isAndCondition(condition)) { const and = condition.and.map((filter) => conditionToPainless(filter, true)).join(' && '); diff --git a/x-pack/plugins/streams/server/lib/streams/index_templates/generate_index_template.ts b/x-pack/plugins/streams/server/lib/streams/index_templates/generate_index_template.ts index 7a16534a618d..0134951c8079 100644 --- a/x-pack/plugins/streams/server/lib/streams/index_templates/generate_index_template.ts +++ b/x-pack/plugins/streams/server/lib/streams/index_templates/generate_index_template.ts @@ -27,6 +27,7 @@ export function generateIndexTemplate(id: string) { }, data_stream: { hidden: false, + failure_store: true, }, template: { settings: { diff --git a/x-pack/plugins/streams/server/lib/streams/internal_stream_mapping.ts b/x-pack/plugins/streams/server/lib/streams/internal_stream_mapping.ts index 8e88eeef8cd8..faff949c0d97 100644 --- a/x-pack/plugins/streams/server/lib/streams/internal_stream_mapping.ts +++ b/x-pack/plugins/streams/server/lib/streams/internal_stream_mapping.ts @@ -29,6 +29,9 @@ export function createStreamsIndex(scopedClusterClient: IScopedClusterClient) { id: { type: 'keyword', }, + managed: { + type: 'boolean', + }, }, }, }); diff --git a/x-pack/plugins/streams/server/lib/streams/root_stream_definition.ts b/x-pack/plugins/streams/server/lib/streams/root_stream_definition.ts index 2b7deed87730..1bdb4f20a95c 100644 --- a/x-pack/plugins/streams/server/lib/streams/root_stream_definition.ts +++ b/x-pack/plugins/streams/server/lib/streams/root_stream_definition.ts @@ -9,6 +9,7 @@ import { StreamDefinition } from '../../../common/types'; export const rootStreamDefinition: StreamDefinition = { id: 'logs', + managed: true, processing: [], children: [], fields: [ diff --git a/x-pack/plugins/streams/server/lib/streams/stream_crud.ts b/x-pack/plugins/streams/server/lib/streams/stream_crud.ts index 78a126905d9a..245e06e8b457 100644 --- a/x-pack/plugins/streams/server/lib/streams/stream_crud.ts +++ b/x-pack/plugins/streams/server/lib/streams/stream_crud.ts @@ -7,29 +7,29 @@ import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; -import { FieldDefinition, StreamDefinition } from '../../../common/types'; import { STREAMS_INDEX } from '../../../common/constants'; -import { DefinitionNotFound } from './errors'; -import { deleteTemplate, upsertTemplate } from './index_templates/manage_index_templates'; +import { FieldDefinition, StreamDefinition } from '../../../common/types'; import { generateLayer } from './component_templates/generate_layer'; -import { generateIngestPipeline } from './ingest_pipelines/generate_ingest_pipeline'; -import { generateReroutePipeline } from './ingest_pipelines/generate_reroute_pipeline'; -import { generateIndexTemplate } from './index_templates/generate_index_template'; import { deleteComponent, upsertComponent } from './component_templates/manage_component_templates'; -import { getIndexTemplateName } from './index_templates/name'; import { getComponentTemplateName } from './component_templates/name'; -import { getProcessingPipelineName, getReroutePipelineName } from './ingest_pipelines/name'; -import { - deleteIngestPipeline, - upsertIngestPipeline, -} from './ingest_pipelines/manage_ingest_pipelines'; -import { getAncestors } from './helpers/hierarchy'; -import { MalformedFields } from './errors/malformed_fields'; import { deleteDataStream, rolloverDataStreamIfNecessary, upsertDataStream, } from './data_streams/manage_data_streams'; +import { DefinitionNotFound } from './errors'; +import { MalformedFields } from './errors/malformed_fields'; +import { getAncestors } from './helpers/hierarchy'; +import { generateIndexTemplate } from './index_templates/generate_index_template'; +import { deleteTemplate, upsertTemplate } from './index_templates/manage_index_templates'; +import { getIndexTemplateName } from './index_templates/name'; +import { generateIngestPipeline } from './ingest_pipelines/generate_ingest_pipeline'; +import { generateReroutePipeline } from './ingest_pipelines/generate_reroute_pipeline'; +import { + deleteIngestPipeline, + upsertIngestPipeline, +} from './ingest_pipelines/manage_ingest_pipelines'; +import { getProcessingPipelineName, getReroutePipelineName } from './ingest_pipelines/name'; interface BaseParams { scopedClusterClient: IScopedClusterClient; @@ -81,57 +81,172 @@ async function upsertInternalStream({ definition, scopedClusterClient }: BasePar return scopedClusterClient.asInternalUser.index({ id: definition.id, index: STREAMS_INDEX, - document: definition, + document: { ...definition, managed: true }, refresh: 'wait_for', }); } type ListStreamsParams = BaseParams; -export async function listStreams({ scopedClusterClient }: ListStreamsParams) { +export interface ListStreamResponse { + total: number; + definitions: StreamDefinition[]; +} + +export async function listStreams({ + scopedClusterClient, +}: ListStreamsParams): Promise { const response = await scopedClusterClient.asInternalUser.search({ index: STREAMS_INDEX, size: 10000, - fields: ['id'], - _source: false, sort: [{ id: 'asc' }], }); - const definitions = response.hits.hits.map((hit) => hit.fields as { id: string[] }); - return definitions; + + const dataStreams = await listDataStreamsAsStreams({ scopedClusterClient }); + const definitions = response.hits.hits.map((hit) => ({ ...hit._source!, managed: true })); + const total = response.hits.total!; + + return { + definitions: [...definitions, ...dataStreams], + total: (typeof total === 'number' ? total : total.value) + dataStreams.length, + }; +} + +export async function listDataStreamsAsStreams({ + scopedClusterClient, +}: ListStreamsParams): Promise { + const response = await scopedClusterClient.asInternalUser.indices.getDataStream(); + return response.data_streams + .filter((dataStream) => dataStream.template.endsWith('@stream') === false) + .map((dataStream) => ({ + id: dataStream.name, + managed: false, + children: [], + fields: [], + processing: [], + })); } interface ReadStreamParams extends BaseParams { id: string; + skipAccessCheck?: boolean; +} + +export interface ReadStreamResponse { + definition: StreamDefinition; } -export async function readStream({ id, scopedClusterClient }: ReadStreamParams) { +export async function readStream({ + id, + scopedClusterClient, + skipAccessCheck, +}: ReadStreamParams): Promise { try { const response = await scopedClusterClient.asInternalUser.get({ id, index: STREAMS_INDEX, }); const definition = response._source as StreamDefinition; + if (!skipAccessCheck) { + const hasAccess = await checkReadAccess({ id, scopedClusterClient }); + if (!hasAccess) { + throw new DefinitionNotFound(`Stream definition for ${id} not found.`); + } + } return { - definition, + definition: { + ...definition, + managed: true, + }, }; } catch (e) { if (e.meta?.statusCode === 404) { - throw new DefinitionNotFound(`Stream definition for ${id} not found.`); + return readDataStreamAsStream({ id, scopedClusterClient, skipAccessCheck }); } throw e; } } +export async function readDataStreamAsStream({ + id, + scopedClusterClient, + skipAccessCheck, +}: ReadStreamParams) { + const response = await scopedClusterClient.asInternalUser.indices.getDataStream({ name: id }); + if (response.data_streams.length === 1) { + const definition: StreamDefinition = { + id, + managed: false, + children: [], + fields: [], + processing: [], + }; + if (!skipAccessCheck) { + const hasAccess = await checkReadAccess({ id, scopedClusterClient }); + if (!hasAccess) { + throw new DefinitionNotFound(`Stream definition for ${id} not found.`); + } + } + // retrieve linked index template, component template and ingest pipeline + const templateName = response.data_streams[0].template; + const componentTemplates: string[] = []; + const template = await scopedClusterClient.asInternalUser.indices.getIndexTemplate({ + name: templateName, + }); + if (template.index_templates.length) { + template.index_templates[0].index_template.composed_of.forEach((componentTemplateName) => { + componentTemplates.push(componentTemplateName); + }); + } + const writeIndexName = response.data_streams[0].indices.at(-1)?.index_name!; + const currentIndex = await scopedClusterClient.asInternalUser.indices.get({ + index: writeIndexName, + }); + const ingestPipelineId = currentIndex[writeIndexName].settings?.index?.default_pipeline!; + + definition.unmanaged_elasticsearch_assets = [ + { + type: 'ingest_pipeline', + id: ingestPipelineId, + }, + ...componentTemplates.map((componentTemplateName) => ({ + type: 'component_template' as const, + id: componentTemplateName, + })), + { + type: 'index_template', + id: templateName, + }, + { + type: 'data_stream', + id, + }, + ]; + + return { definition }; + } + throw new DefinitionNotFound(`Stream definition for ${id} not found.`); +} + interface ReadAncestorsParams extends BaseParams { id: string; } -export async function readAncestors({ id, scopedClusterClient }: ReadAncestorsParams) { +export interface ReadAncestorsResponse { + ancestors: Array<{ definition: StreamDefinition }>; +} + +export async function readAncestors({ + id, + scopedClusterClient, +}: ReadAncestorsParams): Promise { const ancestorIds = getAncestors(id); - return await Promise.all( - ancestorIds.map((ancestorId) => readStream({ scopedClusterClient, id: ancestorId })) - ); + return { + ancestors: await Promise.all( + ancestorIds.map((ancestorId) => readStream({ scopedClusterClient, id: ancestorId })) + ), + }; } interface ReadDescendantsParams extends BaseParams { @@ -167,7 +282,7 @@ export async function validateAncestorFields( id: string, fields: FieldDefinition[] ) { - const ancestors = await readAncestors({ + const { ancestors } = await readAncestors({ id, scopedClusterClient, }); @@ -223,6 +338,21 @@ export async function checkStreamExists({ id, scopedClusterClient }: ReadStreamP } } +interface CheckReadAccessParams extends BaseParams { + id: string; +} + +export async function checkReadAccess({ + id, + scopedClusterClient, +}: CheckReadAccessParams): Promise { + try { + return await scopedClusterClient.asCurrentUser.indices.exists({ index: id }); + } catch (e) { + return false; + } +} + interface SyncStreamParams { scopedClusterClient: IScopedClusterClient; definition: StreamDefinition; @@ -236,10 +366,15 @@ export async function syncStream({ rootDefinition, logger, }: SyncStreamParams) { + if (!definition.managed) { + // TODO For now, we just don't allow reads at all - later on we will relax this to allow certain operations, but they will use a completely different syncing logic + throw new Error('Cannot sync an unmanaged stream'); + } + const componentTemplate = generateLayer(definition.id, definition); await upsertComponent({ esClient: scopedClusterClient.asCurrentUser, logger, - component: generateLayer(definition.id, definition), + component: componentTemplate, }); await upsertIngestPipeline({ esClient: scopedClusterClient.asCurrentUser, @@ -282,5 +417,12 @@ export async function syncStream({ esClient: scopedClusterClient.asCurrentUser, name: definition.id, logger, + mappings: componentTemplate.template.mappings?.properties, + }); +} + +export async function streamsEnabled({ scopedClusterClient }: BaseParams) { + return await scopedClusterClient.asInternalUser.indices.exists({ + index: STREAMS_INDEX, }); } diff --git a/x-pack/plugins/streams/server/plugin.ts b/x-pack/plugins/streams/server/plugin.ts index ef070984803d..937f8c22b5be 100644 --- a/x-pack/plugins/streams/server/plugin.ts +++ b/x-pack/plugins/streams/server/plugin.ts @@ -16,8 +16,7 @@ import { } from '@kbn/core/server'; import { registerRoutes } from '@kbn/server-route-repository'; import { StreamsConfig, configSchema, exposeToBrowserConfig } from '../common/config'; -import { StreamsRouteRepository } from './routes'; -import { RouteDependencies } from './routes/types'; +import { streamsRouteRepository } from './routes'; import { StreamsPluginSetupDependencies, StreamsPluginStartDependencies, @@ -58,8 +57,8 @@ export class StreamsPlugin logger: this.logger, } as StreamsServer; - registerRoutes({ - repository: StreamsRouteRepository, + registerRoutes({ + repository: streamsRouteRepository, dependencies: { server: this.server, getScopedClients: async ({ request }: { request: KibanaRequest }) => { diff --git a/x-pack/plugins/streams/server/routes/esql/route.ts b/x-pack/plugins/streams/server/routes/esql/route.ts new file mode 100644 index 000000000000..0e0e41eee3c7 --- /dev/null +++ b/x-pack/plugins/streams/server/routes/esql/route.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 { excludeFrozenQuery } from '@kbn/observability-utils-common/es/queries/exclude_frozen_query'; +import { kqlQuery } from '@kbn/observability-utils-common/es/queries/kql_query'; +import { rangeQuery } from '@kbn/observability-utils-common/es/queries/range_query'; +import { + UnparsedEsqlResponse, + createObservabilityEsClient, +} from '@kbn/observability-utils-server/es/client/create_observability_es_client'; +import { z } from '@kbn/zod'; +import { isNumber } from 'lodash'; +import { createServerRoute } from '../create_server_route'; + +export const executeEsqlRoute = createServerRoute({ + endpoint: 'POST /internal/streams/esql', + params: z.object({ + body: z.object({ + query: z.string(), + operationName: z.string(), + filter: z.object({}).passthrough().optional(), + kuery: z.string().optional(), + start: z.number().optional(), + end: z.number().optional(), + }), + }), + handler: async ({ params, request, logger, getScopedClients }): Promise => { + const { scopedClusterClient } = await getScopedClients({ request }); + const observabilityEsClient = createObservabilityEsClient({ + client: scopedClusterClient.asCurrentUser, + logger, + plugin: 'streams', + }); + + const { + body: { operationName, query, filter, kuery, start, end }, + } = params; + + const response = await observabilityEsClient.esql( + operationName, + { + query, + filter: { + bool: { + filter: [ + filter || { match_all: {} }, + ...kqlQuery(kuery), + ...excludeFrozenQuery(), + ...(isNumber(start) && isNumber(end) ? rangeQuery(start, end) : []), + ], + }, + }, + }, + { transform: 'none' } + ); + + return response; + }, +}); + +export const esqlRoutes = { + ...executeEsqlRoute, +}; diff --git a/x-pack/plugins/streams/server/routes/index.ts b/x-pack/plugins/streams/server/routes/index.ts index 6fc734d3371b..7267dbedeacf 100644 --- a/x-pack/plugins/streams/server/routes/index.ts +++ b/x-pack/plugins/streams/server/routes/index.ts @@ -5,15 +5,18 @@ * 2.0. */ +import { esqlRoutes } from './esql/route'; import { deleteStreamRoute } from './streams/delete'; +import { disableStreamsRoute } from './streams/disable'; import { editStreamRoute } from './streams/edit'; import { enableStreamsRoute } from './streams/enable'; import { forkStreamsRoute } from './streams/fork'; import { listStreamsRoute } from './streams/list'; import { readStreamRoute } from './streams/read'; import { resyncStreamsRoute } from './streams/resync'; +import { streamsStatusRoutes } from './streams/settings'; -export const StreamsRouteRepository = { +export const streamsRouteRepository = { ...enableStreamsRoute, ...resyncStreamsRoute, ...forkStreamsRoute, @@ -21,6 +24,9 @@ export const StreamsRouteRepository = { ...editStreamRoute, ...deleteStreamRoute, ...listStreamsRoute, + ...streamsStatusRoutes, + ...esqlRoutes, + ...disableStreamsRoute, }; -export type StreamsRouteRepository = typeof StreamsRouteRepository; +export type StreamsRouteRepository = typeof streamsRouteRepository; diff --git a/x-pack/plugins/streams/server/routes/streams/delete.ts b/x-pack/plugins/streams/server/routes/streams/delete.ts index 3820975dbe16..a2092838792c 100644 --- a/x-pack/plugins/streams/server/routes/streams/delete.ts +++ b/x-pack/plugins/streams/server/routes/streams/delete.ts @@ -8,6 +8,7 @@ import { z } from '@kbn/zod'; import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; +import { badRequest, internal, notFound } from '@hapi/boom'; import { DefinitionNotFound, ForkConditionMissing, @@ -20,18 +21,15 @@ import { MalformedStreamId } from '../../lib/streams/errors/malformed_stream_id' import { getParentId } from '../../lib/streams/helpers/hierarchy'; export const deleteStreamRoute = createServerRoute({ - endpoint: 'DELETE /api/streams/{id} 2023-10-31', + endpoint: 'DELETE /api/streams/{id}', options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, params: z.object({ @@ -39,7 +37,13 @@ export const deleteStreamRoute = createServerRoute({ id: z.string(), }), }), - handler: async ({ response, params, logger, request, getScopedClients }) => { + handler: async ({ + response, + params, + logger, + request, + getScopedClients, + }): Promise<{ acknowledged: true }> => { try { const { scopedClusterClient } = await getScopedClients({ request }); @@ -48,14 +52,15 @@ export const deleteStreamRoute = createServerRoute({ throw new MalformedStreamId('Cannot delete root stream'); } + // need to update parent first to cut off documents streaming down await updateParentStream(scopedClusterClient, params.path.id, parentId, logger); await deleteStream(scopedClusterClient, params.path.id, logger); - return response.ok({ body: { acknowledged: true } }); + return { acknowledged: true }; } catch (e) { if (e instanceof IndexTemplateNotFound || e instanceof DefinitionNotFound) { - return response.notFound({ body: e }); + throw notFound(e); } if ( @@ -63,15 +68,19 @@ export const deleteStreamRoute = createServerRoute({ e instanceof ForkConditionMissing || e instanceof MalformedStreamId ) { - return response.customError({ body: e, statusCode: 400 }); + throw badRequest(e); } - return response.customError({ body: e, statusCode: 500 }); + throw internal(e); } }, }); -async function deleteStream(scopedClusterClient: IScopedClusterClient, id: string, logger: Logger) { +export async function deleteStream( + scopedClusterClient: IScopedClusterClient, + id: string, + logger: Logger +) { try { const { definition } = await readStream({ scopedClusterClient, id }); for (const child of definition.children) { diff --git a/x-pack/plugins/streams/server/routes/streams/disable.ts b/x-pack/plugins/streams/server/routes/streams/disable.ts new file mode 100644 index 000000000000..b760b58f1faf --- /dev/null +++ b/x-pack/plugins/streams/server/routes/streams/disable.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { badRequest, internal } from '@hapi/boom'; +import { z } from '@kbn/zod'; +import { SecurityException } from '../../lib/streams/errors'; +import { createServerRoute } from '../create_server_route'; +import { deleteStream } from './delete'; + +export const disableStreamsRoute = createServerRoute({ + endpoint: 'POST /api/streams/_disable', + params: z.object({}), + options: { + access: 'internal', + }, + security: { + authz: { + requiredPrivileges: ['streams_write'], + }, + }, + handler: async ({ + request, + response, + logger, + getScopedClients, + }): Promise<{ acknowledged: true }> => { + try { + const { scopedClusterClient } = await getScopedClients({ request }); + + await deleteStream(scopedClusterClient, 'logs', logger); + + return { acknowledged: true }; + } catch (e) { + if (e instanceof SecurityException) { + throw badRequest(e); + } + throw internal(e); + } + }, +}); diff --git a/x-pack/plugins/streams/server/routes/streams/edit.ts b/x-pack/plugins/streams/server/routes/streams/edit.ts index b82b4d54044d..6125aa2470b9 100644 --- a/x-pack/plugins/streams/server/routes/streams/edit.ts +++ b/x-pack/plugins/streams/server/routes/streams/edit.ts @@ -8,6 +8,7 @@ import { z } from '@kbn/zod'; import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; import { Logger } from '@kbn/logging'; +import { badRequest, internal, notFound } from '@hapi/boom'; import { DefinitionNotFound, ForkConditionMissing, @@ -28,18 +29,15 @@ import { getParentId } from '../../lib/streams/helpers/hierarchy'; import { MalformedChildren } from '../../lib/streams/errors/malformed_children'; export const editStreamRoute = createServerRoute({ - endpoint: 'PUT /api/streams/{id} 2023-10-31', + endpoint: 'PUT /api/streams/{id}', options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, params: z.object({ @@ -59,22 +57,10 @@ export const editStreamRoute = createServerRoute({ const parentId = getParentId(params.path.id); let parentDefinition: StreamDefinition | undefined; - if (parentId) { - parentDefinition = await updateParentStream( - scopedClusterClient, - parentId, - params.path.id, - logger - ); - } const streamDefinition = { ...params.body }; - await syncStream({ - scopedClusterClient, - definition: { ...streamDefinition, id: params.path.id }, - rootDefinition: parentDefinition, - logger, - }); + // always need to go from the leaves to the parent when syncing ingest pipelines, otherwise data + // will be routed before the data stream is ready for (const child of streamDefinition.children) { const streamExists = await checkStreamExists({ @@ -90,6 +76,7 @@ export const editStreamRoute = createServerRoute({ children: [], fields: [], processing: [], + managed: true, }; await syncStream({ @@ -99,10 +86,26 @@ export const editStreamRoute = createServerRoute({ }); } - return response.ok({ body: { acknowledged: true } }); + await syncStream({ + scopedClusterClient, + definition: { ...streamDefinition, id: params.path.id, managed: true }, + rootDefinition: parentDefinition, + logger, + }); + + if (parentId) { + parentDefinition = await updateParentStream( + scopedClusterClient, + parentId, + params.path.id, + logger + ); + } + + return { acknowledged: true }; } catch (e) { if (e instanceof IndexTemplateNotFound || e instanceof DefinitionNotFound) { - return response.notFound({ body: e }); + throw notFound(e); } if ( @@ -110,10 +113,10 @@ export const editStreamRoute = createServerRoute({ e instanceof ForkConditionMissing || e instanceof MalformedStreamId ) { - return response.customError({ body: e, statusCode: 400 }); + throw badRequest(e); } - return response.customError({ body: e, statusCode: 500 }); + throw internal(e); } }, }); diff --git a/x-pack/plugins/streams/server/routes/streams/enable.ts b/x-pack/plugins/streams/server/routes/streams/enable.ts index 27d8929b28e5..cfcb97f9b358 100644 --- a/x-pack/plugins/streams/server/routes/streams/enable.ts +++ b/x-pack/plugins/streams/server/routes/streams/enable.ts @@ -6,43 +6,50 @@ */ import { z } from '@kbn/zod'; +import { badRequest, internal } from '@hapi/boom'; import { SecurityException } from '../../lib/streams/errors'; import { createServerRoute } from '../create_server_route'; -import { syncStream } from '../../lib/streams/stream_crud'; +import { streamsEnabled, syncStream } from '../../lib/streams/stream_crud'; import { rootStreamDefinition } from '../../lib/streams/root_stream_definition'; import { createStreamsIndex } from '../../lib/streams/internal_stream_mapping'; export const enableStreamsRoute = createServerRoute({ - endpoint: 'POST /api/streams/_enable 2023-10-31', + endpoint: 'POST /api/streams/_enable', params: z.object({}), options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, - handler: async ({ request, response, logger, getScopedClients }) => { + handler: async ({ + request, + response, + logger, + getScopedClients, + }): Promise<{ acknowledged: true }> => { try { const { scopedClusterClient } = await getScopedClients({ request }); + const alreadyEnabled = await streamsEnabled({ scopedClusterClient }); + if (alreadyEnabled) { + return { acknowledged: true }; + } await createStreamsIndex(scopedClusterClient); await syncStream({ scopedClusterClient, definition: rootStreamDefinition, logger, }); - return response.ok({ body: { acknowledged: true } }); + return { acknowledged: true }; } catch (e) { if (e instanceof SecurityException) { - return response.customError({ body: e, statusCode: 400 }); + throw badRequest(e); } - return response.customError({ body: e, statusCode: 500 }); + throw internal(e); } }, }); diff --git a/x-pack/plugins/streams/server/routes/streams/fork.ts b/x-pack/plugins/streams/server/routes/streams/fork.ts index 44f405287800..a4d846ceccb3 100644 --- a/x-pack/plugins/streams/server/routes/streams/fork.ts +++ b/x-pack/plugins/streams/server/routes/streams/fork.ts @@ -6,6 +6,7 @@ */ import { z } from '@kbn/zod'; +import { badRequest, internal, notFound } from '@hapi/boom'; import { DefinitionNotFound, ForkConditionMissing, @@ -19,18 +20,15 @@ import { MalformedStreamId } from '../../lib/streams/errors/malformed_stream_id' import { isChildOf } from '../../lib/streams/helpers/hierarchy'; export const forkStreamsRoute = createServerRoute({ - endpoint: 'POST /api/streams/{id}/_fork 2023-10-31', + endpoint: 'POST /api/streams/{id}/_fork', options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, params: z.object({ @@ -39,7 +37,12 @@ export const forkStreamsRoute = createServerRoute({ }), body: z.object({ stream: streamDefinitonWithoutChildrenSchema, condition: conditionSchema }), }), - handler: async ({ response, params, logger, request, getScopedClients }) => { + handler: async ({ + params, + logger, + request, + getScopedClients, + }): Promise<{ acknowledged: true }> => { try { if (!params.body.condition) { throw new ForkConditionMissing('You must provide a condition to fork a stream'); @@ -52,7 +55,7 @@ export const forkStreamsRoute = createServerRoute({ id: params.path.id, }); - const childDefinition = { ...params.body.stream, children: [] }; + const childDefinition = { ...params.body.stream, children: [], managed: true }; // check whether root stream has a child of the given name already if (rootDefinition.children.some((child) => child.id === childDefinition.id)) { @@ -73,29 +76,30 @@ export const forkStreamsRoute = createServerRoute({ params.body.stream.fields ); - rootDefinition.children.push({ - id: params.body.stream.id, - condition: params.body.condition, - }); - + // need to create the child first, otherwise we risk streaming data even though the child data stream is not ready await syncStream({ scopedClusterClient, - definition: rootDefinition, + definition: childDefinition, rootDefinition, logger, }); + rootDefinition.children.push({ + id: params.body.stream.id, + condition: params.body.condition, + }); + await syncStream({ scopedClusterClient, - definition: childDefinition, + definition: rootDefinition, rootDefinition, logger, }); - return response.ok({ body: { acknowledged: true } }); + return { acknowledged: true }; } catch (e) { if (e instanceof IndexTemplateNotFound || e instanceof DefinitionNotFound) { - return response.notFound({ body: e }); + throw notFound(e); } if ( @@ -103,10 +107,10 @@ export const forkStreamsRoute = createServerRoute({ e instanceof ForkConditionMissing || e instanceof MalformedStreamId ) { - return response.customError({ body: e, statusCode: 400 }); + throw badRequest(e); } - return response.customError({ body: e, statusCode: 500 }); + throw internal(e); } }, }); diff --git a/x-pack/plugins/streams/server/routes/streams/list.ts b/x-pack/plugins/streams/server/routes/streams/list.ts index 2e4f13a89bb4..774a256e5ba4 100644 --- a/x-pack/plugins/streams/server/routes/streams/list.ts +++ b/x-pack/plugins/streams/server/routes/streams/list.ts @@ -6,65 +6,73 @@ */ import { z } from '@kbn/zod'; +import { notFound, internal } from '@hapi/boom'; import { createServerRoute } from '../create_server_route'; import { DefinitionNotFound } from '../../lib/streams/errors'; import { listStreams } from '../../lib/streams/stream_crud'; +import { StreamDefinition } from '../../../common'; export const listStreamsRoute = createServerRoute({ - endpoint: 'GET /api/streams 2023-10-31', + endpoint: 'GET /api/streams', options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, params: z.object({}), - handler: async ({ response, request, getScopedClients }) => { + handler: async ({ + response, + request, + getScopedClients, + }): Promise<{ definitions: StreamDefinition[]; trees: StreamTree[] }> => { try { const { scopedClusterClient } = await getScopedClients({ request }); - const definitions = await listStreams({ scopedClusterClient }); + const { definitions } = await listStreams({ scopedClusterClient }); const trees = asTrees(definitions); - return response.ok({ body: { streams: trees } }); + return { definitions, trees }; } catch (e) { if (e instanceof DefinitionNotFound) { - return response.notFound({ body: e }); + throw notFound(e); } - return response.customError({ body: e, statusCode: 500 }); + throw internal(e); } }, }); -interface ListStreamDefinition { +export interface StreamTree { id: string; - children: ListStreamDefinition[]; + children: StreamTree[]; } -function asTrees(definitions: Array<{ id: string[] }>) { - const trees: ListStreamDefinition[] = []; - definitions.forEach((definition) => { - const path = definition.id[0].split('.'); +function asTrees(definitions: Array<{ id: string; managed?: boolean }>) { + const trees: StreamTree[] = []; + const ids = definitions + .filter((definition) => definition.managed) + .map((definition) => definition.id); + + ids.sort((a, b) => a.split('.').length - b.split('.').length); + + ids.forEach((id) => { let currentTree = trees; - path.forEach((_id, index) => { - const partialPath = path.slice(0, index + 1).join('.'); - const existingNode = currentTree.find((node) => node.id === partialPath); - if (existingNode) { - currentTree = existingNode.children; - } else { - const newNode = { id: partialPath, children: [] }; - currentTree.push(newNode); - currentTree = newNode.children; - } - }); + let existingNode: StreamTree | undefined; + // traverse the tree following the prefix of the current id. + // once we reach the leaf, the current id is added as child - this works because the ids are sorted by depth + while ((existingNode = currentTree.find((node) => id.startsWith(node.id)))) { + currentTree = existingNode.children; + } + if (!existingNode) { + const newNode = { id, children: [] }; + currentTree.push(newNode); + } }); + return trees; } diff --git a/x-pack/plugins/streams/server/routes/streams/read.ts b/x-pack/plugins/streams/server/routes/streams/read.ts index 5ea2aaf5f254..5c503e2b7e62 100644 --- a/x-pack/plugins/streams/server/routes/streams/read.ts +++ b/x-pack/plugins/streams/server/routes/streams/read.ts @@ -6,29 +6,38 @@ */ import { z } from '@kbn/zod'; +import { notFound, internal } from '@hapi/boom'; import { createServerRoute } from '../create_server_route'; import { DefinitionNotFound } from '../../lib/streams/errors'; import { readAncestors, readStream } from '../../lib/streams/stream_crud'; +import { StreamDefinition } from '../../../common'; export const readStreamRoute = createServerRoute({ - endpoint: 'GET /api/streams/{id} 2023-10-31', + endpoint: 'GET /api/streams/{id}', options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, params: z.object({ path: z.object({ id: z.string() }), }), - handler: async ({ response, params, request, getScopedClients }) => { + handler: async ({ + response, + params, + request, + logger, + getScopedClients, + }): Promise< + StreamDefinition & { + inheritedFields: Array; + } + > => { try { const { scopedClusterClient } = await getScopedClients({ request }); const streamEntity = await readStream({ @@ -36,7 +45,14 @@ export const readStreamRoute = createServerRoute({ id: params.path.id, }); - const ancestors = await readAncestors({ + if (streamEntity.definition.managed === false) { + return { + ...streamEntity.definition, + inheritedFields: [], + }; + } + + const { ancestors } = await readAncestors({ id: streamEntity.definition.id, scopedClusterClient, }); @@ -48,13 +64,13 @@ export const readStreamRoute = createServerRoute({ ), }; - return response.ok({ body }); + return body; } catch (e) { if (e instanceof DefinitionNotFound) { - return response.notFound({ body: e }); + throw notFound(e); } - return response.customError({ body: e, statusCode: 500 }); + throw internal(e); } }, }); diff --git a/x-pack/plugins/streams/server/routes/streams/resync.ts b/x-pack/plugins/streams/server/routes/streams/resync.ts index 2365252ab00e..8e520410ca5c 100644 --- a/x-pack/plugins/streams/server/routes/streams/resync.ts +++ b/x-pack/plugins/streams/server/routes/streams/resync.ts @@ -10,31 +10,34 @@ import { createServerRoute } from '../create_server_route'; import { syncStream, readStream, listStreams } from '../../lib/streams/stream_crud'; export const resyncStreamsRoute = createServerRoute({ - endpoint: 'POST /api/streams/_resync 2023-10-31', + endpoint: 'POST /api/streams/_resync', options: { - access: 'public', - availability: { - stability: 'experimental', - }, - security: { - authz: { - enabled: false, - reason: - 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', - }, + access: 'internal', + }, + security: { + authz: { + enabled: false, + reason: + 'This API delegates security to the currently logged in user and their Elasticsearch permissions.', }, }, params: z.object({}), - handler: async ({ response, logger, request, getScopedClients }) => { + handler: async ({ + response, + logger, + request, + getScopedClients, + }): Promise<{ acknowledged: true }> => { const { scopedClusterClient } = await getScopedClients({ request }); - const streams = await listStreams({ scopedClusterClient }); + const { definitions: streams } = await listStreams({ scopedClusterClient }); for (const stream of streams) { const { definition } = await readStream({ scopedClusterClient, - id: stream.id[0], + id: stream.id, }); + await syncStream({ scopedClusterClient, definition, @@ -42,6 +45,6 @@ export const resyncStreamsRoute = createServerRoute({ }); } - return response.ok({}); + return { acknowledged: true }; }, }); diff --git a/x-pack/plugins/streams/server/routes/streams/settings.ts b/x-pack/plugins/streams/server/routes/streams/settings.ts new file mode 100644 index 000000000000..7b8dac4cf0a6 --- /dev/null +++ b/x-pack/plugins/streams/server/routes/streams/settings.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { streamsEnabled } from '../../lib/streams/stream_crud'; +import { createServerRoute } from '../create_server_route'; + +export const getStreamsStatusRoute = createServerRoute({ + endpoint: 'GET /api/streams/_status', + options: { + access: 'internal', + }, + security: { + authz: { + requiredPrivileges: ['streams_read'], + }, + }, + handler: async ({ request, getScopedClients }): Promise<{ enabled: boolean }> => { + const { scopedClusterClient } = await getScopedClients({ request }); + + return { + enabled: await streamsEnabled({ scopedClusterClient }), + }; + }, +}); + +export const streamsStatusRoutes = { + ...getStreamsStatusRoute, +}; diff --git a/x-pack/plugins/streams/tsconfig.json b/x-pack/plugins/streams/tsconfig.json index c2fde35f9ca2..3f863145f4d2 100644 --- a/x-pack/plugins/streams/tsconfig.json +++ b/x-pack/plugins/streams/tsconfig.json @@ -27,5 +27,8 @@ "@kbn/zod", "@kbn/encrypted-saved-objects-plugin", "@kbn/licensing-plugin", + "@kbn/server-route-repository-client", + "@kbn/observability-utils-server", + "@kbn/observability-utils-common" ] } diff --git a/x-pack/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx b/x-pack/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx new file mode 100644 index 000000000000..1660042b2cb6 --- /dev/null +++ b/x-pack/plugins/streams_app/.storybook/get_mock_streams_app_context.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { coreMock } from '@kbn/core/public/mocks'; +import type { DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public'; +import type { StreamsPluginStart } from '@kbn/streams-plugin/public'; +import type { ObservabilitySharedPluginStart } from '@kbn/observability-shared-plugin/public'; +import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import type { SharePublicStart } from '@kbn/share-plugin/public/plugin'; +import type { StreamsAppKibanaContext } from '../public/hooks/use_kibana'; + +export function getMockStreamsAppContext(): StreamsAppKibanaContext { + const core = coreMock.createStart(); + + return { + core, + dependencies: { + start: { + observabilityShared: {} as unknown as ObservabilitySharedPluginStart, + dataViews: {} as unknown as DataViewsPublicPluginStart, + data: {} as unknown as DataPublicPluginStart, + unifiedSearch: {} as unknown as UnifiedSearchPublicPluginStart, + streams: {} as unknown as StreamsPluginStart, + share: {} as unknown as SharePublicStart, + }, + }, + services: { + query: jest.fn(), + }, + }; +} diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts b/x-pack/plugins/streams_app/.storybook/jest_setup.js similarity index 62% rename from x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts rename to x-pack/plugins/streams_app/.storybook/jest_setup.js index 90d007d1d941..32071b8aa3f6 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/version_mismatch/index.ts +++ b/x-pack/plugins/streams_app/.storybook/jest_setup.js @@ -5,5 +5,7 @@ * 2.0. */ -export { VersionMismatchPage } from './version_mismatch_page'; -export { VersionMismatchError } from './version_mismatch_error'; +import { setGlobalConfig } from '@storybook/testing-react'; +import * as globalStorybookConfig from './preview'; + +setGlobalConfig(globalStorybookConfig); diff --git a/x-pack/plugins/streams_app/.storybook/main.js b/x-pack/plugins/streams_app/.storybook/main.js new file mode 100644 index 000000000000..86b48c32f103 --- /dev/null +++ b/x-pack/plugins/streams_app/.storybook/main.js @@ -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. + */ + +module.exports = require('@kbn/storybook').defaultConfig; diff --git a/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/constants.ts b/x-pack/plugins/streams_app/.storybook/preview.js similarity index 57% rename from x-pack/plugins/security_solution/public/siem_migrations/rules/utils/constants.ts rename to x-pack/plugins/streams_app/.storybook/preview.js index 7400d4b0bcb6..c8155e9c3d92 100644 --- a/x-pack/plugins/security_solution/public/siem_migrations/rules/utils/constants.ts +++ b/x-pack/plugins/streams_app/.storybook/preview.js @@ -5,7 +5,9 @@ * 2.0. */ -import type { Severity } from '@kbn/securitysolution-io-ts-alerting-types'; +import { EuiThemeProviderDecorator } from '@kbn/kibana-react-plugin/common'; +import * as jest from 'jest-mock'; -export const DEFAULT_TRANSLATION_RISK_SCORE = 21; -export const DEFAULT_TRANSLATION_SEVERITY: Severity = 'low'; +window.jest = jest; + +export const decorators = [EuiThemeProviderDecorator]; diff --git a/x-pack/plugins/streams_app/.storybook/storybook_decorator.tsx b/x-pack/plugins/streams_app/.storybook/storybook_decorator.tsx new file mode 100644 index 000000000000..617b5aee8128 --- /dev/null +++ b/x-pack/plugins/streams_app/.storybook/storybook_decorator.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { ComponentType, useMemo } from 'react'; +import { StreamsAppContextProvider } from '../public/components/streams_app_context_provider'; +import { getMockStreamsAppContext } from './get_mock_streams_app_context'; + +export function KibanaReactStorybookDecorator(Story: ComponentType) { + const context = useMemo(() => getMockStreamsAppContext(), []); + return ( + + + + ); +} diff --git a/x-pack/plugins/streams_app/README.md b/x-pack/plugins/streams_app/README.md new file mode 100644 index 000000000000..6e03524f9274 --- /dev/null +++ b/x-pack/plugins/streams_app/README.md @@ -0,0 +1,3 @@ +# Streams app + +Home of the Streams app plugin, which allows users to manage Streams via the UI. diff --git a/x-pack/plugins/streams_app/common/entity_source_query.ts b/x-pack/plugins/streams_app/common/entity_source_query.ts new file mode 100644 index 000000000000..c076d1f6bd87 --- /dev/null +++ b/x-pack/plugins/streams_app/common/entity_source_query.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export function entitySourceQuery({ entity }: { entity: Record }) { + return { + bool: { + filter: Object.entries(entity).map(([key, value]) => ({ term: { [key]: value } })), + }, + }; +} diff --git a/x-pack/plugins/streams_app/common/index.ts b/x-pack/plugins/streams_app/common/index.ts new file mode 100644 index 000000000000..c41a05b84d30 --- /dev/null +++ b/x-pack/plugins/streams_app/common/index.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { StreamDefinition } from '@kbn/streams-plugin/common'; + +interface EntityBase { + type: string; + displayName: string; + properties: Record; +} + +export type StreamEntity = EntityBase & { type: 'stream'; properties: StreamDefinition }; + +export type Entity = StreamEntity; + +export interface EntityTypeDefinition { + displayName: string; +} diff --git a/x-pack/plugins/streams_app/jest.config.js b/x-pack/plugins/streams_app/jest.config.js new file mode 100644 index 000000000000..d9c01c40a322 --- /dev/null +++ b/x-pack/plugins/streams_app/jest.config.js @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../../..', + roots: [ + '/x-pack/plugins/streams_app/public', + '/x-pack/plugins/streams_app/common', + '/x-pack/plugins/streams_app/server', + ], + setupFiles: ['/x-pack/plugins/streams_app/.storybook/jest_setup.js'], + collectCoverage: true, + collectCoverageFrom: [ + '/x-pack/plugins/streams_app/{public,common,server}/**/*.{js,ts,tsx}', + ], + + coverageReporters: ['html'], +}; diff --git a/x-pack/plugins/streams_app/kibana.jsonc b/x-pack/plugins/streams_app/kibana.jsonc new file mode 100644 index 000000000000..16666084c53e --- /dev/null +++ b/x-pack/plugins/streams_app/kibana.jsonc @@ -0,0 +1,26 @@ +{ + "type": "plugin", + "id": "@kbn/streams-app-plugin", + "owner": "@simianhacker @flash1293 @dgieselaar", + "group": "observability", + "visibility": "private", + "plugin": { + "id": "streamsApp", + "server": true, + "browser": true, + "configPath": ["xpack", "streamsApp"], + "requiredPlugins": [ + "streams", + "observabilityShared", + "data", + "dataViews", + "unifiedSearch", + "share" + ], + "requiredBundles": [ + "kibanaReact" + ], + "optionalPlugins": [], + "extraPublicDirs": [] + } +} diff --git a/x-pack/plugins/streams_app/public/application.tsx b/x-pack/plugins/streams_app/public/application.tsx new file mode 100644 index 000000000000..720f785ecde4 --- /dev/null +++ b/x-pack/plugins/streams_app/public/application.tsx @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { APP_WRAPPER_CLASS, type AppMountParameters, type CoreStart } from '@kbn/core/public'; +import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render'; +import { css } from '@emotion/css'; +import type { StreamsAppStartDependencies } from './types'; +import { StreamsAppServices } from './services/types'; +import { AppRoot } from './components/app_root'; + +export const renderApp = ({ + coreStart, + pluginsStart, + services, + appMountParameters, +}: { + coreStart: CoreStart; + pluginsStart: StreamsAppStartDependencies; + services: StreamsAppServices; +} & { appMountParameters: AppMountParameters }) => { + const { element } = appMountParameters; + + const appWrapperClassName = css` + overflow: auto; + `; + const appWrapperElement = document.getElementsByClassName(APP_WRAPPER_CLASS)[1]; + appWrapperElement.classList.add(appWrapperClassName); + + ReactDOM.render( + + + , + element + ); + return () => { + ReactDOM.unmountComponentAtNode(element); + appWrapperElement.classList.remove(APP_WRAPPER_CLASS); + }; +}; diff --git a/x-pack/plugins/streams_app/public/components/app_root/index.tsx b/x-pack/plugins/streams_app/public/components/app_root/index.tsx new file mode 100644 index 000000000000..c5e8b78ae215 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/app_root/index.tsx @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; +import React from 'react'; +import { type AppMountParameters, type CoreStart } from '@kbn/core/public'; +import { + BreadcrumbsContextProvider, + RouteRenderer, + RouterProvider, +} from '@kbn/typed-react-router-config'; +import { HeaderMenuPortal } from '@kbn/observability-shared-plugin/public'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { StreamsAppContextProvider } from '../streams_app_context_provider'; +import { streamsAppRouter } from '../../routes/config'; +import { StreamsAppStartDependencies } from '../../types'; +import { StreamsAppServices } from '../../services/types'; + +export function AppRoot({ + coreStart, + pluginsStart, + services, + appMountParameters, +}: { + coreStart: CoreStart; + pluginsStart: StreamsAppStartDependencies; + services: StreamsAppServices; +} & { appMountParameters: AppMountParameters }) { + const { history } = appMountParameters; + + const context = { + core: coreStart, + dependencies: { + start: pluginsStart, + }, + services, + }; + + return ( + + + + + + + + + + + ); +} + +export function StreamsAppHeaderActionMenu({ + appMountParameters, +}: { + appMountParameters: AppMountParameters; +}) { + const { setHeaderActionMenu, theme$ } = appMountParameters; + + return ( + + + + <> + + + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/entity_detail_view/index.tsx b/x-pack/plugins/streams_app/public/components/entity_detail_view/index.tsx new file mode 100644 index 000000000000..8e423908af27 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/entity_detail_view/index.tsx @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiLink, EuiPanel, EuiBadge } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import { useStreamsAppBreadcrumbs } from '../../hooks/use_streams_app_breadcrumbs'; +import { useStreamsAppRouter } from '../../hooks/use_streams_app_router'; +import { EntityOverviewTabList } from '../entity_overview_tab_list'; +import { LoadingPanel } from '../loading_panel'; +import { StreamsAppPageBody } from '../streams_app_page_body'; +import { StreamsAppPageHeader } from '../streams_app_page_header'; +import { StreamsAppPageHeaderTitle } from '../streams_app_page_header/streams_app_page_header_title'; + +export interface EntityViewTab { + name: string; + label: string; + content: React.ReactElement; +} + +export function EntityDetailViewWithoutParams({ + selectedTab, + tabs, + entity, + definition, +}: { + selectedTab: string; + tabs: EntityViewTab[]; + entity: { + displayName?: string; + id: string; + }; + definition?: StreamDefinition; +}) { + const router = useStreamsAppRouter(); + useStreamsAppBreadcrumbs(() => { + if (!entity.displayName) { + return []; + } + + return [ + { + title: entity.displayName, + path: `/{key}`, + params: { path: { key: entity.id } }, + } as const, + ]; + }, [entity.displayName, entity.id]); + + if (!entity.displayName) { + return ; + } + + const tabMap = Object.fromEntries( + tabs.map((tab) => { + return [ + tab.name, + { + href: router.link('/{key}/{tab}', { + path: { key: entity.id, tab: tab.name }, + }), + label: tab.label, + content: tab.content, + }, + ]; + }) + ); + + const selectedTabObject = tabMap[selectedTab]; + + return ( + + + + + + + {i18n.translate('xpack.streams.entityDetailView.goBackLinkLabel', { + defaultMessage: 'Back', + })} + + + + + + + {entity.displayName} + {definition && !definition.managed ? ( + <> + {' '} + + {i18n.translate( + 'xpack.streams.entityDetailViewWithoutParams.unmanagedBadgeLabel', + { defaultMessage: 'Unmanaged' } + )} + + + ) : null} + + } + /> + } + > + { + return { + name: tabKey, + label, + href, + selected: selectedTab === tabKey, + }; + })} + /> + + + {selectedTabObject.content} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/entity_detail_view_header_section/index.tsx b/x-pack/plugins/streams_app/public/components/entity_detail_view_header_section/index.tsx new file mode 100644 index 000000000000..4aafb7a7e9bc --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/entity_detail_view_header_section/index.tsx @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiFlexGroup, EuiText } from '@elastic/eui'; +import { css } from '@emotion/css'; +import React from 'react'; + +export function EntityDetailViewHeaderSection({ + title, + children, +}: { + title: React.ReactNode; + children: React.ReactNode; +}) { + return ( + + + {title} + + {children} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/entity_overview_tab_list/index.tsx b/x-pack/plugins/streams_app/public/components/entity_overview_tab_list/index.tsx new file mode 100644 index 000000000000..08502b26f7ca --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/entity_overview_tab_list/index.tsx @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiTab, EuiTabs, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/css'; + +export function EntityOverviewTabList< + T extends { name: string; label: string; href: string; selected: boolean } +>({ tabs }: { tabs: T[] }) { + const theme = useEuiTheme().euiTheme; + + return ( + + {tabs.map((tab) => { + return ( + + {tab.label} + + ); + })} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/esql_chart/controlled_esql_chart.tsx b/x-pack/plugins/streams_app/public/components/esql_chart/controlled_esql_chart.tsx new file mode 100644 index 000000000000..9008f8ee4709 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/esql_chart/controlled_esql_chart.tsx @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useMemo } from 'react'; +import { + AreaSeries, + Axis, + BarSeries, + Chart, + CurveType, + LineSeries, + Position, + ScaleType, + Settings, + Tooltip, + niceTimeFormatter, +} from '@elastic/charts'; +import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { getTimeZone } from '@kbn/observability-utils-browser/utils/ui_settings/get_timezone'; +import { css } from '@emotion/css'; +import { AbortableAsyncState } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import type { UnparsedEsqlResponse } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; +import { esqlResultToTimeseries } from '../../util/esql_result_to_timeseries'; +import { useKibana } from '../../hooks/use_kibana'; +import { LoadingPanel } from '../loading_panel'; + +const END_ZONE_LABEL = i18n.translate('xpack.streams.esqlChart.endzone', { + defaultMessage: + 'The selected time range does not include this entire bucket. It might contain partial data.', +}); + +function getChartType(type: 'area' | 'bar' | 'line') { + switch (type) { + case 'area': + return AreaSeries; + case 'bar': + return BarSeries; + default: + return LineSeries; + } +} + +export function ControlledEsqlChart({ + id, + result, + metricNames, + chartType = 'line', + height, +}: { + id: string; + result: AbortableAsyncState; + metricNames: T[]; + chartType?: 'area' | 'bar' | 'line'; + height: number; +}) { + const { + core: { uiSettings }, + } = useKibana(); + + const allTimeseries = useMemo( + () => + esqlResultToTimeseries({ + result, + metricNames, + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [result, ...metricNames] + ); + + if (result.loading && !result.value?.values.length) { + return ( + + ); + } + + const xValues = allTimeseries.flatMap(({ data }) => data.map(({ x }) => x)); + + const min = Math.min(...xValues); + const max = Math.max(...xValues); + + const isEmpty = min === 0 && max === 0; + + const xFormatter = niceTimeFormatter([min, max]); + + const xDomain = isEmpty ? { min: 0, max: 1 } : { min, max }; + + const yTickFormat = (value: number | null) => (value === null ? '' : String(value)); + const yLabelFormat = (label: string) => label; + + const timeZone = getTimeZone(uiSettings); + + return ( + + { + const formattedValue = xFormatter(value); + if (max === value) { + return ( + <> + + + + + {END_ZONE_LABEL} + + + {formattedValue} + + ); + } + return formattedValue; + }} + /> + + + + {allTimeseries.map((serie) => { + const Series = getChartType(chartType); + + return ( + + ); + })} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/loading_panel/index.tsx b/x-pack/plugins/streams_app/public/components/loading_panel/index.tsx new file mode 100644 index 000000000000..58e432b84a4b --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/loading_panel/index.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiFlexGroup, EuiLoadingSpinner, EuiSpacer } from '@elastic/eui'; +import React from 'react'; + +export function LoadingPanel({ + loading = true, + size, + className, +}: { + loading?: boolean; + size?: React.ComponentProps['size']; + className?: string; +}) { + if (!loading) { + return null; + } + + return ( + + + + + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/not_found/index.tsx b/x-pack/plugins/streams_app/public/components/not_found/index.tsx new file mode 100644 index 000000000000..c0c1d50000cf --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/not_found/index.tsx @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiCallOut } from '@elastic/eui'; +import React from 'react'; +import { i18n } from '@kbn/i18n'; + +export function NotFound() { + return ( + + {i18n.translate('xpack.streams.notFound.calloutLabel', { + defaultMessage: 'The current page can not be found.', + })} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/redirect_to/index.tsx b/x-pack/plugins/streams_app/public/components/redirect_to/index.tsx new file mode 100644 index 000000000000..2bde67faa3b9 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/redirect_to/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useLayoutEffect } from 'react'; +import { PathsOf, TypeOf } from '@kbn/typed-react-router-config'; +import { DeepPartial } from 'utility-types'; +import { merge } from 'lodash'; +import { StreamsAppRoutes } from '../../routes/config'; +import { useStreamsAppRouter } from '../../hooks/use_streams_app_router'; +import { useStreamsAppParams } from '../../hooks/use_streams_app_params'; + +export function RedirectTo< + TPath extends PathsOf, + TParams extends TypeOf +>({ path, params }: { path: TPath; params?: DeepPartial }) { + const router = useStreamsAppRouter(); + const currentParams = useStreamsAppParams('/*'); + useLayoutEffect(() => { + router.replace(path, ...([merge({}, currentParams, params)] as any)); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + return <>; +} diff --git a/x-pack/plugins/streams_app/public/components/stream_detail_enriching/index.tsx b/x-pack/plugins/streams_app/public/components/stream_detail_enriching/index.tsx new file mode 100644 index 000000000000..d87914216235 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_detail_enriching/index.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import React from 'react'; + +export function StreamDetailEnriching({ + definition: _definition, + refreshDefinition: _refreshDefinition, +}: { + definition?: StreamDefinition; + refreshDefinition: () => void; +}) { + return <>{'TODO'}; +} diff --git a/x-pack/plugins/streams_app/public/components/stream_detail_management/index.tsx b/x-pack/plugins/streams_app/public/components/stream_detail_management/index.tsx new file mode 100644 index 000000000000..749b0e659d65 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_detail_management/index.tsx @@ -0,0 +1,195 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import { EuiButtonGroup, EuiFlexGroup, EuiFlexItem, EuiListGroup, EuiText } from '@elastic/eui'; +import { useStreamsAppParams } from '../../hooks/use_streams_app_params'; +import { RedirectTo } from '../redirect_to'; +import { useStreamsAppRouter } from '../../hooks/use_streams_app_router'; +import { StreamDetailRouting } from '../stream_detail_routing'; +import { StreamDetailEnriching } from '../stream_detail_enriching'; +import { StreamDetailSchemaEditor } from '../stream_detail_schema_editor'; +import { useKibana } from '../../hooks/use_kibana'; + +type ManagementSubTabs = 'route' | 'enrich' | 'schemaEditor'; + +function isValidManagementSubTab(value: string): value is ManagementSubTabs { + return ['route', 'enrich', 'schemaEditor'].includes(value); +} + +export function StreamDetailManagement({ + definition, + refreshDefinition, +}: { + definition?: StreamDefinition; + refreshDefinition: () => void; +}) { + const { + path: { key, subtab }, + } = useStreamsAppParams('/{key}/management/{subtab}'); + const router = useStreamsAppRouter(); + + if (subtab === 'overview') { + if (!definition) { + return null; + } + if (definition.managed) { + return ( + + ); + } + return ; + } + + const tabs = { + route: { + content: ( + + ), + label: i18n.translate('xpack.streams.streamDetailView.routingTab', { + defaultMessage: 'Streams Partitioning', + }), + }, + enrich: { + content: ( + + ), + label: i18n.translate('xpack.streams.streamDetailView.enrichingTab', { + defaultMessage: 'Extract field', + }), + }, + schemaEditor: { + content: ( + + ), + label: i18n.translate('xpack.streams.streamDetailView.schemaEditorTab', { + defaultMessage: 'Schema editor', + }), + }, + }; + + if (!isValidManagementSubTab(subtab)) { + return ( + + ); + } + + if (!definition?.managed) { + return ( + + ); + } + + const selectedTabObject = tabs[subtab]; + + return ( + + + { + router.push('/{key}/management/{subtab}', { + path: { key, subtab: optionId }, + query: {}, + }); + }} + options={Object.keys(tabs).map((id) => ({ + id, + label: tabs[id as ManagementSubTabs].label, + }))} + /> + + {selectedTabObject.content} + + ); +} + +function assetToLink(asset: { type: string; id: string }) { + switch (asset.type) { + case 'index_template': + return `/app/management/data/index_management/templates/${asset.id}`; + case 'component_template': + return `/app/management/data/index_management/component_templates/${asset.id}`; + case 'data_stream': + return `/app/management/data/index_management/data_streams/${asset.id}`; + case 'ingest_pipeline': + return `/app/management/ingest/ingest_pipelines?pipeline=${asset.id}`; + default: + return ''; + } +} + +function assetToTitle(asset: { type: string; id: string }) { + switch (asset.type) { + case 'index_template': + return i18n.translate('xpack.streams.streamDetailView.indexTemplate', { + defaultMessage: 'Index template', + }); + case 'component_template': + return i18n.translate('xpack.streams.streamDetailView.componentTemplate', { + defaultMessage: 'Component template', + }); + case 'data_stream': + return i18n.translate('xpack.streams.streamDetailView.dataStream', { + defaultMessage: 'Data stream', + }); + case 'ingest_pipeline': + return i18n.translate('xpack.streams.streamDetailView.ingestPipeline', { + defaultMessage: 'Ingest pipeline', + }); + default: + return ''; + } +} + +function UnmanagedStreamOverview({ definition }: { definition: StreamDefinition }) { + const { + core: { + http: { basePath }, + }, + } = useKibana(); + const groupedAssets = (definition.unmanaged_elasticsearch_assets ?? []).reduce((acc, asset) => { + const title = assetToTitle(asset); + if (title) { + acc[title] = acc[title] ?? []; + acc[title].push(asset); + } + return acc; + }, {} as Record>); + return ( + + +

        + {i18n.translate('xpack.streams.streamDetailView.unmanagedStreamOverview', { + defaultMessage: + 'This stream is not managed. Follow the links to stack management to change the related Elasticsearch objects.', + })} +

        +
        + {Object.entries(groupedAssets).map(([title, assets]) => ( +
        + +

        {title}

        +
        + ({ + label: asset.id, + href: basePath.prepend(assetToLink(asset)), + iconType: 'index', + target: '_blank', + }))} + /> +
        + ))} +
        + ); +} diff --git a/x-pack/plugins/streams_app/public/components/stream_detail_overview/index.tsx b/x-pack/plugins/streams_app/public/components/stream_detail_overview/index.tsx new file mode 100644 index 000000000000..c051d114317e --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_detail_overview/index.tsx @@ -0,0 +1,172 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; +import { calculateAuto } from '@kbn/calculate-auto'; +import { i18n } from '@kbn/i18n'; +import { useDateRange } from '@kbn/observability-utils-browser/hooks/use_date_range'; +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import moment from 'moment'; +import React, { useMemo } from 'react'; +import { useKibana } from '../../hooks/use_kibana'; +import { useStreamsAppFetch } from '../../hooks/use_streams_app_fetch'; +import { ControlledEsqlChart } from '../esql_chart/controlled_esql_chart'; +import { StreamsAppSearchBar } from '../streams_app_search_bar'; + +export function StreamDetailOverview({ definition }: { definition?: StreamDefinition }) { + const { + dependencies: { + start: { + data, + dataViews, + streams: { streamsRepositoryClient }, + share, + }, + }, + } = useKibana(); + + const { + timeRange, + absoluteTimeRange: { start, end }, + setTimeRange, + } = useDateRange({ data }); + + const indexPatterns = useMemo(() => { + if (!definition?.id) { + return undefined; + } + + const isRoot = definition.id.indexOf('.') === -1; + + const dataStreamOfDefinition = definition.id; + + return isRoot + ? [dataStreamOfDefinition, `${dataStreamOfDefinition}.*`] + : [`${dataStreamOfDefinition}*`]; + }, [definition?.id]); + + const discoverLocator = useMemo( + () => share.url.locators.get('DISCOVER_APP_LOCATOR'), + [share.url.locators] + ); + + const queries = useMemo(() => { + if (!indexPatterns) { + return undefined; + } + + const baseQuery = `FROM ${indexPatterns.join(', ')}`; + + const bucketSize = Math.round( + calculateAuto.atLeast(50, moment.duration(1, 'minute'))!.asSeconds() + ); + + const histogramQuery = `${baseQuery} | STATS metric = COUNT(*) BY @timestamp = BUCKET(@timestamp, ${bucketSize} seconds)`; + + return { + baseQuery, + histogramQuery, + }; + }, [indexPatterns]); + + const discoverLink = useMemo(() => { + if (!discoverLocator || !queries?.baseQuery) { + return undefined; + } + + return discoverLocator.getRedirectUrl({ + query: { + esql: queries.baseQuery, + }, + }); + }, [queries?.baseQuery, discoverLocator]); + + const histogramQueryFetch = useStreamsAppFetch( + async ({ signal }) => { + if (!queries?.histogramQuery || !indexPatterns) { + return undefined; + } + + const existingIndices = await dataViews.getExistingIndices(indexPatterns); + + if (existingIndices.length === 0) { + return undefined; + } + + return streamsRepositoryClient.fetch('POST /internal/streams/esql', { + params: { + body: { + operationName: 'get_histogram_for_stream', + query: queries.histogramQuery, + start, + end, + }, + }, + signal, + }); + }, + [indexPatterns, dataViews, streamsRepositoryClient, queries?.histogramQuery, start, end] + ); + + return ( + <> + + + + + { + if (!isUpdate) { + histogramQueryFetch.refresh(); + return; + } + + if (dateRange) { + setTimeRange({ from: dateRange.from, to: dateRange?.to, mode: dateRange.mode }); + } + }} + onRefresh={() => { + histogramQueryFetch.refresh(); + }} + placeholder={i18n.translate( + 'xpack.streams.entityDetailOverview.searchBarPlaceholder', + { + defaultMessage: 'Filter data by using KQL', + } + )} + dateRangeFrom={timeRange.from} + dateRangeTo={timeRange.to} + /> + + + {i18n.translate('xpack.streams.streamDetailOverview.openInDiscoverButtonLabel', { + defaultMessage: 'Open in Discover', + })} + + + + + + + + + + + + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/stream_detail_routing/index.tsx b/x-pack/plugins/streams_app/public/components/stream_detail_routing/index.tsx new file mode 100644 index 000000000000..af65c7eab423 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_detail_routing/index.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import React from 'react'; + +export function StreamDetailRouting({ + definition: _definition, + refreshDefinition: _refreshDefinition, +}: { + definition?: StreamDefinition; + refreshDefinition: () => void; +}) { + return <>{'TODO'}; +} diff --git a/x-pack/plugins/streams_app/public/components/stream_detail_schema_editor/index.tsx b/x-pack/plugins/streams_app/public/components/stream_detail_schema_editor/index.tsx new file mode 100644 index 000000000000..7d3e9322e8d4 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_detail_schema_editor/index.tsx @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import React from 'react'; + +export function StreamDetailSchemaEditor({ + definition: _definition, + refreshDefinition: _refreshDefinition, +}: { + definition?: StreamDefinition; + refreshDefinition: () => void; +}) { + return <>{'TODO'}; +} diff --git a/x-pack/plugins/streams_app/public/components/stream_detail_view/index.tsx b/x-pack/plugins/streams_app/public/components/stream_detail_view/index.tsx new file mode 100644 index 000000000000..d091fb5758a1 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_detail_view/index.tsx @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EntityDetailViewWithoutParams, EntityViewTab } from '../entity_detail_view'; +import { useStreamsAppParams } from '../../hooks/use_streams_app_params'; +import { useStreamsAppFetch } from '../../hooks/use_streams_app_fetch'; +import { useKibana } from '../../hooks/use_kibana'; +import { StreamDetailOverview } from '../stream_detail_overview'; +import { StreamDetailManagement } from '../stream_detail_management'; + +export function StreamDetailView() { + const { path } = useStreamsAppParams('/{key}/*'); + + const key = path.key; + const tab = 'tab' in path ? path.tab : 'management'; + + const { + dependencies: { + start: { + streams: { streamsRepositoryClient }, + }, + }, + } = useKibana(); + + const { value: streamEntity, refresh } = useStreamsAppFetch( + ({ signal }) => { + return streamsRepositoryClient.fetch('GET /api/streams/{id}', { + signal, + params: { + path: { + id: key, + }, + }, + }); + }, + [streamsRepositoryClient, key] + ); + + const entity = { + id: key, + displayName: key, + }; + + const tabs: EntityViewTab[] = [ + { + name: 'overview', + content: , + label: i18n.translate('xpack.streams.streamDetailView.overviewTab', { + defaultMessage: 'Overview', + }), + }, + { + name: 'management', + content: , + label: i18n.translate('xpack.streams.streamDetailView.managementTab', { + defaultMessage: 'Management', + }), + }, + ]; + + return ( + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/stream_list_view/index.tsx b/x-pack/plugins/streams_app/public/components/stream_list_view/index.tsx new file mode 100644 index 000000000000..7ffda5f40295 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/stream_list_view/index.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem, EuiSearchBar } from '@elastic/eui'; +import { useKibana } from '../../hooks/use_kibana'; +import { useStreamsAppFetch } from '../../hooks/use_streams_app_fetch'; +import { StreamsAppPageHeader } from '../streams_app_page_header'; +import { StreamsAppPageHeaderTitle } from '../streams_app_page_header/streams_app_page_header_title'; +import { StreamsAppPageBody } from '../streams_app_page_body'; +import { StreamsTable } from '../streams_table'; + +export function StreamListView() { + const { + dependencies: { + start: { + streams: { streamsRepositoryClient }, + }, + }, + } = useKibana(); + + const [query, setQuery] = useState(''); + + const streamsListFetch = useStreamsAppFetch( + ({ signal }) => { + return streamsRepositoryClient.fetch('GET /api/streams', { + signal, + }); + }, + [streamsRepositoryClient] + ); + + return ( + + + + } + /> + + + + + { + setQuery(nextQuery.queryText); + }} + /> + + + + + + + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/streams_app_context_provider/index.tsx b/x-pack/plugins/streams_app/public/components/streams_app_context_provider/index.tsx new file mode 100644 index 000000000000..fd5886c08939 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_context_provider/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React, { useMemo } from 'react'; +import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public'; +import type { StreamsAppKibanaContext } from '../../hooks/use_kibana'; + +export function StreamsAppContextProvider({ + context, + children, +}: { + context: StreamsAppKibanaContext; + children: React.ReactNode; +}) { + const servicesForContext = useMemo(() => { + const { core, ...services } = context; + return { + ...core, + ...services, + }; + }, [context]); + + return {children}; +} diff --git a/x-pack/plugins/streams_app/public/components/streams_app_page_body/index.tsx b/x-pack/plugins/streams_app/public/components/streams_app_page_body/index.tsx new file mode 100644 index 000000000000..04b44f82df0f --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_page_body/index.tsx @@ -0,0 +1,27 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import React from 'react'; +import { EuiPanel, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/css'; + +export function StreamsAppPageBody({ children }: { children: React.ReactNode }) { + const theme = useEuiTheme().euiTheme; + return ( + + {children} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/streams_app_page_header/index.tsx b/x-pack/plugins/streams_app/public/components/streams_app_page_header/index.tsx new file mode 100644 index 000000000000..1171772116f2 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_page_header/index.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiFlexGroup, EuiPageHeader, useEuiTheme } from '@elastic/eui'; +import { css } from '@emotion/css'; +import React from 'react'; + +export function StreamsAppPageHeader({ + title, + children, + verticalPaddingSize = 'l', +}: { + title: React.ReactNode; + children?: React.ReactNode; + verticalPaddingSize?: 'none' | 'l'; +}) { + const theme = useEuiTheme().euiTheme; + + return ( + + + {title} + + {children} + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/streams_app_page_header/streams_app_page_header_title.tsx b/x-pack/plugins/streams_app/public/components/streams_app_page_header/streams_app_page_header_title.tsx new file mode 100644 index 000000000000..a0fcc554f513 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_page_header/streams_app_page_header_title.tsx @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { EuiTitle } from '@elastic/eui'; +import React from 'react'; + +export function StreamsAppPageHeaderTitle({ title }: { title: React.ReactNode }) { + return ( + +

        {title}

        +
        + ); +} diff --git a/x-pack/plugins/streams_app/public/components/streams_app_page_template/index.tsx b/x-pack/plugins/streams_app/public/components/streams_app_page_template/index.tsx new file mode 100644 index 000000000000..942d2937dba8 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_page_template/index.tsx @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { css } from '@emotion/css'; +import React from 'react'; +import { EuiPanel, EuiSpacer } from '@elastic/eui'; +import { useKibana } from '../../hooks/use_kibana'; + +export function StreamsAppPageTemplate({ children }: { children: React.ReactNode }) { + const { + dependencies: { + start: { observabilityShared }, + }, + } = useKibana(); + + const { PageTemplate } = observabilityShared.navigation; + + return ( + + + + {children} + + + ); +} diff --git a/x-pack/plugins/streams_app/public/components/streams_app_router_breadcrumb/index.tsx b/x-pack/plugins/streams_app/public/components/streams_app_router_breadcrumb/index.tsx new file mode 100644 index 000000000000..88aab4662de6 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_router_breadcrumb/index.tsx @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createRouterBreadcrumbComponent } from '@kbn/typed-react-router-config'; +import type { StreamsAppRoutes } from '../../routes/config'; + +export const StreamsAppRouterBreadcrumb = createRouterBreadcrumbComponent(); diff --git a/x-pack/plugins/streams_app/public/components/streams_app_search_bar/index.tsx b/x-pack/plugins/streams_app/public/components/streams_app_search_bar/index.tsx new file mode 100644 index 000000000000..563fb752efbd --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_app_search_bar/index.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { css } from '@emotion/css'; +import type { TimeRange } from '@kbn/es-query'; +import { SearchBar } from '@kbn/unified-search-plugin/public'; +import React, { useMemo } from 'react'; +import type { DataView } from '@kbn/data-views-plugin/common'; +import { useKibana } from '../../hooks/use_kibana'; + +const parentClassName = css` + width: 100%; +`; + +interface Props { + query?: string; + dateRangeFrom?: string; + dateRangeTo?: string; + onQueryChange?: (payload: { dateRange?: TimeRange; query: string }) => void; + onQuerySubmit?: (payload: { dateRange?: TimeRange; query: string }, isUpdate?: boolean) => void; + onRefresh?: Required>['onRefresh']; + placeholder?: string; + dataViews?: DataView[]; +} + +export function StreamsAppSearchBar({ + dateRangeFrom, + dateRangeTo, + onQueryChange, + onQuerySubmit, + onRefresh, + query, + placeholder, + dataViews, +}: Props) { + const { + dependencies: { + start: { unifiedSearch }, + }, + } = useKibana(); + + const queryObj = useMemo(() => (query ? { query, language: 'kuery' } : undefined), [query]); + + const showQueryInput = query === undefined; + + return ( +
        + { + onQuerySubmit?.( + { dateRange, query: (nextQuery?.query as string | undefined) ?? '' }, + isUpdate + ); + }} + onQueryChange={({ dateRange, query: nextQuery }) => { + onQueryChange?.({ dateRange, query: (nextQuery?.query as string | undefined) ?? '' }); + }} + query={queryObj} + showQueryInput={showQueryInput} + showFilterBar={false} + showQueryMenu={false} + showDatePicker={Boolean(dateRangeFrom && dateRangeTo)} + showSubmitButton={true} + dateRangeFrom={dateRangeFrom} + dateRangeTo={dateRangeTo} + onRefresh={onRefresh} + displayStyle="inPage" + disableQueryLanguageSwitcher + placeholder={placeholder} + indexPatterns={dataViews} + /> +
        + ); +} diff --git a/x-pack/plugins/streams_app/public/components/streams_table/index.tsx b/x-pack/plugins/streams_app/public/components/streams_table/index.tsx new file mode 100644 index 000000000000..39814ed90455 --- /dev/null +++ b/x-pack/plugins/streams_app/public/components/streams_table/index.tsx @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { + EuiBasicTable, + EuiBasicTableColumn, + EuiFlexGroup, + EuiIcon, + EuiLink, + EuiTitle, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import type { AbortableAsyncState } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import { StreamDefinition } from '@kbn/streams-plugin/common'; +import React, { useMemo } from 'react'; +import { useStreamsAppRouter } from '../../hooks/use_streams_app_router'; + +export function StreamsTable({ + listFetch, + query, +}: { + listFetch: AbortableAsyncState<{ definitions: StreamDefinition[] }>; + query: string; +}) { + const router = useStreamsAppRouter(); + + const items = useMemo(() => { + return listFetch.value?.definitions ?? []; + }, [listFetch.value?.definitions]); + + const filteredItems = useMemo(() => { + if (!query) { + return items; + } + + return items.filter((item) => item.id.toLowerCase().includes(query.toLowerCase())); + }, [query, items]); + + const columns = useMemo>>(() => { + return [ + { + field: 'id', + name: i18n.translate('xpack.streams.streamsTable.nameColumnTitle', { + defaultMessage: 'Name', + }), + render: (_, { id, managed }) => { + return ( + + + + {id} + + + ); + }, + }, + ]; + }, [router]); + + return ( + + +

        + {i18n.translate('xpack.streams.streamsTable.tableTitle', { + defaultMessage: 'Streams', + })} +

        +
        + +
        + ); +} diff --git a/x-pack/plugins/streams_app/public/hooks/use_kibana.tsx b/x-pack/plugins/streams_app/public/hooks/use_kibana.tsx new file mode 100644 index 000000000000..9c6b23465fb1 --- /dev/null +++ b/x-pack/plugins/streams_app/public/hooks/use_kibana.tsx @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreStart } from '@kbn/core/public'; +import { useMemo } from 'react'; +import { useKibana } from '@kbn/kibana-react-plugin/public'; +import type { StreamsAppStartDependencies } from '../types'; +import type { StreamsAppServices } from '../services/types'; + +export interface StreamsAppKibanaContext { + core: CoreStart; + dependencies: { + start: StreamsAppStartDependencies; + }; + services: StreamsAppServices; +} + +const useTypedKibana = (): StreamsAppKibanaContext => { + const context = useKibana>(); + + return useMemo(() => { + const { dependencies, services, ...core } = context.services; + + return { + core, + dependencies, + services, + }; + }, [context.services]); +}; + +export { useTypedKibana as useKibana }; diff --git a/x-pack/plugins/streams_app/public/hooks/use_streams_app_breadcrumbs.ts b/x-pack/plugins/streams_app/public/hooks/use_streams_app_breadcrumbs.ts new file mode 100644 index 000000000000..e3ac760e3b77 --- /dev/null +++ b/x-pack/plugins/streams_app/public/hooks/use_streams_app_breadcrumbs.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { createUseBreadcrumbs } from '@kbn/typed-react-router-config'; +import { StreamsAppRoutes } from '../routes/config'; + +export const useStreamsAppBreadcrumbs = createUseBreadcrumbs(); diff --git a/x-pack/plugins/streams_app/public/hooks/use_streams_app_fetch.ts b/x-pack/plugins/streams_app/public/hooks/use_streams_app_fetch.ts new file mode 100644 index 000000000000..08b112d4f207 --- /dev/null +++ b/x-pack/plugins/streams_app/public/hooks/use_streams_app_fetch.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { + UseAbortableAsync, + useAbortableAsync, +} from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import { omit } from 'lodash'; +import { useKibana } from './use_kibana'; + +export const useStreamsAppFetch: UseAbortableAsync<{}, { disableToastOnError?: boolean }> = ( + callback, + deps, + options +) => { + const { + core: { notifications }, + } = useKibana(); + + const onError = (error: Error) => { + let requestUrl: string | undefined; + + if (!options?.disableToastOnError) { + if ( + 'body' in error && + typeof error.body === 'object' && + !!error.body && + 'message' in error.body && + typeof error.body.message === 'string' + ) { + error.message = error.body.message; + } + + if ( + 'request' in error && + typeof error.request === 'object' && + !!error.request && + 'url' in error.request && + typeof error.request.url === 'string' + ) { + requestUrl = error.request.url; + } + + notifications.toasts.addError(error, { + title: i18n.translate('xpack.streams.failedToFetchError', { + defaultMessage: 'Failed to fetch data{requestUrlSuffix}', + values: { + requestUrlSuffix: requestUrl ? ` (${requestUrl})` : '', + }, + }), + }); + } + }; + + const optionsForHook = { + ...omit(options, 'disableToastOnError'), + onError, + }; + + return useAbortableAsync( + ({ signal }) => { + return callback({ signal }); + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + deps, + optionsForHook + ); +}; diff --git a/x-pack/plugins/streams_app/public/hooks/use_streams_app_params.ts b/x-pack/plugins/streams_app/public/hooks/use_streams_app_params.ts new file mode 100644 index 000000000000..d7a6e175e549 --- /dev/null +++ b/x-pack/plugins/streams_app/public/hooks/use_streams_app_params.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { type PathsOf, type TypeOf, useParams } from '@kbn/typed-react-router-config'; +import type { StreamsAppRoutes } from '../routes/config'; + +export function useStreamsAppParams>( + path: TPath, + optional: boolean = false +): TypeOf { + return useParams(path, optional)! as TypeOf; +} diff --git a/x-pack/plugins/streams_app/public/hooks/use_streams_app_route_path.ts b/x-pack/plugins/streams_app/public/hooks/use_streams_app_route_path.ts new file mode 100644 index 000000000000..78e63ead57da --- /dev/null +++ b/x-pack/plugins/streams_app/public/hooks/use_streams_app_route_path.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PathsOf, useRoutePath } from '@kbn/typed-react-router-config'; +import type { StreamsAppRoutes } from '../routes/config'; + +export function useStreamsAppRoutePath() { + const path = useRoutePath(); + + return path as PathsOf; +} diff --git a/x-pack/plugins/streams_app/public/hooks/use_streams_app_router.ts b/x-pack/plugins/streams_app/public/hooks/use_streams_app_router.ts new file mode 100644 index 000000000000..17472044b7b4 --- /dev/null +++ b/x-pack/plugins/streams_app/public/hooks/use_streams_app_router.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PathsOf, TypeAsArgs, TypeOf } from '@kbn/typed-react-router-config'; +import { useMemo } from 'react'; +import type { StreamsAppRouter, StreamsAppRoutes } from '../routes/config'; +import { streamsAppRouter } from '../routes/config'; +import { useKibana } from './use_kibana'; + +interface StatefulStreamsAppRouter extends StreamsAppRouter { + push>( + path: T, + ...params: TypeAsArgs> + ): void; + replace>( + path: T, + ...params: TypeAsArgs> + ): void; +} + +export function useStreamsAppRouter(): StatefulStreamsAppRouter { + const { + core: { + http, + application: { navigateToApp }, + }, + } = useKibana(); + + const link = (...args: any[]) => { + // @ts-expect-error + return streamsAppRouter.link(...args); + }; + + return useMemo( + () => ({ + ...streamsAppRouter, + push: (...args) => { + const next = link(...args); + navigateToApp('streams', { path: next, replace: false }); + }, + replace: (path, ...args) => { + const next = link(path, ...args); + navigateToApp('streams', { path: next, replace: true }); + }, + link: (path, ...args) => { + return http.basePath.prepend('/app/streams' + link(path, ...args)); + }, + }), + [navigateToApp, http.basePath] + ); +} diff --git a/x-pack/plugins/streams_app/public/index.ts b/x-pack/plugins/streams_app/public/index.ts new file mode 100644 index 000000000000..eea2d8b7452a --- /dev/null +++ b/x-pack/plugins/streams_app/public/index.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { PluginInitializer, PluginInitializerContext } from '@kbn/core/public'; + +import { StreamsAppPlugin } from './plugin'; +import type { + StreamsAppPublicSetup, + StreamsAppPublicStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies, + ConfigSchema, +} from './types'; + +export type { StreamsAppPublicSetup, StreamsAppPublicStart }; + +export const plugin: PluginInitializer< + StreamsAppPublicSetup, + StreamsAppPublicStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies +> = (pluginInitializerContext: PluginInitializerContext) => + new StreamsAppPlugin(pluginInitializerContext); diff --git a/x-pack/plugins/streams_app/public/plugin.ts b/x-pack/plugins/streams_app/public/plugin.ts new file mode 100644 index 000000000000..9df399693d02 --- /dev/null +++ b/x-pack/plugins/streams_app/public/plugin.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import { map } from 'rxjs'; +import { + AppMountParameters, + AppUpdater, + CoreSetup, + CoreStart, + DEFAULT_APP_CATEGORIES, + Plugin, + PluginInitializerContext, +} from '@kbn/core/public'; +import type { Logger } from '@kbn/logging'; +import { STREAMS_APP_ID } from '@kbn/deeplinks-observability/constants'; +import type { + ConfigSchema, + StreamsAppPublicSetup, + StreamsAppPublicStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies, +} from './types'; +import { StreamsAppServices } from './services/types'; + +export class StreamsAppPlugin + implements + Plugin< + StreamsAppPublicSetup, + StreamsAppPublicStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies + > +{ + logger: Logger; + + constructor(context: PluginInitializerContext) { + this.logger = context.logger.get(); + } + setup( + coreSetup: CoreSetup, + pluginsSetup: StreamsAppSetupDependencies + ): StreamsAppPublicSetup { + pluginsSetup.observabilityShared.navigation.registerSections( + pluginsSetup.streams.status$.pipe( + map(({ status }) => { + if (status !== 'enabled') { + return []; + } + + return [ + { + label: '', + sortKey: 101, + entries: [ + { + label: i18n.translate('xpack.streams.streamsAppLinkTitle', { + defaultMessage: 'Streams', + }), + app: STREAMS_APP_ID, + path: '/', + isTechnicalPreview: true, + matchPath(currentPath: string) { + return ['/', ''].some((testPath) => currentPath.startsWith(testPath)); + }, + }, + ], + }, + ]; + }) + ) + ); + + coreSetup.application.register({ + id: STREAMS_APP_ID, + title: i18n.translate('xpack.streams.appTitle', { + defaultMessage: 'Streams', + }), + euiIconType: 'logoObservability', + appRoute: '/app/streams', + category: DEFAULT_APP_CATEGORIES.observability, + order: 8001, + updater$: pluginsSetup.streams.status$.pipe( + map(({ status }): AppUpdater => { + return (app) => { + if (status !== 'enabled') { + return { + visibleIn: [], + deepLinks: [], + }; + } + + return { + visibleIn: ['sideNav', 'globalSearch'], + deepLinks: + status === 'enabled' + ? [ + { + id: 'streams', + title: i18n.translate('xpack.streams.streamsAppDeepLinkTitle', { + defaultMessage: 'Streams', + }), + path: '/', + }, + ] + : [], + }; + }; + }) + ), + mount: async (appMountParameters: AppMountParameters) => { + // Load application bundle and Get start services + const [{ renderApp }, [coreStart, pluginsStart]] = await Promise.all([ + import('./application'), + coreSetup.getStartServices(), + ]); + + const services: StreamsAppServices = {}; + + return renderApp({ + coreStart, + pluginsStart, + services, + appMountParameters, + }); + }, + }); + + return {}; + } + + start(coreStart: CoreStart, pluginsStart: StreamsAppStartDependencies): StreamsAppPublicStart { + return {}; + } +} diff --git a/x-pack/plugins/streams_app/public/routes/config.tsx b/x-pack/plugins/streams_app/public/routes/config.tsx new file mode 100644 index 000000000000..444218c6f976 --- /dev/null +++ b/x-pack/plugins/streams_app/public/routes/config.tsx @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { i18n } from '@kbn/i18n'; +import { createRouter, Outlet, RouteMap } from '@kbn/typed-react-router-config'; +import * as t from 'io-ts'; +import React from 'react'; +import { StreamDetailView } from '../components/stream_detail_view'; +import { StreamsAppPageTemplate } from '../components/streams_app_page_template'; +import { StreamsAppRouterBreadcrumb } from '../components/streams_app_router_breadcrumb'; +import { RedirectTo } from '../components/redirect_to'; +import { StreamListView } from '../components/stream_list_view'; + +/** + * The array of route definitions to be used when the application + * creates the routes. + */ +const streamsAppRoutes = { + '/': { + element: ( + + + + + + ), + children: { + '/{key}': { + element: , + params: t.type({ + path: t.type({ + key: t.string, + }), + }), + children: { + '/{key}': { + element: , + }, + '/{key}/management': { + element: ( + + ), + }, + '/{key}/management/{subtab}': { + element: , + params: t.type({ + path: t.type({ + subtab: t.string, + }), + }), + }, + '/{key}/{tab}': { + element: , + params: t.type({ + path: t.type({ + tab: t.string, + }), + }), + }, + }, + }, + '/': { + element: , + }, + }, + }, +} satisfies RouteMap; + +export type StreamsAppRoutes = typeof streamsAppRoutes; + +export const streamsAppRouter = createRouter(streamsAppRoutes); + +export type StreamsAppRouter = typeof streamsAppRouter; diff --git a/x-pack/plugins/streams_app/public/services/types.ts b/x-pack/plugins/streams_app/public/services/types.ts new file mode 100644 index 000000000000..7f75493d2525 --- /dev/null +++ b/x-pack/plugins/streams_app/public/services/types.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StreamsAppServices {} diff --git a/x-pack/plugins/streams_app/public/types.ts b/x-pack/plugins/streams_app/public/types.ts new file mode 100644 index 000000000000..58d44784fe03 --- /dev/null +++ b/x-pack/plugins/streams_app/public/types.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { DataPublicPluginSetup, DataPublicPluginStart } from '@kbn/data-plugin/public'; +import type { + DataViewsPublicPluginSetup, + DataViewsPublicPluginStart, +} from '@kbn/data-views-plugin/public'; +import type { + ObservabilitySharedPluginSetup, + ObservabilitySharedPluginStart, +} from '@kbn/observability-shared-plugin/public'; +import type { StreamsPluginSetup, StreamsPluginStart } from '@kbn/streams-plugin/public'; +import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public'; +import type { SharePublicSetup, SharePublicStart } from '@kbn/share-plugin/public/plugin'; +/* eslint-disable @typescript-eslint/no-empty-interface*/ + +export interface ConfigSchema {} + +export interface StreamsAppSetupDependencies { + streams: StreamsPluginSetup; + data: DataPublicPluginSetup; + dataViews: DataViewsPublicPluginSetup; + observabilityShared: ObservabilitySharedPluginSetup; + unifiedSearch: {}; + share: SharePublicSetup; +} + +export interface StreamsAppStartDependencies { + streams: StreamsPluginStart; + data: DataPublicPluginStart; + dataViews: DataViewsPublicPluginStart; + observabilityShared: ObservabilitySharedPluginStart; + unifiedSearch: UnifiedSearchPublicPluginStart; + share: SharePublicStart; +} + +export interface StreamsAppPublicSetup {} + +export interface StreamsAppPublicStart {} diff --git a/x-pack/plugins/streams_app/public/util/esql_result_to_timeseries.ts b/x-pack/plugins/streams_app/public/util/esql_result_to_timeseries.ts new file mode 100644 index 000000000000..c32bbf89135b --- /dev/null +++ b/x-pack/plugins/streams_app/public/util/esql_result_to_timeseries.ts @@ -0,0 +1,99 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { AbortableAsyncState } from '@kbn/observability-utils-browser/hooks/use_abortable_async'; +import type { UnparsedEsqlResponse } from '@kbn/observability-utils-server/es/client/create_observability_es_client'; +import { orderBy } from 'lodash'; + +interface Timeseries { + id: string; + label: string; + metricNames: T[]; + data: Array<{ x: number } & Record>; +} + +export function esqlResultToTimeseries({ + result, + metricNames, +}: { + result: AbortableAsyncState; + metricNames: T[]; +}): Array> { + const columns = result.value?.columns; + + const rows = result.value?.values; + + if (!columns?.length || !rows?.length) { + return []; + } + + const timestampColumn = columns.find((col) => col.name === '@timestamp'); + + if (!timestampColumn) { + return []; + } + + const collectedSeries: Map> = new Map(); + + rows.forEach((columnsInRow) => { + const values = new Map(); + const labels = new Map(); + let timestamp: number; + + columnsInRow.forEach((value, index) => { + const column = columns[index]; + const isTimestamp = column.name === '@timestamp'; + const isMetric = metricNames.indexOf(column.name as T) !== -1; + + if (isTimestamp) { + timestamp = new Date(value as string | number).getTime(); + } else if (isMetric) { + values.set(column.name, value as number | null); + } else { + labels.set(column.name, String(value)); + } + }); + + const seriesKey = + Array.from(labels.entries()) + .map(([key, value]) => [key, value].join(':')) + .sort() + .join(',') || '-'; + + if (!collectedSeries.has(seriesKey)) { + collectedSeries.set(seriesKey, { + id: seriesKey, + data: [], + label: seriesKey, + metricNames, + }); + } + + const series = collectedSeries.get(seriesKey)!; + + const coordinate = { + x: timestamp!, + } as { x: number } & Record; + + values.forEach((value, key) => { + if (key !== 'x') { + // @ts-expect-error + coordinate[key as T] = value; + } + }); + + series.data.push(coordinate); + + return collectedSeries; + }); + + return Array.from(collectedSeries.entries()).map(([id, timeseries]) => { + return { + ...timeseries, + data: orderBy(timeseries.data, 'x', 'asc'), + }; + }); +} diff --git a/x-pack/plugins/streams_app/server/config.ts b/x-pack/plugins/streams_app/server/config.ts new file mode 100644 index 000000000000..73e631c7f6d9 --- /dev/null +++ b/x-pack/plugins/streams_app/server/config.ts @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, type TypeOf } from '@kbn/config-schema'; + +export const config = schema.object({ + enabled: schema.boolean({ defaultValue: true }), +}); + +export type StreamsAppConfig = TypeOf; diff --git a/x-pack/plugins/streams_app/server/index.ts b/x-pack/plugins/streams_app/server/index.ts new file mode 100644 index 000000000000..1ca3b3c6e3de --- /dev/null +++ b/x-pack/plugins/streams_app/server/index.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { + PluginConfigDescriptor, + PluginInitializer, + PluginInitializerContext, +} from '@kbn/core/server'; +import type { StreamsAppConfig } from './config'; +import { StreamsAppPlugin } from './plugin'; +import type { + StreamsAppServerSetup, + StreamsAppServerStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies, +} from './types'; + +export type { StreamsAppServerSetup, StreamsAppServerStart }; + +import { config as configSchema } from './config'; + +export const config: PluginConfigDescriptor = { + schema: configSchema, +}; + +export const plugin: PluginInitializer< + StreamsAppServerSetup, + StreamsAppServerStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies +> = async (pluginInitializerContext: PluginInitializerContext) => + new StreamsAppPlugin(pluginInitializerContext); diff --git a/x-pack/plugins/streams_app/server/plugin.ts b/x-pack/plugins/streams_app/server/plugin.ts new file mode 100644 index 000000000000..00fb61c1a9cc --- /dev/null +++ b/x-pack/plugins/streams_app/server/plugin.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import type { Logger } from '@kbn/logging'; +import type { + ConfigSchema, + StreamsAppServerSetup, + StreamsAppServerStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies, +} from './types'; + +export class StreamsAppPlugin + implements + Plugin< + StreamsAppServerSetup, + StreamsAppServerStart, + StreamsAppSetupDependencies, + StreamsAppStartDependencies + > +{ + logger: Logger; + + constructor(context: PluginInitializerContext) { + this.logger = context.logger.get(); + } + setup( + coreSetup: CoreSetup, + pluginsSetup: StreamsAppSetupDependencies + ): StreamsAppServerSetup { + return {}; + } + + start(core: CoreStart, pluginsStart: StreamsAppStartDependencies): StreamsAppServerStart { + return {}; + } +} diff --git a/x-pack/plugins/streams_app/server/types.ts b/x-pack/plugins/streams_app/server/types.ts new file mode 100644 index 000000000000..e425ae7422d7 --- /dev/null +++ b/x-pack/plugins/streams_app/server/types.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import type { StreamsPluginStart, StreamsPluginSetup } from '@kbn/streams-plugin/server'; + +/* eslint-disable @typescript-eslint/no-empty-interface*/ + +export interface ConfigSchema {} + +export interface StreamsAppSetupDependencies { + streams: StreamsPluginSetup; +} + +export interface StreamsAppStartDependencies { + streams: StreamsPluginStart; +} + +export interface StreamsAppServerSetup {} + +export interface StreamsAppServerStart {} diff --git a/x-pack/plugins/streams_app/tsconfig.json b/x-pack/plugins/streams_app/tsconfig.json new file mode 100644 index 000000000000..39acb94665ae --- /dev/null +++ b/x-pack/plugins/streams_app/tsconfig.json @@ -0,0 +1,37 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "../../../typings/**/*", + "common/**/*", + "public/**/*", + "typings/**/*", + "public/**/*.json", + "server/**/*", + ".storybook/**/*" + ], + "exclude": ["target/**/*", ".storybook/**/*.js"], + "kbn_references": [ + "@kbn/core", + "@kbn/data-plugin", + "@kbn/data-views-plugin", + "@kbn/observability-shared-plugin", + "@kbn/unified-search-plugin", + "@kbn/react-kibana-context-render", + "@kbn/shared-ux-link-redirect-app", + "@kbn/typed-react-router-config", + "@kbn/i18n", + "@kbn/observability-utils-browser", + "@kbn/kibana-react-plugin", + "@kbn/es-query", + "@kbn/logging", + "@kbn/deeplinks-observability", + "@kbn/config-schema", + "@kbn/calculate-auto", + "@kbn/streams-plugin", + "@kbn/share-plugin", + "@kbn/observability-utils-server", + ] +} diff --git a/x-pack/plugins/task_manager/server/index.ts b/x-pack/plugins/task_manager/server/index.ts index 79ec16b52987..f2ad559f02b9 100644 --- a/x-pack/plugins/task_manager/server/index.ts +++ b/x-pack/plugins/task_manager/server/index.ts @@ -104,4 +104,13 @@ export const config: PluginConfigDescriptor = { }, ]; }, + exposeToUsage: { + claim_strategy: true, + discovery: { + active_nodes_lookback: true, + }, + unsafe: { + exclude_task_types: true, + }, + }, }; diff --git a/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.test.ts b/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.test.ts index 23ef344c197f..f5b3912eabd3 100644 --- a/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.test.ts +++ b/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.test.ts @@ -644,7 +644,7 @@ describe('estimateCapacity', () => { value: expect.any(Object), }); expect(logger.warn).toHaveBeenCalledWith( - 'Task Manager is unhealthy, the assumedAverageRecurringRequiredThroughputPerMinutePerKibana (175) < capacityPerMinutePerKibana (200)' + 'Task Manager is unhealthy, the assumedRequiredThroughputPerMinutePerKibana (215) >= capacityPerMinutePerKibana (200)' ); }); @@ -710,7 +710,7 @@ describe('estimateCapacity', () => { value: expect.any(Object), }); expect(logger.warn).toHaveBeenCalledWith( - 'Task Manager is unhealthy, the assumedRequiredThroughputPerMinutePerKibana (250) >= capacityPerMinutePerKibana (200) AND assumedAverageRecurringRequiredThroughputPerMinutePerKibana (210) >= capacityPerMinutePerKibana (200)' + 'Task Manager is unhealthy, the assumedAverageRecurringRequiredThroughputPerMinutePerKibana (210) > capacityPerMinutePerKibana (200)' ); }); diff --git a/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.ts b/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.ts index acbf1284b21b..a4a9c963e8ee 100644 --- a/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.ts +++ b/x-pack/plugins/task_manager/server/monitoring/capacity_estimation.ts @@ -248,13 +248,13 @@ function getHealthStatus( return { status: HealthStatus.OK, reason }; } - if (assumedAverageRecurringRequiredThroughputPerMinutePerKibana < capacityPerMinutePerKibana) { - const reason = `Task Manager is unhealthy, the assumedAverageRecurringRequiredThroughputPerMinutePerKibana (${assumedAverageRecurringRequiredThroughputPerMinutePerKibana}) < capacityPerMinutePerKibana (${capacityPerMinutePerKibana})`; + if (assumedAverageRecurringRequiredThroughputPerMinutePerKibana > capacityPerMinutePerKibana) { + const reason = `Task Manager is unhealthy, the assumedAverageRecurringRequiredThroughputPerMinutePerKibana (${assumedAverageRecurringRequiredThroughputPerMinutePerKibana}) > capacityPerMinutePerKibana (${capacityPerMinutePerKibana})`; logger.warn(reason); return { status: HealthStatus.OK, reason }; } - const reason = `Task Manager is unhealthy, the assumedRequiredThroughputPerMinutePerKibana (${assumedRequiredThroughputPerMinutePerKibana}) >= capacityPerMinutePerKibana (${capacityPerMinutePerKibana}) AND assumedAverageRecurringRequiredThroughputPerMinutePerKibana (${assumedAverageRecurringRequiredThroughputPerMinutePerKibana}) >= capacityPerMinutePerKibana (${capacityPerMinutePerKibana})`; + const reason = `Task Manager is unhealthy, the assumedRequiredThroughputPerMinutePerKibana (${assumedRequiredThroughputPerMinutePerKibana}) >= capacityPerMinutePerKibana (${capacityPerMinutePerKibana})`; logger.warn(reason); return { status: HealthStatus.OK, reason }; } diff --git a/x-pack/plugins/task_manager/server/task_store.test.ts b/x-pack/plugins/task_manager/server/task_store.test.ts index cbb1c44dde3f..029aa2b1760c 100644 --- a/x-pack/plugins/task_manager/server/task_store.test.ts +++ b/x-pack/plugins/task_manager/server/task_store.test.ts @@ -555,7 +555,14 @@ describe('TaskStore', () => { body: { size: 0, query: { - bool: { filter: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }] }, + bool: { + filter: { + bool: { + must: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }], + must_not: [{ term: { 'task.status': 'unrecognized' } }], + }, + }, + }, }, aggs: { testAgg: { terms: { field: 'task.taskType' } } }, }, @@ -578,7 +585,12 @@ describe('TaskStore', () => { must: [ { bool: { - filter: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }], + filter: { + bool: { + must: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }], + must_not: [{ term: { 'task.status': 'unrecognized' } }], + }, + }, }, }, { term: { 'task.taskType': 'bar' } }, @@ -600,7 +612,14 @@ describe('TaskStore', () => { body: { size: 0, query: { - bool: { filter: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }] }, + bool: { + filter: { + bool: { + must: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }], + must_not: [{ term: { 'task.status': 'unrecognized' } }], + }, + }, + }, }, aggs: { testAgg: { terms: { field: 'task.taskType' } } }, runtime_mappings: { testMapping: { type: 'long', script: { source: `` } } }, diff --git a/x-pack/plugins/task_manager/server/task_store.ts b/x-pack/plugins/task_manager/server/task_store.ts index 0946c5c18d32..6c48f3bd7552 100644 --- a/x-pack/plugins/task_manager/server/task_store.ts +++ b/x-pack/plugins/task_manager/server/task_store.ts @@ -34,6 +34,7 @@ import { ConcreteTaskInstance, ConcreteTaskInstanceVersion, TaskInstance, + TaskStatus, TaskLifecycle, TaskLifecycleResult, SerializedConcreteTaskInstance, @@ -842,7 +843,12 @@ function ensureAggregationOnlyReturnsEnabledTaskObjects(opts: AggregationOpts): const originalQuery = opts.query; const filterToOnlyTasks = { bool: { - filter: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }], + filter: { + bool: { + must: [{ term: { type: 'task' } }, { term: { 'task.enabled': true } }], + must_not: [{ term: { 'task.status': TaskStatus.Unrecognized } }], + }, + }, }, }; const query = originalQuery diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/README.md b/x-pack/plugins/telemetry_collection_xpack/schema/README.md index 097cc6c57d88..80040d1ec387 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/README.md +++ b/x-pack/plugins/telemetry_collection_xpack/schema/README.md @@ -2,17 +2,21 @@ This is an extension of the [OSS Telemetry Schemas](../../../../src/plugins/telemetry/schema) to add the X-Pack-related data. The payloads described in these `.json` files must be merged to the OSS ones to get the structure of the full payload sent to the Remote Telemetry Service. All the files follow the schema convention as defined in the `usage_collection` plugin and `@kbn/telemetry-tools`. -There are currently 2 files: +There are currently 7 files: - `xpack_root.json`: Defines the extra fields x-pack reports over the OSS payload defined in the `oss_root.json`. Manually maintained for now because the frequency it changes is expected to be pretty low. - `xpack_plugins.json`: The X-Pack related schema for the content that will be nested in `stack_stats.kibana.plugins`. It is automatically generated by `@kbn/telemetry-tools` based on the `schema` property provided by all the registered Usage Collectors via the `usageCollection.makeUsageCollector` API. More details in the [Schema field](../../usage_collection/README.md#schema-field) chapter in the UsageCollection's docs. +- `xpack_platform.json`: Same as `xpack_plugins.json` but for collectors defined in `/x-pack/platform/*`. +- `xpack_observability.json`: Same as `xpack_plugins.json` but for collectors defined in `/x-pack/solutions/observability/*`. +- `xpack_search.json`: Same as `xpack_plugins.json` but for collectors defined in `/x-pack/solutions/search/*`. +- `xpack_security.json`: Same as `xpack_plugins.json` but for collectors defined in `/x-pack/solutions/security/*`. - `xpack_monitoring.json`: It declares the payload sent by the monitoring-sourced telemetry. The actual schema for the payload is declared under `properties.monitoringTelemetry.properties.stats.items`, but due to the general behaviour in the `@kbn/telemetry-tools`, it gets nested down in that path. NOTE: Despite its similarities to ES mappings, the intention of these files is not to define any index mappings. They should be considered as a tool to understand the format of the payload that will be sent when reporting telemetry to the Remote Service. ## Testing -Functional tests are defined at `x-pack/test/api_integration/apis/telemetry/telemetry_local.ts`. They merge both files (+ the OSS definitions), and validates the actual output of the telemetry endpoint against the final schema. \ No newline at end of file +Functional tests are defined at `x-pack/test/api_integration/apis/telemetry/telemetry_local.ts`. They merge these files (+ the [OSS definitions](../../../../src/plugins/telemetry/schema)), and validates the actual output of the telemetry endpoint against the final schema. \ No newline at end of file diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_observability.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_observability.json new file mode 100644 index 000000000000..d5b0514b6491 --- /dev/null +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_observability.json @@ -0,0 +1,3 @@ +{ + "properties": {} +} diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_platform.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_platform.json new file mode 100644 index 000000000000..d5b0514b6491 --- /dev/null +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_platform.json @@ -0,0 +1,3 @@ +{ + "properties": {} +} diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json index 257ad9c3af07..b08684479221 100644 --- a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_plugins.json @@ -15224,6 +15224,12 @@ } } }, + "fipsModeEnabled": { + "type": "boolean", + "_meta": { + "description": "Indicates if Kibana is being run in FIPS mode." + } + }, "httpAuthSchemes": { "type": "array", "items": { diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_search.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_search.json new file mode 100644 index 000000000000..d5b0514b6491 --- /dev/null +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_search.json @@ -0,0 +1,3 @@ +{ + "properties": {} +} diff --git a/x-pack/plugins/telemetry_collection_xpack/schema/xpack_security.json b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_security.json new file mode 100644 index 000000000000..d5b0514b6491 --- /dev/null +++ b/x-pack/plugins/telemetry_collection_xpack/schema/xpack_security.json @@ -0,0 +1,3 @@ +{ + "properties": {} +} diff --git a/x-pack/plugins/telemetry_collection_xpack/tsconfig.json b/x-pack/plugins/telemetry_collection_xpack/tsconfig.json index 5ea98b7ecfb1..740f21400b2a 100644 --- a/x-pack/plugins/telemetry_collection_xpack/tsconfig.json +++ b/x-pack/plugins/telemetry_collection_xpack/tsconfig.json @@ -8,9 +8,7 @@ "common/**/*", "server/**/*", "../../../typings/*", - "schema/xpack_monitoring.json", - "schema/xpack_plugins.json", - "schema/xpack_root.json", + "schema/*.json", ], "kbn_references": [ "@kbn/core", diff --git a/x-pack/plugins/timelines/common/index.ts b/x-pack/plugins/timelines/common/index.ts index 0a96a22fb267..3e335a7edd27 100644 --- a/x-pack/plugins/timelines/common/index.ts +++ b/x-pack/plugins/timelines/common/index.ts @@ -67,3 +67,5 @@ export type { } from './search_strategy'; export { Direction, EntityType, EMPTY_BROWSER_FIELDS } from './search_strategy'; + +export { getDataFromFieldsHits, toArray, isGeoField, toObjectArrayOfStrings } from './utils'; diff --git a/x-pack/plugins/timelines/common/utils/field_formatters.test.ts b/x-pack/plugins/timelines/common/utils/field_formatters.test.ts index 43babd374d99..46eb77c8f7f3 100644 --- a/x-pack/plugins/timelines/common/utils/field_formatters.test.ts +++ b/x-pack/plugins/timelines/common/utils/field_formatters.test.ts @@ -7,7 +7,7 @@ import { eventDetailsFormattedFields, eventHit } from '@kbn/securitysolution-t-grid'; import { EventHit } from '../search_strategy'; -import { getDataFromFieldsHits, getDataSafety } from './field_formatters'; +import { getDataFromFieldsHits } from './field_formatters'; describe('Events Details Helpers', () => { const fields: EventHit['fields'] = eventHit.fields; @@ -84,7 +84,7 @@ describe('Events Details Helpers', () => { }, ]; const result = getDataFromFieldsHits(whackFields); - expect(result).toEqual(whackResultFields); + expect(result).toMatchObject(whackResultFields); }); it('flattens alert parameters', () => { const ruleParameterFields = { @@ -191,7 +191,7 @@ describe('Events Details Helpers', () => { ]; const result = getDataFromFieldsHits(ruleParameterFields); - expect(result).toEqual(ruleParametersResultFields); + expect(result).toMatchObject(ruleParametersResultFields); }); it('get data from threat enrichments', () => { @@ -546,6 +546,17 @@ describe('Events Details Helpers', () => { originalValue: ['495ad7a7-316e-4544-8a0f-9c098daee76e'], values: ['495ad7a7-316e-4544-8a0f-9c098daee76e'], }, + { + category: 'threat', + field: 'threat.enrichments', + isObjectArray: true, + originalValue: [ + '{"matched.field":["myhash.mysha256"],"matched.index":["logs-ti_abusech.malware"],"matched.type":["indicator_match_rule"],"feed.name":["AbuseCH malware"],"matched.atomic":["a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3"]}', + ], + values: [ + '{"matched.field":["myhash.mysha256"],"matched.index":["logs-ti_abusech.malware"],"matched.type":["indicator_match_rule"],"feed.name":["AbuseCH malware"],"matched.atomic":["a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3"]}', + ], + }, { category: 'threat', field: 'threat.enrichments.matched.field', @@ -581,25 +592,9 @@ describe('Events Details Helpers', () => { originalValue: ['a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3'], values: ['a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3'], }, - { - category: 'threat', - field: 'threat.enrichments', - isObjectArray: true, - originalValue: [ - '{"matched.field":["myhash.mysha256"],"matched.index":["logs-ti_abusech.malware"],"matched.type":["indicator_match_rule"],"feed.name":["AbuseCH malware"],"matched.atomic":["a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3"]}', - ], - values: [ - '{"matched.field":["myhash.mysha256"],"matched.index":["logs-ti_abusech.malware"],"matched.type":["indicator_match_rule"],"feed.name":["AbuseCH malware"],"matched.atomic":["a04ac6d98ad989312783d4fe3456c53730b212c79a426fb215708b6c6daa3de3"]}', - ], - }, ]; const result = getDataFromFieldsHits(data); - expect(result).toEqual(ruleParametersResultFields); + expect(result).toMatchObject(ruleParametersResultFields); }); }); - - it('#getDataSafety', async () => { - const result = await getDataSafety(getDataFromFieldsHits, fields); - expect(result).toEqual(resultFields); - }); }); diff --git a/x-pack/plugins/timelines/common/utils/field_formatters.ts b/x-pack/plugins/timelines/common/utils/field_formatters.ts index c9292987f59b..2e3785633bc3 100644 --- a/x-pack/plugins/timelines/common/utils/field_formatters.ts +++ b/x-pack/plugins/timelines/common/utils/field_formatters.ts @@ -8,9 +8,15 @@ import { isEmpty } from 'lodash/fp'; import { ALERT_RULE_PARAMETERS } from '@kbn/rule-data-utils'; -import { ecsFieldMap } from '@kbn/rule-registry-plugin/common/assets/field_maps/ecs_field_map'; -import { technicalRuleFieldMap } from '@kbn/rule-registry-plugin/common/assets/field_maps/technical_rule_field_map'; -import { legacyExperimentalFieldMap } from '@kbn/alerts-as-data-utils'; +import { + ecsFieldMap, + EcsFieldMap, +} from '@kbn/rule-registry-plugin/common/assets/field_maps/ecs_field_map'; +import { + technicalRuleFieldMap, + TechnicalRuleFieldMap, +} from '@kbn/rule-registry-plugin/common/assets/field_maps/technical_rule_field_map'; +import { legacyExperimentalFieldMap, ExperimentalRuleFieldMap } from '@kbn/alerts-as-data-utils'; import { Fields, TimelineEventsDetailsItem } from '../search_strategy'; import { toObjectArrayOfStrings, toStringArray } from './to_array'; import { ENRICHMENT_DESTINATION_PATH } from '../constants'; @@ -51,117 +57,141 @@ export const isRuleParametersFieldOrSubfield = (field: string, prependField?: st export const isThreatEnrichmentFieldOrSubfield = (field: string, prependField?: string) => prependField?.includes(ENRICHMENT_DESTINATION_PATH) || field === ENRICHMENT_DESTINATION_PATH; +// Helper functions +const createFieldItem = ( + fieldCategory: string, + field: string, + values: string[], + isObjectArray: boolean +): TimelineEventsDetailsItem => ({ + category: fieldCategory, + field, + values, + originalValue: values, + isObjectArray, +}); + +const processGeoField = ( + field: string, + item: unknown[], + fieldCategory: string +): TimelineEventsDetailsItem => { + const formattedLocation = formatGeoLocation(item); + return createFieldItem(fieldCategory, field, formattedLocation, true); +}; + +const processSimpleField = ( + dotField: string, + strArr: string[], + isObjectArray: boolean, + fieldCategory: string +): TimelineEventsDetailsItem => createFieldItem(fieldCategory, dotField, strArr, isObjectArray); + +const processNestedFields = ( + item: unknown, + dotField: string, + fieldCategory: string, + prependDotField: boolean +): TimelineEventsDetailsItem[] => { + if (Array.isArray(item)) { + return item.flatMap((curr) => + getDataFromFieldsHits(curr as Fields, prependDotField ? dotField : undefined, fieldCategory) + ); + } + + return getDataFromFieldsHits( + item as Fields, + prependDotField ? dotField : undefined, + fieldCategory + ); +}; + +type DisjointFieldNames = 'ecs.version' | 'event.action' | 'event.kind' | 'event.original'; + +// Memoized field maps +const fieldMaps: EcsFieldMap & + Omit & + ExperimentalRuleFieldMap = { + ...technicalRuleFieldMap, + ...ecsFieldMap, + ...legacyExperimentalFieldMap, +}; + export const getDataFromFieldsHits = ( fields: Fields, prependField?: string, prependFieldCategory?: string -): TimelineEventsDetailsItem[] => - Object.keys(fields).reduce((accumulator, field) => { +): TimelineEventsDetailsItem[] => { + const resultMap = new Map(); + const fieldNames = Object.keys(fields); + for (let i = 0; i < fieldNames.length; i++) { + const field = fieldNames[i]; const item: unknown[] = fields[field]; - const fieldCategory = - prependFieldCategory != null ? prependFieldCategory : getFieldCategory(field); + const fieldCategory = prependFieldCategory ?? getFieldCategory(field); + const dotField = prependField ? `${prependField}.${field}` : field; + + // Handle geo fields if (isGeoField(field)) { - return [ - ...accumulator, - { - category: fieldCategory, - field, - values: formatGeoLocation(item), - originalValue: formatGeoLocation(item), - isObjectArray: true, // important for UI - }, - ]; + const geoItem = processGeoField(field, item, fieldCategory); + resultMap.set(field, geoItem); + // eslint-disable-next-line no-continue + continue; } + const objArrStr = toObjectArrayOfStrings(item); const strArr = objArrStr.map(({ str }) => str); const isObjectArray = objArrStr.some((o) => o.isObjectArray); - const dotField = prependField ? `${prependField}.${field}` : field; - // return simple field value (non-ecs object, non-array) - if ( - !isObjectArray || - (Object.keys({ - ...ecsFieldMap, - ...technicalRuleFieldMap, - ...legacyExperimentalFieldMap, - }).find((ecsField) => ecsField === field) === undefined && - !isRuleParametersFieldOrSubfield(field, prependField)) - ) { - return [ - ...accumulator, - { - category: fieldCategory, - field: dotField, - values: strArr, - originalValue: strArr, - isObjectArray, - }, - ]; + const isEcsField = fieldMaps[field as keyof typeof fieldMaps] !== undefined; + const isRuleParameters = isRuleParametersFieldOrSubfield(field, prependField); + + // Handle simple fields + if (!isObjectArray || (!isEcsField && !isRuleParameters)) { + const simpleItem = processSimpleField(dotField, strArr, isObjectArray, fieldCategory); + resultMap.set(dotField, simpleItem); + // eslint-disable-next-line no-continue + continue; } - const threatEnrichmentObject = isThreatEnrichmentFieldOrSubfield(field, prependField) - ? [ - { - category: fieldCategory, - field: dotField, - values: strArr, - originalValue: strArr, - isObjectArray, - }, - ] - : []; - - // format nested fields - let nestedFields: TimelineEventsDetailsItem[] = []; - if (isRuleParametersFieldOrSubfield(field, prependField)) { - nestedFields = Array.isArray(item) - ? item - .reduce((acc, curr) => { - acc.push(getDataFromFieldsHits(curr as Fields, dotField, fieldCategory)); - return acc; - }, []) - .flat() - : getDataFromFieldsHits(item, dotField, fieldCategory); - } else { - nestedFields = Array.isArray(item) - ? item - .reduce((acc, curr) => { - acc.push(getDataFromFieldsHits(curr as Fields, dotField, fieldCategory)); - return acc; - }, []) - .flat() - : getDataFromFieldsHits(item, prependField, fieldCategory); + // Handle threat enrichment + if (isThreatEnrichmentFieldOrSubfield(field, prependField)) { + const enrichmentItem = createFieldItem(fieldCategory, dotField, strArr, isObjectArray); + resultMap.set(dotField, enrichmentItem); } - // combine duplicate fields - const flat: Record = [ - ...accumulator, - ...nestedFields, - ...threatEnrichmentObject, - ].reduce( - (acc, f) => ({ - ...acc, - // acc/flat is hashmap to determine if we already have the field or not without an array iteration - // its converted back to array in return with Object.values - ...(acc[f.field] != null - ? { - [f.field]: { - ...f, - originalValue: acc[f.field].originalValue.includes(f.originalValue[0]) - ? acc[f.field].originalValue - : [...acc[f.field].originalValue, ...f.originalValue], - values: acc[f.field].values?.includes(f.values?.[0] || '') - ? acc[f.field].values - : [...(acc[f.field].values || []), ...(f.values || [])], - }, - } - : { [f.field]: f }), - }), - {} as Record + // Process nested fields + const nestedFields = processNestedFields( + item, + dotField, + fieldCategory, + isRuleParameters || isThreatEnrichmentFieldOrSubfield(field, prependField) ); + // Merge results + for (const nestedItem of nestedFields) { + const existing = resultMap.get(nestedItem.field); + + if (!existing) { + resultMap.set(nestedItem.field, nestedItem); + // eslint-disable-next-line no-continue + continue; + } - return Object.values(flat); - }, []); + // Merge values and originalValue arrays + const mergedValues = existing.values?.includes(nestedItem.values?.[0] || '') + ? existing.values + : [...(existing.values || []), ...(nestedItem.values || [])]; -export const getDataSafety = (fn: (args: A) => T, args: A): Promise => - new Promise((resolve) => setTimeout(() => resolve(fn(args)))); + const mergedOriginal = existing.originalValue.includes(nestedItem.originalValue[0]) + ? existing.originalValue + : [...existing.originalValue, ...nestedItem.originalValue]; + + resultMap.set(nestedItem.field, { + ...nestedItem, + values: mergedValues, + originalValue: mergedOriginal, + }); + } + } + + return Array.from(resultMap.values()); +}; diff --git a/x-pack/plugins/timelines/common/utils/index.ts b/x-pack/plugins/timelines/common/utils/index.ts new file mode 100644 index 000000000000..e4b7eefec454 --- /dev/null +++ b/x-pack/plugins/timelines/common/utils/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export { getDataFromFieldsHits, isGeoField } from './field_formatters'; +export { toArray, toObjectArrayOfStrings } from './to_array'; diff --git a/x-pack/plugins/timelines/common/utils/to_array.ts b/x-pack/plugins/timelines/common/utils/to_array.ts index fbb2b8d48a25..d13eb0578008 100644 --- a/x-pack/plugins/timelines/common/utils/to_array.ts +++ b/x-pack/plugins/timelines/common/utils/to_array.ts @@ -5,83 +5,55 @@ * 2.0. */ -export const toArray = (value: T | T[] | null): T[] => - Array.isArray(value) ? value : value == null ? [] : [value]; -export const toStringArray = (value: T | T[] | null): string[] => { - if (Array.isArray(value)) { - return value.reduce((acc, v) => { - if (v != null) { - switch (typeof v) { - case 'number': - case 'boolean': - return [...acc, v.toString()]; - case 'object': - try { - return [...acc, JSON.stringify(v)]; - } catch { - return [...acc, 'Invalid Object']; - } - case 'string': - return [...acc, v]; - default: - return [...acc, `${v}`]; - } +export const toArray = (value: T | T[] | null | undefined): T[] => + value == null ? [] : Array.isArray(value) ? value : [value]; + +export const toStringArray = (value: T | T[] | null): string[] => { + if (value == null) return []; + + const arr = Array.isArray(value) ? value : [value]; + return arr.reduce((acc, v) => { + if (v == null) return acc; + + if (typeof v === 'object') { + try { + acc.push(JSON.stringify(v)); + } catch { + acc.push('Invalid Object'); } return acc; - }, []); - } else if (value == null) { - return []; - } else if (!Array.isArray(value) && typeof value === 'object') { - try { - return [JSON.stringify(value)]; - } catch { - return ['Invalid Object']; } - } else { - return [`${value}`]; - } + + acc.push(String(v)); + return acc; + }, []); }; -export const toObjectArrayOfStrings = ( + +export const toObjectArrayOfStrings = ( value: T | T[] | null ): Array<{ str: string; isObjectArray?: boolean; }> => { - if (Array.isArray(value)) { - return value.reduce< - Array<{ - str: string; - isObjectArray?: boolean; - }> - >((acc, v) => { - if (v != null) { - switch (typeof v) { - case 'number': - case 'boolean': - return [...acc, { str: v.toString() }]; - case 'object': - try { - return [...acc, { str: JSON.stringify(v), isObjectArray: true }]; // need to track when string is not a simple value - } catch { - return [...acc, { str: 'Invalid Object' }]; - } - case 'string': - return [...acc, { str: v }]; - default: - return [...acc, { str: `${v}` }]; - } + if (value == null) return []; + + const arr = Array.isArray(value) ? value : [value]; + return arr.reduce>((acc, v) => { + if (v == null) return acc; + + if (typeof v === 'object') { + try { + acc.push({ + str: JSON.stringify(v), + isObjectArray: true, + }); + } catch { + acc.push({ str: 'Invalid Object' }); } return acc; - }, []); - } else if (value == null) { - return []; - } else if (!Array.isArray(value) && typeof value === 'object') { - try { - return [{ str: JSON.stringify(value), isObjectArray: true }]; - } catch { - return [{ str: 'Invalid Object' }]; } - } else { - return [{ str: `${value}` }]; - } + + acc.push({ str: String(v) }); + return acc; + }, []); }; diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts index 2b4f562954df..645f6daa5727 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/eql/helpers.ts @@ -17,7 +17,6 @@ import { } from '../../../../common/search_strategy'; import { TimelineEqlResponse } from '../../../../common/search_strategy/timeline/events/eql'; import { inspectStringifyObject } from '../../../utils/build_query'; -import { TIMELINE_EVENTS_FIELDS } from '../factory/helpers/constants'; import { formatTimelineData } from '../factory/helpers/format_timeline_data'; export const buildEqlDsl = (options: TimelineEqlRequestOptions): Record => { @@ -68,38 +67,38 @@ export const buildEqlDsl = (options: TimelineEqlRequestOptions): Record>, fieldRequested: string[]) => - sequences.reduce>(async (acc, sequence, sequenceIndex) => { +const parseSequences = async (sequences: Array>, fieldRequested: string[]) => { + let result: TimelineEdges[] = []; + + for (const [sequenceIndex, sequence] of sequences.entries()) { const sequenceParentId = sequence.events[0]?._id ?? null; - const data = await acc; - const allData = await Promise.all( - sequence.events.map(async (event, eventIndex) => { - const item = await formatTimelineData( - fieldRequested, - TIMELINE_EVENTS_FIELDS, - event as EventHit - ); - return Promise.resolve({ - ...item, - node: { - ...item.node, - ecs: { - ...item.node.ecs, - ...(sequenceParentId != null - ? { - eql: { - parentId: sequenceParentId, - sequenceNumber: `${sequenceIndex}-${eventIndex}`, - }, - } - : {}), - }, - }, - }); - }) + const formattedEvents = await formatTimelineData( + sequence.events as EventHit[], + fieldRequested, + false ); - return Promise.resolve([...data, ...allData]); - }, Promise.resolve([])); + + const eventsWithEql = formattedEvents.map((item, eventIndex) => ({ + ...item, + node: { + ...item.node, + ecs: { + ...item.node.ecs, + ...(sequenceParentId && { + eql: { + parentId: sequenceParentId, + sequenceNumber: `${sequenceIndex}-${eventIndex}`, + }, + }), + }, + }, + })); + + result = result.concat(eventsWithEql); + } + + return result; +}; export const parseEqlResponse = async ( options: TimelineEqlRequestOptions, @@ -116,10 +115,10 @@ export const parseEqlResponse = async ( if (response.rawResponse.hits.sequences !== undefined) { edges = await parseSequences(response.rawResponse.hits.sequences, options.fieldRequested); } else if (response.rawResponse.hits.events !== undefined) { - edges = await Promise.all( - response.rawResponse.hits.events.map(async (event) => - formatTimelineData(options.fieldRequested, TIMELINE_EVENTS_FIELDS, event as EventHit) - ) + edges = await formatTimelineData( + response.rawResponse.hits.events as EventHit[], + options.fieldRequested, + false ); } diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/all/index.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/all/index.ts index 4ed857b4885e..2ee2b64162c1 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/all/index.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/all/index.ts @@ -14,13 +14,11 @@ import { DEFAULT_MAX_TABLE_QUERY_SIZE } from '../../../../../../common/constants import { EventHit, TimelineEventsAllStrategyResponse, - TimelineEdges, } from '../../../../../../common/search_strategy'; import { TimelineFactory } from '../../types'; import { buildTimelineEventsAllQuery } from './query.events_all.dsl'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import { formatTimelineData } from '../../helpers/format_timeline_data'; -import { TIMELINE_EVENTS_FIELDS } from '../../helpers/constants'; export const timelineEventsAll: TimelineFactory = { buildDsl: ({ authFilter, ...options }) => { @@ -54,14 +52,10 @@ export const timelineEventsAll: TimelineFactory = { fieldRequested = [...new Set(fieldsReturned)]; } - const edges: TimelineEdges[] = await Promise.all( - hits.map((hit) => - formatTimelineData( - fieldRequested, - options.excludeEcsData ? [] : TIMELINE_EVENTS_FIELDS, - hit as EventHit - ) - ) + const edges = await formatTimelineData( + hits as EventHit[], + fieldRequested, + options.excludeEcsData ?? false ); const consumers = producerBuckets.reduce( diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/details/index.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/details/index.ts index 46edcf926d06..fcb90b73c241 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/details/index.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/events/details/index.ts @@ -12,15 +12,11 @@ import { TimelineEventsQueries } from '../../../../../../common/api/search_strat import { EventHit, TimelineEventsDetailsStrategyResponse, - TimelineEventsDetailsItem, } from '../../../../../../common/search_strategy'; import { inspectStringifyObject } from '../../../../../utils/build_query'; import { TimelineFactory } from '../../types'; import { buildTimelineDetailsQuery } from './query.events_details.dsl'; -import { - getDataFromFieldsHits, - getDataSafety, -} from '../../../../../../common/utils/field_formatters'; +import { getDataFromFieldsHits } from '../../../../../../common/utils/field_formatters'; import { buildEcsObjects } from '../../helpers/build_ecs_objects'; export const timelineEventsDetails: TimelineFactory = { @@ -57,10 +53,7 @@ export const timelineEventsDetails: TimelineFactory( - getDataFromFieldsHits, - merge(fields, hitsData) - ); + const fieldsData = getDataFromFieldsHits(merge(fields, hitsData)); const rawEventData = response.rawResponse.hits.hits[0]; const ecs = buildEcsObjects(rawEventData as EventHit); diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts index 5117f8dc889e..3e96494c8831 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.test.ts @@ -7,12 +7,12 @@ import { eventHit } from '@kbn/securitysolution-t-grid'; import { EventHit } from '../../../../../common/search_strategy'; -import { TIMELINE_EVENTS_FIELDS } from './constants'; import { formatTimelineData } from './format_timeline_data'; describe('formatTimelineData', () => { it('should properly format the timeline data', async () => { const res = await formatTimelineData( + [eventHit], [ '@timestamp', 'host.name', @@ -21,187 +21,188 @@ describe('formatTimelineData', () => { 'source.geo.location', 'threat.enrichments.matched.field', ], - TIMELINE_EVENTS_FIELDS, - eventHit + false ); - expect(res).toEqual({ - cursor: { - tiebreaker: 'beats-ci-immutable-ubuntu-1804-1605624279743236239', - value: '1605624488922', - }, - node: { - _id: 'tkCt1nUBaEgqnrVSZ8R_', - _index: 'auditbeat-7.8.0-2020.11.05-000003', - data: [ - { - field: '@timestamp', - value: ['2020-11-17T14:48:08.922Z'], - }, - { - field: 'host.name', - value: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], - }, - { - field: 'threat.enrichments.matched.field', - value: [ - 'matched_field', - 'other_matched_field', - 'matched_field_2', - 'host.name', - 'host.hostname', - 'host.architecture', - ], - }, - { - field: 'source.geo.location', - value: [`{"lon":118.7778,"lat":32.0617}`], - }, - ], - ecs: { - '@timestamp': ['2020-11-17T14:48:08.922Z'], + expect(res).toEqual([ + { + cursor: { + tiebreaker: 'beats-ci-immutable-ubuntu-1804-1605624279743236239', + value: '1605624488922', + }, + node: { _id: 'tkCt1nUBaEgqnrVSZ8R_', _index: 'auditbeat-7.8.0-2020.11.05-000003', - agent: { - type: ['auditbeat'], - }, - event: { - action: ['process_started'], - category: ['process'], - dataset: ['process'], - kind: ['event'], - module: ['system'], - type: ['start'], - }, - host: { - id: ['e59991e835905c65ed3e455b33e13bd6'], - ip: ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], - name: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], - os: { - family: ['debian'], + data: [ + { + field: '@timestamp', + value: ['2020-11-17T14:48:08.922Z'], }, - }, - message: ['Process go (PID: 4313) by user jenkins STARTED'], - process: { - args: ['go', 'vet', './...'], - entity_id: ['Z59cIkAAIw8ZoK0H'], - executable: [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', - ], - hash: { - sha1: ['1eac22336a41e0660fb302add9d97daa2bcc7040'], - }, - name: ['go'], - pid: ['4313'], - ppid: ['3977'], - working_directory: [ - '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', - ], - }, - timestamp: '2020-11-17T14:48:08.922Z', - user: { - name: ['jenkins'], - }, - threat: { - enrichments: [ - { - feed: { name: [] }, - indicator: { - provider: ['yourself'], - reference: [], - }, - matched: { - atomic: ['matched_atomic'], - field: ['matched_field', 'other_matched_field'], - type: [], - }, - }, - { - feed: { name: [] }, - indicator: { - provider: ['other_you'], - reference: [], - }, - matched: { - atomic: ['matched_atomic_2'], - field: ['matched_field_2'], - type: [], - }, - }, - { - feed: { - name: [], - }, - indicator: { - provider: [], - reference: [], - }, - matched: { - atomic: ['MacBook-Pro-de-Gloria.local'], - field: ['host.name'], - type: ['indicator_match_rule'], - }, + { + field: 'host.name', + value: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], + }, + { + field: 'threat.enrichments.matched.field', + value: [ + 'matched_field', + 'other_matched_field', + 'matched_field_2', + 'host.name', + 'host.hostname', + 'host.architecture', + ], + }, + { + field: 'source.geo.location', + value: [`{"lon":118.7778,"lat":32.0617}`], + }, + ], + ecs: { + '@timestamp': ['2020-11-17T14:48:08.922Z'], + _id: 'tkCt1nUBaEgqnrVSZ8R_', + _index: 'auditbeat-7.8.0-2020.11.05-000003', + agent: { + type: ['auditbeat'], + }, + event: { + action: ['process_started'], + category: ['process'], + dataset: ['process'], + kind: ['event'], + module: ['system'], + type: ['start'], + }, + host: { + id: ['e59991e835905c65ed3e455b33e13bd6'], + ip: ['10.224.1.237', 'fe80::4001:aff:fee0:1ed', '172.17.0.1'], + name: ['beats-ci-immutable-ubuntu-1804-1605624279743236239'], + os: { + family: ['debian'], }, - { - feed: { - name: [], - }, - indicator: { - provider: [], - reference: [], - }, - matched: { - atomic: ['MacBook-Pro-de-Gloria.local'], - field: ['host.hostname'], - type: ['indicator_match_rule'], - }, + }, + message: ['Process go (PID: 4313) by user jenkins STARTED'], + process: { + args: ['go', 'vet', './...'], + entity_id: ['Z59cIkAAIw8ZoK0H'], + executable: [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/.gvm/versions/go1.14.7.linux.amd64/bin/go', + ], + hash: { + sha1: ['1eac22336a41e0660fb302add9d97daa2bcc7040'], }, - { - feed: { - name: [], - }, - indicator: { - provider: [], - reference: [], + name: ['go'], + pid: ['4313'], + ppid: ['3977'], + working_directory: [ + '/var/lib/jenkins/workspace/Beats_beats_PR-22624/src/github.com/elastic/beats/libbeat', + ], + }, + timestamp: '2020-11-17T14:48:08.922Z', + user: { + name: ['jenkins'], + }, + threat: { + enrichments: [ + { + feed: { name: [] }, + indicator: { + provider: ['yourself'], + reference: [], + }, + matched: { + atomic: ['matched_atomic'], + field: ['matched_field', 'other_matched_field'], + type: [], + }, }, - matched: { - atomic: ['x86_64'], - field: ['host.architecture'], - type: ['indicator_match_rule'], + { + feed: { name: [] }, + indicator: { + provider: ['other_you'], + reference: [], + }, + matched: { + atomic: ['matched_atomic_2'], + field: ['matched_field_2'], + type: [], + }, }, - }, - { - feed: { - name: [], + { + feed: { + name: [], + }, + indicator: { + provider: [], + reference: [], + }, + matched: { + atomic: ['MacBook-Pro-de-Gloria.local'], + field: ['host.name'], + type: ['indicator_match_rule'], + }, }, - indicator: { - provider: [], - reference: [], + { + feed: { + name: [], + }, + indicator: { + provider: [], + reference: [], + }, + matched: { + atomic: ['MacBook-Pro-de-Gloria.local'], + field: ['host.hostname'], + type: ['indicator_match_rule'], + }, }, - matched: { - atomic: ['MacBook-Pro-de-Gloria.local'], - field: ['host.name'], - type: ['indicator_match_rule'], + { + feed: { + name: [], + }, + indicator: { + provider: [], + reference: [], + }, + matched: { + atomic: ['x86_64'], + field: ['host.architecture'], + type: ['indicator_match_rule'], + }, }, - }, - { - feed: { - name: [], + { + feed: { + name: [], + }, + indicator: { + provider: [], + reference: [], + }, + matched: { + atomic: ['MacBook-Pro-de-Gloria.local'], + field: ['host.name'], + type: ['indicator_match_rule'], + }, }, - indicator: { - provider: [], - reference: [], + { + feed: { + name: [], + }, + indicator: { + provider: [], + reference: [], + }, + matched: { + atomic: ['MacBook-Pro-de-Gloria.local'], + field: ['host.hostname'], + type: ['indicator_match_rule'], + }, }, - matched: { - atomic: ['MacBook-Pro-de-Gloria.local'], - field: ['host.hostname'], - type: ['indicator_match_rule'], - }, - }, - ], + ], + }, }, }, }, - }); + ]); }); it('should properly format the rule signal results', async () => { @@ -240,57 +241,61 @@ describe('formatTimelineData', () => { expect( await formatTimelineData( + [response], ['@timestamp', 'host.name', 'destination.ip', 'source.ip'], - TIMELINE_EVENTS_FIELDS, - response + false ) - ).toEqual({ - cursor: { - tiebreaker: null, - value: '', - }, - node: { - _id: 'a77040f198355793c35bf22b900902371309be615381f0a2ec92c208b6132562', - _index: '.siem-signals-patrykkopycinski-default-000007', - data: [ - { - field: '@timestamp', - value: ['2021-01-09T13:41:40.517Z'], - }, - ], - ecs: { - '@timestamp': ['2021-01-09T13:41:40.517Z'], - timestamp: '2021-01-09T13:41:40.517Z', + ).toEqual([ + { + cursor: { + tiebreaker: null, + value: '', + }, + node: { _id: 'a77040f198355793c35bf22b900902371309be615381f0a2ec92c208b6132562', _index: '.siem-signals-patrykkopycinski-default-000007', - event: { - kind: ['signal'], - }, - kibana: { - alert: { - original_time: ['2021-01-09T13:39:32.595Z'], - workflow_status: ['open'], - threshold_result: ['{"count":10000,"value":"2a990c11-f61b-4c8e-b210-da2574e9f9db"}'], - severity: ['low'], - risk_score: ['21'], - rule: { - building_block_type: [], - exceptions_list: [], - from: ['now-360s'], - uuid: ['696c24e0-526d-11eb-836c-e1620268b945'], - name: ['Threshold test'], - to: ['now'], - type: ['threshold'], - version: ['1'], - timeline_id: [], - timeline_title: [], - note: [], + data: [ + { + field: '@timestamp', + value: ['2021-01-09T13:41:40.517Z'], + }, + ], + ecs: { + '@timestamp': ['2021-01-09T13:41:40.517Z'], + timestamp: '2021-01-09T13:41:40.517Z', + _id: 'a77040f198355793c35bf22b900902371309be615381f0a2ec92c208b6132562', + _index: '.siem-signals-patrykkopycinski-default-000007', + event: { + kind: ['signal'], + }, + kibana: { + alert: { + original_time: ['2021-01-09T13:39:32.595Z'], + workflow_status: ['open'], + threshold_result: [ + '{"count":10000,"value":"2a990c11-f61b-4c8e-b210-da2574e9f9db"}', + ], + severity: ['low'], + risk_score: ['21'], + rule: { + building_block_type: [], + exceptions_list: [], + from: ['now-360s'], + uuid: ['696c24e0-526d-11eb-836c-e1620268b945'], + name: ['Threshold test'], + to: ['now'], + type: ['threshold'], + version: ['1'], + timeline_id: [], + timeline_title: [], + note: [], + }, }, }, }, }, }, - }); + ]); }); it('should properly format the inventory rule signal results', async () => { @@ -347,6 +352,7 @@ describe('formatTimelineData', () => { expect( await formatTimelineData( + [response], [ 'kibana.alert.status', '@timestamp', @@ -376,168 +382,169 @@ describe('formatTimelineData', () => { 'event.kind', 'kibana.alert.rule.parameters', ], - TIMELINE_EVENTS_FIELDS, - response + false ) - ).toEqual({ - cursor: { - tiebreaker: null, - value: '', - }, - node: { - _id: '3fef4a4c-3d96-4e79-b4e5-158a0461d577', - _index: '.internal.alerts-observability.metrics.alerts-default-000001', - data: [ - { - field: 'kibana.alert.rule.consumer', - value: ['infrastructure'], - }, - { - field: '@timestamp', - value: ['2022-07-21T22:38:57.888Z'], - }, - { - field: 'kibana.alert.workflow_status', - value: ['open'], - }, - { - field: 'kibana.alert.reason', - value: [ - 'CPU usage is 37.8% in the last 1 day for gke-edge-oblt-pool-1-9a60016d-7dvq. Alert when > 10%.', - ], - }, - { - field: 'kibana.alert.rule.name', - value: ['test 1212'], - }, - { - field: 'kibana.alert.rule.uuid', - value: ['15d82f10-0926-11ed-bece-6b0c033d0075'], - }, - { - field: 'kibana.alert.rule.parameters.sourceId', - value: ['default'], - }, - { - field: 'kibana.alert.rule.parameters.nodeType', - value: ['host'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.comparator', - value: ['>'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.timeSize', - value: ['1'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.metric', - value: ['cpu'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.threshold', - value: ['10'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.customMetric.aggregation', - value: ['avg'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.customMetric.id', - value: ['alert-custom-metric'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.customMetric.field', - value: [''], - }, - { - field: 'kibana.alert.rule.parameters.criteria.customMetric.type', - value: ['custom'], - }, - { - field: 'kibana.alert.rule.parameters.criteria.timeUnit', - value: ['d'], - }, - { - field: 'event.action', - value: ['active'], - }, - { - field: 'event.kind', - value: ['signal'], - }, - { - field: 'kibana.alert.status', - value: ['active'], - }, - { - field: 'kibana.alert.duration.us', - value: ['9502040000'], - }, - { - field: 'kibana.alert.rule.category', - value: ['Inventory'], - }, - { - field: 'kibana.alert.uuid', - value: ['3fef4a4c-3d96-4e79-b4e5-158a0461d577'], - }, - { - field: 'kibana.alert.start', - value: ['2022-07-21T20:00:35.848Z'], - }, - { - field: 'kibana.alert.rule.producer', - value: ['infrastructure'], - }, - { - field: 'kibana.alert.rule.rule_type_id', - value: ['metrics.alert.inventory.threshold'], - }, - { - field: 'kibana.alert.instance.id', - value: ['gke-edge-oblt-pool-1-9a60016d-7dvq'], - }, - { - field: 'kibana.alert.rule.execution.uuid', - value: ['37498c42-0190-4a83-adfa-c7e5f817f977'], - }, - { - field: 'kibana.space_ids', - value: ['default'], - }, - { - field: 'kibana.version', - value: ['8.4.0'], - }, - ], - ecs: { - '@timestamp': ['2022-07-21T22:38:57.888Z'], + ).toEqual([ + { + cursor: { + tiebreaker: null, + value: '', + }, + node: { _id: '3fef4a4c-3d96-4e79-b4e5-158a0461d577', _index: '.internal.alerts-observability.metrics.alerts-default-000001', - event: { - action: ['active'], - kind: ['signal'], - }, - kibana: { - alert: { - reason: [ + data: [ + { + field: 'kibana.alert.rule.consumer', + value: ['infrastructure'], + }, + { + field: '@timestamp', + value: ['2022-07-21T22:38:57.888Z'], + }, + { + field: 'kibana.alert.workflow_status', + value: ['open'], + }, + { + field: 'kibana.alert.reason', + value: [ 'CPU usage is 37.8% in the last 1 day for gke-edge-oblt-pool-1-9a60016d-7dvq. Alert when > 10%.', ], - rule: { - consumer: ['infrastructure'], - name: ['test 1212'], - uuid: ['15d82f10-0926-11ed-bece-6b0c033d0075'], - parameters: [ - '{"sourceId":"default","nodeType":"host","criteria":[{"comparator":">","timeSize":1,"metric":"cpu","threshold":[10],"customMetric":{"aggregation":"avg","id":"alert-custom-metric","field":"","type":"custom"},"timeUnit":"d"}]}', + }, + { + field: 'kibana.alert.rule.name', + value: ['test 1212'], + }, + { + field: 'kibana.alert.rule.uuid', + value: ['15d82f10-0926-11ed-bece-6b0c033d0075'], + }, + { + field: 'kibana.alert.rule.parameters.sourceId', + value: ['default'], + }, + { + field: 'kibana.alert.rule.parameters.nodeType', + value: ['host'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.comparator', + value: ['>'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.timeSize', + value: ['1'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.metric', + value: ['cpu'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.threshold', + value: ['10'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.customMetric.aggregation', + value: ['avg'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.customMetric.id', + value: ['alert-custom-metric'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.customMetric.field', + value: [''], + }, + { + field: 'kibana.alert.rule.parameters.criteria.customMetric.type', + value: ['custom'], + }, + { + field: 'kibana.alert.rule.parameters.criteria.timeUnit', + value: ['d'], + }, + { + field: 'event.action', + value: ['active'], + }, + { + field: 'event.kind', + value: ['signal'], + }, + { + field: 'kibana.alert.status', + value: ['active'], + }, + { + field: 'kibana.alert.duration.us', + value: ['9502040000'], + }, + { + field: 'kibana.alert.rule.category', + value: ['Inventory'], + }, + { + field: 'kibana.alert.uuid', + value: ['3fef4a4c-3d96-4e79-b4e5-158a0461d577'], + }, + { + field: 'kibana.alert.start', + value: ['2022-07-21T20:00:35.848Z'], + }, + { + field: 'kibana.alert.rule.producer', + value: ['infrastructure'], + }, + { + field: 'kibana.alert.rule.rule_type_id', + value: ['metrics.alert.inventory.threshold'], + }, + { + field: 'kibana.alert.instance.id', + value: ['gke-edge-oblt-pool-1-9a60016d-7dvq'], + }, + { + field: 'kibana.alert.rule.execution.uuid', + value: ['37498c42-0190-4a83-adfa-c7e5f817f977'], + }, + { + field: 'kibana.space_ids', + value: ['default'], + }, + { + field: 'kibana.version', + value: ['8.4.0'], + }, + ], + ecs: { + '@timestamp': ['2022-07-21T22:38:57.888Z'], + _id: '3fef4a4c-3d96-4e79-b4e5-158a0461d577', + _index: '.internal.alerts-observability.metrics.alerts-default-000001', + event: { + action: ['active'], + kind: ['signal'], + }, + kibana: { + alert: { + reason: [ + 'CPU usage is 37.8% in the last 1 day for gke-edge-oblt-pool-1-9a60016d-7dvq. Alert when > 10%.', ], + rule: { + consumer: ['infrastructure'], + name: ['test 1212'], + uuid: ['15d82f10-0926-11ed-bece-6b0c033d0075'], + parameters: [ + '{"sourceId":"default","nodeType":"host","criteria":[{"comparator":">","timeSize":1,"metric":"cpu","threshold":[10],"customMetric":{"aggregation":"avg","id":"alert-custom-metric","field":"","type":"custom"},"timeUnit":"d"}]}', + ], + }, + workflow_status: ['open'], }, - workflow_status: ['open'], }, + timestamp: '2022-07-21T22:38:57.888Z', }, - timestamp: '2022-07-21T22:38:57.888Z', }, }, - }); + ]); }); }); diff --git a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.ts b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.ts index f56cfd32391d..3b83bb087398 100644 --- a/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.ts +++ b/x-pack/plugins/timelines/server/search_strategy/timeline/factory/helpers/format_timeline_data.ts @@ -5,118 +5,137 @@ * 2.0. */ -import { get, has, merge, uniq } from 'lodash/fp'; -import { EventHit, TimelineEdges, TimelineNonEcsData } from '../../../../../common/search_strategy'; +import { get, has } from 'lodash/fp'; +import { + EventHit, + TimelineEdges, + TimelineNonEcsData, + EventSource, +} from '../../../../../common/search_strategy'; import { toStringArray } from '../../../../../common/utils/to_array'; -import { getDataFromFieldsHits, getDataSafety } from '../../../../../common/utils/field_formatters'; +import { getDataFromFieldsHits } from '../../../../../common/utils/field_formatters'; import { getTimestamp } from './get_timestamp'; import { getNestedParentPath } from './get_nested_parent_path'; import { buildObjectRecursive } from './build_object_recursive'; -import { ECS_METADATA_FIELDS } from './constants'; +import { ECS_METADATA_FIELDS, TIMELINE_EVENTS_FIELDS } from './constants'; -export const formatTimelineData = async ( - dataFields: readonly string[], - ecsFields: readonly string[], - hit: EventHit -) => - uniq([...ecsFields, ...dataFields]).reduce>( - async (acc, fieldName) => { - const flattenedFields: TimelineEdges = await acc; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - flattenedFields.node._id = hit._id!; - flattenedFields.node._index = hit._index; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - flattenedFields.node.ecs._id = hit._id!; - flattenedFields.node.ecs.timestamp = getTimestamp(hit); - flattenedFields.node.ecs._index = hit._index; - if (hit.sort && hit.sort.length > 1) { - flattenedFields.cursor.value = hit.sort[0]; - flattenedFields.cursor.tiebreaker = hit.sort[1]; - } - const waitForIt = await mergeTimelineFieldsWithHit( - fieldName, - flattenedFields, - hit, - dataFields, - ecsFields - ); - return Promise.resolve(waitForIt); - }, - Promise.resolve({ - node: { ecs: { _id: '' }, data: [], _id: '', _index: '' }, - cursor: { - value: '', - tiebreaker: null, - }, - }) - ); - -const getValuesFromFields = async ( +const createBaseTimelineEdges = (): TimelineEdges => ({ + node: { + ecs: { _id: '' }, + data: [], + _id: '', + _index: '', + }, + cursor: { + value: '', + tiebreaker: null, + }, +}); + +function deepMerge(target: EventSource, source: EventSource) { + for (const key in source) { + if ( + !Object.prototype.hasOwnProperty.call(source, key) || + key === '__proto__' || + key === 'constructor' + ) + // eslint-disable-next-line no-continue + continue; + if (source[key] instanceof Object && target[key] instanceof Object) { + deepMerge(target[key], source[key]); + } else { + target[key] = source[key]; + } + } + return target; +} + +const processMetadataField = (fieldName: string, hit: EventHit): TimelineNonEcsData[] => [ + { + field: fieldName, + value: toStringArray(get(fieldName, hit)), + }, +]; + +const processFieldData = ( fieldName: string, hit: EventHit, nestedParentFieldName?: string -): Promise => { - if (ECS_METADATA_FIELDS.includes(fieldName)) { - return [{ field: fieldName, value: toStringArray(get(fieldName, hit)) }]; - } +): TimelineNonEcsData[] => { + const fieldToEval = nestedParentFieldName + ? { [nestedParentFieldName]: hit.fields[nestedParentFieldName] } + : { [fieldName]: hit.fields[fieldName] }; - let fieldToEval; - - if (nestedParentFieldName == null) { - fieldToEval = { - [fieldName]: hit.fields[fieldName], - }; - } else { - fieldToEval = { - [nestedParentFieldName]: hit.fields[nestedParentFieldName], - }; - } - const formattedData = await getDataSafety(getDataFromFieldsHits, fieldToEval); - return formattedData.reduce((acc: TimelineNonEcsData[], { field, values }) => { - // nested fields return all field values, pick only the one we asked for + const formattedData = getDataFromFieldsHits(fieldToEval); + const fieldsData: TimelineNonEcsData[] = []; + return formattedData.reduce((agg, { field, values }) => { if (field.includes(fieldName)) { - acc.push({ field, value: values }); + agg.push({ + field, + value: values, + }); } - return acc; - }, []); + return agg; + }, fieldsData); }; -const mergeTimelineFieldsWithHit = async ( - fieldName: string, - flattenedFields: T, - hit: EventHit, - dataFields: readonly string[], - ecsFields: readonly string[] -) => { - if (fieldName != null) { - const nestedParentPath = getNestedParentPath(fieldName, hit.fields); - if ( - nestedParentPath != null || - has(fieldName, hit.fields) || - ECS_METADATA_FIELDS.includes(fieldName) - ) { - const objectWithProperty = { - node: { - ...get('node', flattenedFields), - data: dataFields.includes(fieldName) - ? [ - ...get('node.data', flattenedFields), - ...(await getValuesFromFields(fieldName, hit, nestedParentPath)), - ] - : get('node.data', flattenedFields), - ecs: ecsFields.includes(fieldName) - ? { - ...get('node.ecs', flattenedFields), - ...buildObjectRecursive(fieldName, hit.fields), - } - : get('node.ecs', flattenedFields), - }, - }; - return merge(flattenedFields, objectWithProperty); +export const formatTimelineData = async ( + hits: EventHit[], + fieldRequested: readonly string[], + excludeEcsData: boolean +): Promise => { + const ecsFields = excludeEcsData ? [] : TIMELINE_EVENTS_FIELDS; + + const uniqueFields = new Set([...ecsFields, ...fieldRequested]); + const dataFieldSet = new Set(fieldRequested); + const ecsFieldSet = new Set(ecsFields); + + const results: TimelineEdges[] = new Array(hits.length); + + for (let i = 0; i < hits.length; i++) { + const hit = hits[i]; + if (hit._id) { + const result = createBaseTimelineEdges(); + + result.node._id = hit._id; + result.node._index = hit._index; + result.node.ecs._id = hit._id; + result.node.ecs.timestamp = getTimestamp(hit); + result.node.ecs._index = hit._index; + + if (hit.sort?.length > 1) { + result.cursor.value = hit.sort[0]; + result.cursor.tiebreaker = hit.sort[1]; + } + + result.node.data = []; + + for (const fieldName of uniqueFields) { + const nestedParentPath = getNestedParentPath(fieldName, hit.fields); + const isEcs = ECS_METADATA_FIELDS.includes(fieldName); + if (!nestedParentPath && !has(fieldName, hit.fields) && !isEcs) { + // eslint-disable-next-line no-continue + continue; + } + + if (dataFieldSet.has(fieldName)) { + const values = isEcs + ? processMetadataField(fieldName, hit) + : processFieldData(fieldName, hit, nestedParentPath); + + result.node.data.push(...values); + } + + if (ecsFieldSet.has(fieldName)) { + deepMerge(result.node.ecs, buildObjectRecursive(fieldName, hit.fields)); + } + } + + results[i] = result; } else { - return flattenedFields; + results[i] = createBaseTimelineEdges(); } - } else { - return flattenedFields; } + + return results; }; diff --git a/x-pack/plugins/timelines/server/types.ts b/x-pack/plugins/timelines/server/types.ts index 311281f67ea2..b412b69be973 100644 --- a/x-pack/plugins/timelines/server/types.ts +++ b/x-pack/plugins/timelines/server/types.ts @@ -6,7 +6,7 @@ */ import type { PluginSetup, PluginStart } from '@kbn/data-plugin/server'; -import { PluginStartContract as AlertingPluginStartContract } from '@kbn/alerting-plugin/server'; +import { AlertingServerStart } from '@kbn/alerting-plugin/server'; import { SecurityPluginSetup } from '@kbn/security-plugin/server'; // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -21,5 +21,5 @@ export interface SetupPlugins { export interface StartPlugins { data: PluginStart; - alerting: AlertingPluginStartContract; + alerting: AlertingServerStart; } diff --git a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts index ac04ff6a7662..1fe9c3cc5933 100644 --- a/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts +++ b/x-pack/plugins/transform/server/lib/alerting/transform_health_rule_type/register_transform_health_rule_type.ts @@ -16,11 +16,7 @@ import type { RuleTypeState, } from '@kbn/alerting-plugin/common'; import { AlertsClientError } from '@kbn/alerting-plugin/server'; -import type { - PluginSetupContract as AlertingSetup, - IRuleTypeAlerts, - RuleType, -} from '@kbn/alerting-plugin/server'; +import type { AlertingServerSetup, IRuleTypeAlerts, RuleType } from '@kbn/alerting-plugin/server'; import type { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { TransformHealthAlert } from '@kbn/alerts-as-data-utils'; import { ALERT_REASON } from '@kbn/rule-data-utils'; @@ -74,7 +70,7 @@ export const TRANSFORM_ISSUE_DETECTED: ActionGroup = { interface RegisterParams { logger: Logger; - alerting: AlertingSetup; + alerting: AlertingServerSetup; getFieldFormatsStart: () => FieldFormatsStart; } diff --git a/x-pack/plugins/transform/server/routes/api/transforms_all/route_handler.ts b/x-pack/plugins/transform/server/routes/api/transforms_all/route_handler.ts index 8bbedd9faa02..4bf9a03b6488 100644 --- a/x-pack/plugins/transform/server/routes/api/transforms_all/route_handler.ts +++ b/x-pack/plugins/transform/server/routes/api/transforms_all/route_handler.ts @@ -28,10 +28,13 @@ export const routeHandler: RequestHandler< }); const alerting = await ctx.alerting; + if (alerting) { + const rulesClient = await alerting.getRulesClient(); + const transformHealthService = transformHealthServiceProvider({ esClient: esClient.asCurrentUser, - rulesClient: alerting.getRulesClient(), + rulesClient, }); // @ts-ignore diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index ada6529e8d32..c7a1ebde48ed 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -191,14 +191,8 @@ "alertsUIShared.healthCheck.encryptionErrorTitle": "Configuration supplémentaire requise", "alertsUIShared.healthCheck.healthCheck.apiKeysAndEncryptionErrorTitle": "Configuration supplémentaire requise", "alertsUIShared.hooks.useAlertDataView.fetchErrorMessage": "Impossible de charger la vue des données de l'alerte", - "alertsUIShared.hooks.useFindAlertsQuery.unableToFetchAlertsGroupingAggregations": "Impossible de récupérer les agrégations de groupement d'alertes", "alertsUIShared.hooks.useFindAlertsQuery.unableToFindAlertsQueryMessage": "Impossible de trouver les alertes", "alertsUIShared.hooks.useLoadRuleTypesQuery.unableToLoadRuleTypesMessage": "Impossible de charger les types de règles", - "alertsUIShared.hooks.useRuleAADFields.errorMessage": "Impossible de charger les champs d'alerte par type de règle", - "alertsUIShared.licenseCheck.actionTypeDisabledByConfigMessageTitle": "Cette fonctionnalité est désactivée par la configuration de Kibana.", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseLinkTitle": "Afficher les options de licence", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageDescription": "Pour réactiver cette action, veuillez mettre à niveau votre licence.", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageTitle": "Cette fonctionnalité requiert une licence {minimumLicenseRequired}.", "alertsUIShared.maintenanceWindowCallout.fetchError": "La vérification visant à déterminer si les fenêtres de maintenance sont actives a échoué", "alertsUIShared.maintenanceWindowCallout.fetchErrorDescription": "Les notifications de règle sont arrêtées lorsque les fenêtres de maintenance sont en cours d'exécution.", "alertsUIShared.maintenanceWindowCallout.maintenanceWindowActive": "{activeWindowCount, plural, one {Une fenêtre de maintenance est} other {Des fenêtres de maintenance sont}} en cours d'exécution pour des règles de {categories}", @@ -2734,11 +2728,7 @@ "discover.advancedSettings.context.tieBreakerFieldsTitle": "Champs de départage", "discover.advancedSettings.defaultColumnsText": "Les colonnes affichées par défaut dans l'application Discover. Si elles sont vides, un résumé du document s’affiche.", "discover.advancedSettings.defaultColumnsTitle": "Colonnes par défaut", - "discover.advancedSettings.disableDocumentExplorer": "Explorateur de documents ou vue classique", - "discover.advancedSettings.disableDocumentExplorerDescription": "Désactivez cette option pour utiliser le nouveau {documentExplorerDocs} au lieu de la vue classique. l'explorateur de documents offre un meilleur tri des données, des colonnes redimensionnables et une vue en plein écran.", - "discover.advancedSettings.discover.disableDocumentExplorerDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", "discover.advancedSettings.discover.fieldStatisticsLinkText": "Vue des statistiques de champ", - "discover.advancedSettings.discover.maxCellHeightDeprecation": "Ce paramètre est déclassé et sera supprimé dans la version 9.0 de Kibana.", "discover.advancedSettings.discover.modifyColumnsOnSwitchText": "Supprimez les colonnes qui ne sont pas disponibles dans la nouvelle vue de données.", "discover.advancedSettings.discover.modifyColumnsOnSwitchTitle": "Modifier les colonnes en cas de changement des vues de données", "discover.advancedSettings.discover.multiFieldsLinkText": "champs multiples", @@ -2751,13 +2741,10 @@ "discover.advancedSettings.discover.showMultifieldsDescription": "Détermine si les {multiFields} doivent s'afficher dans la fenêtre de document étendue. Dans la plupart des cas, les champs multiples sont les mêmes que les champs d'origine. Cette option est uniquement disponible lorsque le paramètre `searchFieldsFromSource` est désactivé.", "discover.advancedSettings.docTableHideTimeColumnText": "Permet de masquer la colonne ''Time'' dans Discover et dans toutes les recherches enregistrées des tableaux de bord.", "discover.advancedSettings.docTableHideTimeColumnTitle": "Masquer la colonne ''Time''", - "discover.advancedSettings.documentExplorerLinkText": "Explorateur de documents", "discover.advancedSettings.fieldsPopularLimitText": "Les N champs les plus populaires à afficher", "discover.advancedSettings.fieldsPopularLimitTitle": "Limite de champs populaires", "discover.advancedSettings.maxDocFieldsDisplayedText": "Le nombre maximal de champs renvoyés dans le résumé du document", "discover.advancedSettings.maxDocFieldsDisplayedTitle": "Nombre maximal de champs de document affichés", - "discover.advancedSettings.params.maxCellHeightText": "La hauteur maximale qu'une cellule de tableau peut atteindre. Définissez ce paramètre sur 0 pour désactiver la troncation.", - "discover.advancedSettings.params.maxCellHeightTitle": "Hauteur de cellule maximale dans le tableau classique", "discover.advancedSettings.params.rowHeightText": "Nombre de sous-lignes à autoriser dans une ligne. La valeur -1 ajuste automatiquement la hauteur de ligne selon le contenu. La valeur 0 affiche le contenu en une seule ligne.", "discover.advancedSettings.params.rowHeightTitle": "Hauteur de ligne dans l'explorateur de documents", "discover.advancedSettings.sampleRowsPerPageText": "Limite le nombre de lignes par page dans le tableau de documents.", @@ -2773,7 +2760,6 @@ "discover.alerts.createSearchThreshold": "Créer une règle de seuil de recherche", "discover.alerts.manageRulesAndConnectors": "Gérer les règles et les connecteurs", "discover.alerts.missedTimeFieldToolTip": "La vue de données ne possède pas de champ temporel.", - "discover.backToTopLinkText": "Revenir en haut de la page.", "discover.badge.readOnly.text": "Lecture seule", "discover.badge.readOnly.tooltip": "Impossible d’enregistrer les recherches", "discover.context.breadcrumb": "Documents relatifs", @@ -2782,7 +2768,6 @@ "discover.context.failedToLoadAnchorDocumentErrorDescription": "Le document ancré n’a pas pu être chargé.", "discover.context.invalidTieBreakerFiledSetting": "Paramètre de champ de départage non valide", "discover.context.loadButtonLabel": "Charger", - "discover.context.loadingDescription": "Chargement...", "discover.context.newerDocumentsAriaLabel": "Nombre de documents plus récents", "discover.context.newerDocumentsDescription": "documents plus récents", "discover.context.newerDocumentsWarning": "Seuls {docCount} documents plus récents que le document ancré ont été trouvés.", @@ -2819,39 +2804,8 @@ "discover.doc.pageTitle": "Document unique - #{id}", "discover.doc.somethingWentWrongDescription": "Index {indexName} manquant.", "discover.doc.somethingWentWrongDescriptionAddon": "Veuillez vérifier que cet index existe.", - "discover.docExplorerCallout.closeButtonAriaLabel": "Fermer", - "discover.docExplorerCallout.documentExplorer": "Explorateur de documents", - "discover.docExplorerCallout.headerMessage": "Une meilleure façon d'explorer", - "discover.docExplorerCallout.learnMore": "En savoir plus", - "discover.docExplorerCallout.tryDocumentExplorer": "Testez l'explorateur de documents", - "discover.docTable.documentsNavigation": "Navigation dans les documents", - "discover.docTable.limitedSearchResultLabel": "Limité à {resultCount} résultats. Veuillez affiner votre recherche.", - "discover.docTable.noResultsTitle": "Résultat introuvable", - "discover.docTable.rows": "lignes", - "discover.docTable.rowsPerPage": "Lignes par page : {pageSize}", - "discover.docTable.tableHeader.documentHeader": "Document", - "discover.docTable.tableHeader.moveColumnLeftButtonAriaLabel": "Déplacer la colonne {columnName} vers la gauche", - "discover.docTable.tableHeader.moveColumnLeftButtonTooltip": "Déplacer la colonne vers la gauche", - "discover.docTable.tableHeader.moveColumnRightButtonAriaLabel": "Déplacer la colonne {columnName} vers la droite", - "discover.docTable.tableHeader.moveColumnRightButtonTooltip": "Déplacer la colonne vers la droite", - "discover.docTable.tableHeader.removeColumnButtonAriaLabel": "Supprimer la colonne {columnName}", - "discover.docTable.tableHeader.removeColumnButtonTooltip": "Supprimer la colonne", - "discover.docTable.tableHeader.sortByColumnAscendingAriaLabel": "Trier la colonne {columnName} par ordre croissant", - "discover.docTable.tableHeader.sortByColumnDescendingAriaLabel": "Trier la colonne {columnName} par ordre décroissant", - "discover.docTable.tableHeader.sortByColumnUnsortedAriaLabel": "Arrêter de trier la colonne {columnName}", - "discover.docTable.tableHeader.timeFieldIconTooltip": "Ce champ représente l'heure à laquelle les événements se sont produits.", - "discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} : ce champ représente l'heure à laquelle les événements se sont produits.", - "discover.docTable.tableRow.detailHeading": "Document développé", - "discover.docTable.tableRow.filterForValueButtonAriaLabel": "Filtrer sur la valeur", - "discover.docTable.tableRow.filterForValueButtonTooltip": "Filtrer sur la valeur", - "discover.docTable.tableRow.filterOutValueButtonAriaLabel": "Exclure la valeur", - "discover.docTable.tableRow.filterOutValueButtonTooltip": "Exclure la valeur", - "discover.docTable.tableRow.toggleRowDetailsButtonAriaLabel": "Afficher/Masquer les détails de la ligne", - "discover.docTable.tableRow.viewSingleDocumentLinkText": "Afficher un seul document", - "discover.docTable.tableRow.viewSurroundingDocumentsLinkText": "Afficher les documents alentour", "discover.documentsAriaLabel": "Documents", "discover.docViews.logsOverview.title": "Aperçu du log", - "discover.docViews.table.scoreSortWarningTooltip": "Filtrez sur _score pour pouvoir récupérer les valeurs correspondantes.", "discover.dropZoneTableLabel": "Abandonner la zone pour ajouter un champ en tant que colonne dans la table", "discover.embeddable.inspectorRequestDataTitle": "Données", "discover.embeddable.inspectorRequestDescription": "Cette requête interroge Elasticsearch afin de récupérer les données pour la recherche.", @@ -2873,7 +2827,6 @@ "discover.globalSearch.esqlSearchTitle": "Créer des recherches ES|QL", "discover.goToDiscoverButtonText": "Aller à Discover", "discover.grid.tableRow.actionsLabel": "Actions", - "discover.grid.tableRow.esqlDetailHeading": "Résultat étendu", "discover.grid.tableRow.mobileFlyoutActionsButton": "Actions", "discover.grid.tableRow.moreFlyoutActionsButton": "Plus d'actions", "discover.grid.tableRow.viewSingleDocumentLinkLabel": "Afficher un seul document", @@ -2884,7 +2837,6 @@ "discover.hitsCounter.hitsPluralTitle": "{formattedHits} {hits, plural, one {résultat} other {résultats}}", "discover.hitsCounter.partialHits": "≥{formattedHits}", "discover.hitsCounter.partialHitsPluralTitle": "≥{formattedHits} {hits, plural, one {résultat} other {résultats}}", - "discover.howToSeeOtherMatchingDocumentsDescription": "Voici les {sampleSize} premiers documents correspondant à votre recherche. Veuillez affiner celle-ci pour en voir plus.", "discover.inspectorEsqlRequestDescription": "Cette requête interroge Elasticsearch afin de récupérer les résultats pour le tableau.", "discover.inspectorEsqlRequestTitle": "Tableau", "discover.inspectorRequestDataTitleDocuments": "Documents", @@ -2893,7 +2845,6 @@ "discover.invalidFiltersWarnToast.description": "Les références d'ID de la vue de données dans certains filtres appliqués diffèrent de la vue de données actuelle.", "discover.invalidFiltersWarnToast.title": "Références d'index différentes", "discover.loadingDocuments": "Chargement des documents", - "discover.loadingResults": "Chargement des résultats", "discover.localMenu.alertsDescription": "Alertes", "discover.localMenu.esqlTooltipLabel": "ES|QL est le nouveau langage de requête canalisé puissant d'Elastic.", "discover.localMenu.fallbackReportTitle": "Recherche Discover sans titre", @@ -8314,24 +8265,16 @@ "unifiedDocViewer.docView.table.searchPlaceHolder": "Rechercher des noms ou valeurs de champs", "unifiedDocViewer.docViews.json.jsonTitle": "JSON", "unifiedDocViewer.docViews.table.esqlMultivalueFilteringDisabled": "Le filtrage multivalué n'est pas pris en charge dans ES|QL", - "unifiedDocViewer.docViews.table.filterForFieldPresentButtonAriaLabel": "Filtrer sur le champ", "unifiedDocViewer.docViews.table.filterForFieldPresentButtonTooltip": "Filtrer sur le champ", - "unifiedDocViewer.docViews.table.filterForValueButtonAriaLabel": "Filtrer sur la valeur", "unifiedDocViewer.docViews.table.filterForValueButtonTooltip": "Filtrer sur la valeur", - "unifiedDocViewer.docViews.table.filterOutValueButtonAriaLabel": "Exclure la valeur", "unifiedDocViewer.docViews.table.filterOutValueButtonTooltip": "Exclure la valeur", "unifiedDocViewer.docViews.table.ignored.multiValueLabel": "Contient des valeurs ignorées", "unifiedDocViewer.docViews.table.ignored.singleValueLabel": "Valeur ignorée", "unifiedDocViewer.docViews.table.ignoredValuesCanNotBeSearchedWarningMessage": "Les valeurs ignorées ne peuvent pas être recherchées", "unifiedDocViewer.docViews.table.pinFieldLabel": "Épingler le champ", "unifiedDocViewer.docViews.table.tableTitle": "Tableau", - "unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel": "Afficher/Masquer la colonne dans le tableau", - "unifiedDocViewer.docViews.table.toggleColumnInTableButtonTooltip": "Afficher/Masquer la colonne dans le tableau", "unifiedDocViewer.docViews.table.toggleColumnTableButtonTooltip": "Afficher/Masquer la colonne dans le tableau", - "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip": "Impossible de filtrer sur les champs méta", - "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip": "Impossible de filtrer sur les champs scriptés", "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsWarningMessage": "Impossible de filtrer sur les champs scriptés", - "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "Les champs non indexés ou les valeurs ignorées ne peuvent pas être recherchés", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedWarningMessage": "Il est impossible d’effectuer une recherche sur des champs non indexés", "unifiedDocViewer.docViews.table.unpinFieldLabel": "Désépingler le champ", "unifiedDocViewer.docViews.table.viewLessButton": "Afficher moins", @@ -8341,7 +8284,6 @@ "unifiedDocViewer.fieldActions.filterForValue": "Filtrer sur la valeur", "unifiedDocViewer.fieldActions.filterOutValue": "Exclure la valeur", "unifiedDocViewer.fieldActions.toggleColumn": "Afficher/Masquer la colonne dans le tableau", - "unifiedDocViewer.fieldChooser.discoverField.actions": "Actions", "unifiedDocViewer.fieldChooser.discoverField.multiField": "champ multiple", "unifiedDocViewer.fieldChooser.discoverField.multiFieldTooltipContent": "Les champs multiples peuvent avoir plusieurs valeurs.", "unifiedDocViewer.fieldChooser.discoverField.name": "Champ", @@ -11527,7 +11469,6 @@ "xpack.apm.profiling.callout.dismiss": "Rejeter", "xpack.apm.profiling.callout.learnMore": "En savoir plus", "xpack.apm.profiling.callout.title": "Affichage des informations de profilage de l'hôte ou des hôtes exécutant des services {serviceName}", - "xpack.apm.profiling.flamegraph.filteredLabel": "Affichage des informations de profilage du ou des hôtes des services", "xpack.apm.profiling.flamegraph.link": "Accéder au flame-graph d'Universal Profiling", "xpack.apm.profiling.flamegraph.noDataFound": "Aucune donnée trouvée", "xpack.apm.profiling.tabs.flamegraph": "Flame-graph", @@ -15037,7 +14978,6 @@ "xpack.csp.fleetIntegration.azureAccountTypeDescriptionLabel": "Choisissez d'intégrer une organisation Azure (groupe racine du locataire) ou un seul abonnement Azure, puis saisissez un nom et une description pour permettre l'identification de cette intégration.", "xpack.csp.fleetIntegration.cnvm.additionalChargesCalloutDescription": "Veuillez noter que l'utilisation de ce service peut entraîner des frais supplémentaires sur le prochain relevé de facturation provenant de votre fournisseur cloud en raison d'une augmentation de l'utilisation.", "xpack.csp.fleetIntegration.cnvm.additionalChargesCalloutTitle": "Frais supplémentaires sur le compte de facturation du fournisseur cloud.", - "xpack.csp.fleetIntegration.cnvm.configureIntegrationDescription": "Sélectionner le fournisseur de services cloud (CSP) que vous souhaitez monitorer, puis remplir le nom et la description pour faciliter l'identification de cette intégration", "xpack.csp.fleetIntegration.configureCspmIntegrationDescription": "Sélectionner le fournisseur de services cloud (CSP) que vous souhaitez monitorer, puis remplir le nom et la description pour faciliter l'identification de cette intégration", "xpack.csp.fleetIntegration.configureKspmIntegrationDescription": "Sélectionner le type de cluster Kubernetes que vous souhaitez monitorer, puis remplir le nom et la description pour faciliter l'identification de cette intégration", "xpack.csp.fleetIntegration.editWarning.calloutDescription": "Afin de changer le fournisseur de services cloud (CSP) que vous souhaitez monitorer, d'ajouter des comptes ou de modifier l'emplacement de déploiement (organisation ou compte unique) de la gestion du niveau de sécurité du cloud (CSPM), veuillez ajouter une nouvelle intégration CSPM.", @@ -15105,15 +15045,9 @@ "xpack.csp.grouping.nullGroupTooltip.groupingTitle": "regrouper par", "xpack.csp.integrationDashboard.noFindings.promptTitle": "Statut d'évaluation des résultats", "xpack.csp.integrationDashboard.noFindingsPrompt.promptDescription": "En attente de la collecte et de l'indexation des données. Si ce processus prend plus de temps que prévu, veuillez contacter notre support technique", - "xpack.csp.kspmIntegration.aksOption.benchmarkTitle": "CIS AKS", - "xpack.csp.kspmIntegration.aksOption.nameTitle": "AKS", - "xpack.csp.kspmIntegration.aksOption.tooltipContent": "Azure Kubernetes Service - Bientôt disponible", "xpack.csp.kspmIntegration.eksOption.benchmarkTitle": "CIS EKS", "xpack.csp.kspmIntegration.eksOption.nameTitle": "EKS", "xpack.csp.kspmIntegration.eksOption.tooltipContent": "EKS (Elastic Kubernetes Service)", - "xpack.csp.kspmIntegration.gkeOption.benchmarkTitle": "CIS GKE", - "xpack.csp.kspmIntegration.gkeOption.nameTitle": "GKE", - "xpack.csp.kspmIntegration.gkeOption.tooltipContent": "Google Kubernetes Engine - Bientôt disponible", "xpack.csp.kspmIntegration.integration.nameTitle": "Gestion du niveau de sécurité Kubernetes", "xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM", "xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes", @@ -15248,10 +15182,6 @@ "xpack.csp.vulnerabilties.intergationNoInstalledEmptyPrompt.promptDescription": "Détectez et corrigez les vulnérabilités potentielles {lineBreak} de vos ressources cloud, grâce à l'intégration de notre solution Gestion des vulnérabilités {lineBreak} cloud-native (CNVM). {lineBreak} {learnMore}", "xpack.csp.vulnerabilties.intergationNoInstalledEmptyPrompt.promptTitle": "Gestion des vulnérabilités {lineBreak} cloud-native d'Elastic", "xpack.csp.vulnMgmtIntegration.awsOption.nameTitle": "Amazon Web Services", - "xpack.csp.vulnMgmtIntegration.azureOption.nameTitle": "Azure", - "xpack.csp.vulnMgmtIntegration.azureOption.tooltipContent": "Bientôt disponible", - "xpack.csp.vulnMgmtIntegration.gcpOption.nameTitle": "GCP", - "xpack.csp.vulnMgmtIntegration.gcpOption.tooltipContent": "Bientôt disponible", "xpack.customBranding.appName": "Marque personnalisée", "xpack.customBranding.customizedLogoDescription": "Remplace le texte en regard du logo. Les images sont plus belles lorsqu'elles ne dépassent pas 200 x 84 pixels et qu'elles ont un arrière-plan transparent. {subscriptionLink}", "xpack.customBranding.customizedLogoLabel": "Nom de l'organisation", @@ -15287,8 +15217,6 @@ "xpack.datasetQuality.degradedDocsColumnTooltip": "Le pourcentage de documents avec la propriété {ignoredProperty} dans votre ensemble de données.", "xpack.datasetQuality.degradedDocsQualityDescription": "{quality} -{comparator} {minimimPercentage}%", "xpack.datasetQuality.detail.degradedFieldsSectionTitle": "Problèmes de qualité", - "xpack.datasetQuality.details.chartExploreDataInDiscoverText": "Explorer les données dans Discover", - "xpack.datasetQuality.details.chartExploreDataInLogsExplorerText": "Explorer les données dans l'Explorateur de logs", "xpack.datasetQuality.details.chartOpenInLensText": "Ouvrir dans Lens", "xpack.datasetQuality.details.checkBreakdownFieldEcsFailed": "Nous n'avons pas pu récupérer les métadonnées du champ de répartition.", "xpack.datasetQuality.details.datasetCreatedOnText": "Créé le", @@ -15324,7 +15252,6 @@ "xpack.datasetQuality.details.fetchDataStreamDetailsFailed": "Nous n'avons pas pu obtenir les détails de votre flux de données.", "xpack.datasetQuality.details.fetchDataStreamSettingsFailed": "Les paramètres du flux de données n'ont pas pu être chargés.", "xpack.datasetQuality.details.fetchIntegrationDashboardsFailed": "Nous n'avons pas pu obtenir vos tableaux de bord d'intégration.", - "xpack.datasetQuality.details.fetchIntegrationsFailed": "Nous n'avons pas pu obtenir les informations relatives à l'intégration de {integrationName}.", "xpack.datasetQuality.details.indexTemplateActionText": "Modèle d'index", "xpack.datasetQuality.details.integrationActionsText": "Actions d'intégration", "xpack.datasetQuality.details.integrationnameText": "Intégration", @@ -15431,7 +15358,6 @@ "xpack.datasetQuality.types.label": "Types", "xpack.dataUsage.charts.ingestedMax": "Données ingérées", "xpack.dataUsage.charts.retainedMax": "Données conservées dans le stockage", - "xpack.dataUsage.metrics.filter.clearAll": "Tout effacer", "xpack.dataUsage.metrics.filter.dataStreams": "Flux de données", "xpack.dataUsage.metrics.filter.emptyMessage": "Aucun {filterName} disponible", "xpack.dataUsage.metrics.filter.metricTypes": "Types d'indicateurs", @@ -17425,8 +17351,6 @@ "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done": "Terminé", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton": "Générer une clé", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title": "Créer une clé d'API d'analyse", - "xpack.enterpriseSearch.content.cannotConnect.body": "En savoir plus.", - "xpack.enterpriseSearch.content.cannotConnect.title": "Impossible de se connecter à Enterprise Search", "xpack.enterpriseSearch.content.conectors.indexHealth": "Intègre", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.badgeType.connectorClient": "Connecteur autogéré", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.badgeType.nativeConnector": "Connecteur géré par Elastic", @@ -17451,7 +17375,6 @@ "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.callout.finishLaterButton.label": "Terminer le déploiement plus tard", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.callout.title": "En attente de votre connecteur", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.title": "En attente du contrôle de votre connecteur", - "xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.apiKey.title": "Clé d'API", "xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.configuration.title": "Configuration", "xpack.enterpriseSearch.content.connectors.breadcrumb": "Connecteurs", "xpack.enterpriseSearch.content.connectors.connectorDetail.configurationTabLabel": "Configuration", @@ -17481,10 +17404,6 @@ "xpack.enterpriseSearch.content.connectors.deleteModal.delete.crawler.description": "Vous êtes sur le point de supprimer le robot d'indexation suivant :", "xpack.enterpriseSearch.content.connectors.deleteModal.syncsWarning.indexNameDescription": "Cette action ne peut pas être annulée. Veuillez saisir {connectorName} pour confirmer.", "xpack.enterpriseSearch.content.connectors.deleteModal.title": "Supprimer {connectorCount} connecteur ?", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.description.ariaLabel": "Modifier la description du connecteur", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.description.placeholder": "Ajouter une description", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.name.ariaLabel": "Modifier le nom du connecteur", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.name.placeholder": "Ajouter un nom pour votre connecteur", "xpack.enterpriseSearch.content.connectors.overview.connectorErrorCallOut.title": "Votre connecteur a rapporté une erreur", "xpack.enterpriseSearch.content.connectors.overview.connectorIndexDoesntExistCallOut.description": "Le connecteur va créer l'index lors de sa prochaine synchronisation. Vous pouvez également créer l’index {indexName} manuellement avec les paramètres et les mappings de votre choix.", "xpack.enterpriseSearch.content.connectors.overview.connectorIndexDoesntExistCallOut.title": "L'index attaché n'existe pas", @@ -17622,8 +17541,6 @@ "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.description": "Vous souhaitez héberger vous-même ce connecteur ? Convertissez-le en {link} afin qu'il soit géré sur votre propre infrastructure. Vous devez convertir ce connecteur si vous souhaitez personnaliser le code à l'aide de notre cadre Python.", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.linkTitle": "connecteur autogéré", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.title": "Autogestion de ce connecteur", - "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.text": "Les connecteurs gérés par Elastic nécessitent une instance Enterprise Search en cours d'exécution.", - "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.title": "Aucune instance Enterprise Search en cours d'exécution détectée", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnectorAdvancedConfiguration.description": "Finalisez votre connecteur en déclenchant une synchronisation unique, ou en définissant un calendrier de synchronisation récurrent.", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnectorAdvancedConfiguration.schedulingButtonLabel": "Définir un calendrier et synchroniser", "xpack.enterpriseSearch.content.indices.configurationConnector.researchConfiguration.connectorDocumentationLinkLabel": "Documentation", @@ -17976,7 +17893,6 @@ "xpack.enterpriseSearch.content.playground.breadcrumb": "Playground", "xpack.enterpriseSearch.content.searchIndex.cancelSync.successMessage": "Annulation réussie de la synchronisation", "xpack.enterpriseSearch.content.searchIndex.cancelSyncs.successMessage": "Annulation réussie des synchronisations", - "xpack.enterpriseSearch.content.searchIndex.cannotConnect.body": "Le robot d'indexation Elastic requiert Enterprise Search. {link}", "xpack.enterpriseSearch.content.searchIndex.configurationTabLabel": "Configuration", "xpack.enterpriseSearch.content.searchIndex.connectorErrorCallOut.title": "Votre connecteur a rapporté une erreur", "xpack.enterpriseSearch.content.searchIndex.crawlerConfigurationTabLabel": "Configuration", @@ -18310,14 +18226,10 @@ "xpack.enterpriseSearch.createConnector..title": "Créer un connecteur", "xpack.enterpriseSearch.createConnector.badgeType.ElasticManaged": "Géré par Elastic", "xpack.enterpriseSearch.createConnector.badgeType.selfManaged": "Autogéré", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.BetaBadgeLabel": "Bêta", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.OnlySelfManagedBadgeLabel": "Autogéré", "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.placeholder.text": "Choisir une source de données", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.thechPreviewBadgeLabel": "Préversion technique", "xpack.enterpriseSearch.createConnector.configurationStep.configurationLabel": "Configuration", "xpack.enterpriseSearch.createConnector.configurationStep.h4.finishUpLabel": "Terminer", "xpack.enterpriseSearch.createConnector.configurationStep.p.description": "Vous pouvez synchroniser manuellement vos données, planifier une synchronisation récurrente ou gérer vos domaines.", - "xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.notAvailableTitle": "Ce connecteur n'est pas disponible en tant que connecteur géré par Elastic", "xpack.enterpriseSearch.createConnector.connectorDocsLinkLabel": "référence du connecteur", "xpack.enterpriseSearch.createConnector.DeploymentStep.Configuration.description": "Maintenant, configurez votre robot Elastic et synchronisez les données.", "xpack.enterpriseSearch.createConnector.DeploymentStep.Configuration.title": "Configuration", @@ -18392,17 +18304,6 @@ "xpack.enterpriseSearch.enterpriseSearch.setupGuide.videoAlt": "Premiers pas avec Enterprise Search", "xpack.enterpriseSearch.enterpriseSearchCard.cta": "En savoir plus", "xpack.enterpriseSearch.entSearch.productCardDescription": "Applications standalone adaptées à des expériences de recherche plus simples, conviviales et axées sur les entreprises.", - "xpack.enterpriseSearch.errorConnectingCallout.setupGuideCta": "Consulter le guide de configuration", - "xpack.enterpriseSearch.errorConnectingCallout.title": "Impossible de se connecter à Enterprise Search", - "xpack.enterpriseSearch.errorConnectingState.cloudErrorMessage": "Les nœuds Enterprise Search fonctionnent-ils dans votre déploiement cloud ? {deploymentSettingsLink}", - "xpack.enterpriseSearch.errorConnectingState.cloudErrorMessageLinkText": "Vérifier vos paramètres de déploiement", - "xpack.enterpriseSearch.errorConnectingState.description1": "Impossible d'établir une connexion à Enterprise Search avec l'URL hôte {enterpriseSearchUrl} en raison de l'erreur suivante :", - "xpack.enterpriseSearch.errorConnectingState.description2": "Vérifiez que l'URL hôte est correctement configurée dans {configFile}.", - "xpack.enterpriseSearch.errorConnectingState.description3": "Assurez-vous que le serveur d'Enterprise Search est en état de répondre.", - "xpack.enterpriseSearch.errorConnectingState.setupGuideCta": "Consulter le guide de configuration", - "xpack.enterpriseSearch.errorConnectingState.title": "Impossible d'établir une connexion", - "xpack.enterpriseSearch.errorConnectingState.troubleshootAuth": "Vérifiez votre authentification utilisateur :", - "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthMessage": "Contactez votre administrateur pour installer un mapping des rôles pour vous donner accès à Enterprise Search", "xpack.enterpriseSearch.exampleConnectorLabel": "Exemple", "xpack.enterpriseSearch.finishUpStep.euiButton.viewInDiscoverLabel": "Afficher dans Discover", "xpack.enterpriseSearch.getConnectorTypeBadge.connectorClientBadgeLabel": "Autogéré", @@ -18551,9 +18452,6 @@ "xpack.enterpriseSearch.navigation.contentPlaygroundLinkLabel": "Playground", "xpack.enterpriseSearch.navigation.contentWebcrawlersLinkLabel": "Robots d'indexation", "xpack.enterpriseSearch.navigation.relevanceInferenceEndpointsLinkLabel": "Points de terminaison d'inférence", - "xpack.enterpriseSearch.noEntSearch.noCrawler": "Le robot d'indexation d'Elastic n'est pas disponible sans Entreprise Search.", - "xpack.enterpriseSearch.noEntSearch.setupGuideCta": "Consulter le guide de configuration", - "xpack.enterpriseSearch.noEntSearchConfigured.title": "Enterprise Search n'a pas encore été configuré", "xpack.enterpriseSearch.notFound.action1": "Retour à votre tableau de bord", "xpack.enterpriseSearch.notFound.action2": "Contacter le support technique", "xpack.enterpriseSearch.notFound.description": "Impossible de trouver la page que vous recherchez.", @@ -18822,7 +18720,6 @@ "xpack.enterpriseSearch.searchApplications.searchApplication.indices.searchPlaceholder": "Filtrer les index", "xpack.enterpriseSearch.searchApplications.searchApplication.indices.someUnknownIndicesCallout.description": "Certaines données peuvent être inaccessibles à partir de cette application de recherche. Recherchez les opérations en attente ou les erreurs sur les index concernés, ou supprimez les index qui ne doivent plus être utilisés par cette application de recherche.", "xpack.enterpriseSearch.searchApplications.searchApplication.indices.someUnknownIndicesCallout.title": "Certains de vos index ne sont pas disponibles.", - "xpack.enterpriseSearch.searchApplications.searchApplication.notFound.action1": "Revenir aux applications de recherche", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.button": "Afficher les conflits", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.description": "Les conflits de type de champ de schéma peuvent être résolus en navigant directement sur l’index source et en mettant à jour le type de champ du ou des champs conflictuels afin qu’il corresponde à celui des autres index sources.", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.title": "Problèmes potentiels de mapping de champ trouvés", @@ -19036,10 +18933,6 @@ "xpack.enterpriseSearch.vectorSearch.guide.query.title": "Effectuer une recherche vectorielle", "xpack.enterpriseSearch.vectorSearch.navTitle": "Recherche vectorielle", "xpack.enterpriseSearch.vectorSearch.productName": "Recherche vectorielle", - "xpack.enterpriseSearch.versionMismatch.body": "Vos versions de Kibana et d'Enterprise Search ne correspondent pas. Pour accéder à Enterprise Search, utilisez la même version majeure et mineure pour chaque service.", - "xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText": "Version d'Enterprise Search : {enterpriseSearchVersion}", - "xpack.enterpriseSearch.versionMismatch.kibanaVersionText": "Version de Kibana: {kibanaVersion}", - "xpack.enterpriseSearch.versionMismatch.title": "Erreur de version incompatible", "xpack.enterpriseSearch.welcomeBanner.header.greeting.customTitle": "👋 Bonjour {name} !", "xpack.enterpriseSearch.welcomeBanner.header.greeting.defaultTitle": "👋 Bonjour", "xpack.enterpriseSearch.welcomeBanner.header.title": "Ajouter des données à Elasticsearch et rechercher, vectoriser ou visualiser", @@ -20495,7 +20388,6 @@ "xpack.fleet.agentPolicyForm.newAgentPolicyFieldLabel": "Nouveau nom de la stratégie d'agent", "xpack.fleet.agentPolicyForm.outputOptionDisabledTypeNotSupportedText": "La sortie {outputType} pour l'intégration des agents n'est pas prise en charge pour Fleet Server, Synthetics ou APM.", "xpack.fleet.agentPolicyForm.outputOptionDisableOutputTypeText": "La sortie {outputType} pour l'intégration des agents n'est pas prise en charge pour Fleet Server, Synthetics ou APM.", - "xpack.fleet.agentPolicyForm.spaceDescription": "Sélectionnez un ou plusieurs espaces pour cette politique ou créez un nouvel espace. {link}", "xpack.fleet.agentPolicyForm.spaceFieldLabel": "Espaces", "xpack.fleet.agentPolicyForm.systemMonitoringText": "Collecte des logs et des mesures du système", "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "Cela ajoutera également une intégration {system} pour collecter les logs et les indicateurs du système.", @@ -22585,8 +22477,6 @@ "xpack.idxMgmt.enrichPolicyCreate.configurationStep.queryLabel": "Requête (facultative)", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeOption": "Plage", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeTypePopOver": "{type} correspond à un nombre, une date ou une plage d'adresses IP.", - "xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesLabel": "Index source", - "xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesRequiredError": "Au moins un index source est requis.", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.typeRequiredError": "Une valeur est requise pour le type de politique.", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.typeTitlePopOver": "Détermine comment faire correspondre les données avec les documents entrants.", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.uploadFileLink": "Charger un fichier", @@ -22669,10 +22559,6 @@ "xpack.idxMgmt.home.componentTemplates.list.loadingMessage": "Chargement des modèles de composants en cours…", "xpack.idxMgmt.home.componentTemplatesTabTitle": "Modèles de composants", "xpack.idxMgmt.home.dataStreamsTabTitle": "Flux de données", - "xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesDescription": "Vérification des privilèges…", - "xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesErrorMessage": "Erreur lors de la récupération des privilèges utilisateur depuis le serveur.", - "xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeDescription": "Pour utiliser les Politiques d'enrichissement, vous devez disposer des privilèges de cluster suivants : {missingPrivileges}.", - "xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeTitle": "Gestion des privilèges d'enrichissement requise", "xpack.idxMgmt.home.enrichPoliciesTabTitle": "Politiques d'enrichissement", "xpack.idxMgmt.home.idxMgmtDescription": "Mettez à jour vos index Elasticsearch individuellement ou par lots. {learnMoreLink}", "xpack.idxMgmt.home.idxMgmtDocsLinkText": "Documentation sur la gestion des index", @@ -23322,7 +23208,6 @@ "xpack.idxMgmt.mappingsEditor.parameters.validations.fieldDataFrequency.numberGreaterThanOneErrorMessage": "La valeur doit être supérieure à un.", "xpack.idxMgmt.mappingsEditor.parameters.validations.greaterThanZeroErrorMessage": "Le facteur de montée en charge doit être supérieur à 0.", "xpack.idxMgmt.mappingsEditor.parameters.validations.ignoreAboveIsRequiredErrorMessage": "Limite de longueur de caractère obligatoire.", - "xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage": "L’ID d’inférence est requis.", "xpack.idxMgmt.mappingsEditor.parameters.validations.localeFieldRequiredErrorMessage": "Spécifiez un paramètre régional.", "xpack.idxMgmt.mappingsEditor.parameters.validations.maxInputLengthFieldRequiredErrorMessage": "Spécifiez une longueur d'entrée maximale.", "xpack.idxMgmt.mappingsEditor.parameters.validations.nameIsRequiredErrorMessage": "Donnez un nom au champ.", @@ -23728,7 +23613,6 @@ "xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableExplanationText": "Réduisez le nombre de segments dans chaque partition d'index et nettoyez les documents supprimés.", "xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableText": "Forcer la fusion", "xpack.indexLifecycleMgmt.editPolicy.forcemerge.numberOfSegmentsRequiredError": "Valeur obligatoire du nombre de segments.", - "xpack.indexLifecycleMgmt.editPolicy.formErrorsMessage": "Veuillez corriger les erreurs sur cette page.", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.activateFrozenPhaseSwitchLabel": "Activer la phase \"frozen\"", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.frozenPhaseDescription": "Transférez les données au niveau \"frozen\" pour les conserver sur le long terme. Le niveau \"frozen\" représente le moyen le plus rentable de conserver vos données tout en permettant d'effectuer des recherches.", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.frozenPhaseTitle": "Phase \"frozen\"", @@ -26184,7 +26068,6 @@ "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "Horodatage des dernières données reçues pour l'entité (entity.lastSeenTimestamp)", "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "Type", "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "Type d'entité (entity.type)", - "xpack.inventory.entityActions.discoverLink": "Ouvrir dans Discover", "xpack.inventory.featureRegistry.inventoryFeatureName": "Inventory", "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "Alertes actives", "xpack.inventory.inventoryLinkTitle": "Inventory", @@ -26366,7 +26249,6 @@ "xpack.lens.app.createVisualizationLabel": "ES|QL", "xpack.lens.app.docLoadingError": "Erreur lors du chargement du document enregistré", "xpack.lens.app.editLensEmbeddableLabel": "Modifier la visualisation", - "xpack.lens.app.editVisualizationLabel": "Modifier la visualisation {lang}", "xpack.lens.app.exploreDataInDiscover": "Explorer dans Discover", "xpack.lens.app.exploreDataInDiscoverDrilldown": "Ouvrir dans Discover", "xpack.lens.app.exploreDataInDiscoverDrilldown.newTabConfig": "Ouvrir dans un nouvel onglet", @@ -26524,14 +26406,6 @@ "xpack.lens.editorFrame.suggestionPanelTitle": "Suggestions", "xpack.lens.editorFrame.tooManyDimensionsSingularWarningLabel": "Veuillez retirer {dimensionsTooMany, plural, one {une dimension} other {{dimensionsTooMany} dimensions}}", "xpack.lens.editorFrame.workspaceLabel": "Espace de travail", - "xpack.lens.embeddable.failure": "Impossible d'afficher la visualisation", - "xpack.lens.embeddable.featureBadge.iconDescription": "{count} {count, plural, one {modificateur} other {modificateurs}} de visualisation", - "xpack.lens.embeddable.fixErrors": "Effectuez des modifications dans l'éditeur Lens pour corriger l'erreur", - "xpack.lens.embeddable.legacyURLConflict.shortMessage": "Vous avez rencontré un conflit d’URL.", - "xpack.lens.embeddable.missingTimeRangeParam.longMessage": "La propriété timeRange est requise pour cette configuration.", - "xpack.lens.embeddable.missingTimeRangeParam.shortMessage": "Propriété timeRange manquante", - "xpack.lens.embeddable.moreErrors": "Effectuez des modifications dans l'éditeur Lens pour afficher plus d'erreurs", - "xpack.lens.embeddableDisplayName": "Lens", "xpack.lens.endValue.nearest": "La plus proche", "xpack.lens.endValue.none": "Masquer", "xpack.lens.endValue.zero": "Zéro", @@ -26539,6 +26413,7 @@ "xpack.lens.endValueDescription.none": "Ne pas étendre la série au bord du graphique", "xpack.lens.endValueDescription.zero": "Étendre la série au bord du graphique avec la valeur zéro", "xpack.lens.experimentalLabel": "Version d'évaluation technique", + "xpack.lens.featureBadge.iconDescription": "{count} {count, plural, one {modificateur} other {modificateurs}} de visualisation", "xpack.lens.fieldFormats.longSuffix.d": "par jour", "xpack.lens.fieldFormats.longSuffix.h": "par heure", "xpack.lens.fieldFormats.longSuffix.m": "par minute", @@ -26558,6 +26433,7 @@ "xpack.lens.fittingFunctionsTitle.lookahead": "Suivant", "xpack.lens.fittingFunctionsTitle.none": "Masquer", "xpack.lens.fittingFunctionsTitle.zero": "Zéro", + "xpack.lens.fixErrors": "Effectuez des modifications dans l'éditeur Lens pour corriger l'erreur", "xpack.lens.formula.disableWordWrapLabel": "Désactiver le renvoi à la ligne des mots", "xpack.lens.formula.editorHelpInlineHideLabel": "Masquer la référence des fonctions", "xpack.lens.formula.editorHelpInlineHideToolTip": "Masquer la référence des fonctions", @@ -27041,7 +26917,6 @@ "xpack.lens.legacyMetric.titlePositions.bottom": "Bas", "xpack.lens.legacyMetric.titlePositions.top": "Haut", "xpack.lens.legacyUrlConflict.objectNoun": "Visualisation Lens", - "xpack.lens.lensSavedObjectLabel": "Visualisation Lens", "xpack.lens.lineCurve.smooth": "Lisser", "xpack.lens.lineCurve.step": "Étape", "xpack.lens.lineCurve.straight": "Droit", @@ -27101,6 +26976,7 @@ "xpack.lens.modalTitle.title.deleteAnnotations": "Supprimer le groupe d'annotations ?", "xpack.lens.modalTitle.title.deleteReferenceLines": "Supprimer le calque de lignes de référence ?", "xpack.lens.modalTitle.title.deleteVis": "Supprimer le calque de visualisation ?", + "xpack.lens.moreErrors": "Effectuez des modifications dans l'éditeur Lens pour afficher plus d'erreurs", "xpack.lens.pageTitle": "Lens", "xpack.lens.paletteHeatmapGradient.label": "Couleur", "xpack.lens.paletteMetricGradient.label": "Couleur", @@ -36024,15 +35900,6 @@ "xpack.searchInferenceEndpoints.actions.endpointAddedSuccess": "Point de terminaison ajouté", "xpack.searchInferenceEndpoints.actions.endpointAddedSuccessDescription": "Le point de terminaison d'inférence \"{endpointId}\" a été ajouté.", "xpack.searchInferenceEndpoints.actions.trainedModelsStatGatherFailed": "Échec de la récupération des statistiques du modèle entraîné", - "xpack.searchInferenceEndpoints.addEmptyPrompt.createFirstInferenceEndpointDescription": "Les points de terminaison d'inférence vous permettent d'effectuer des tâches d'inférence à l'aide de modèles NLP fournis par des services tiers ou de modèles intégrés d'Elastic comme ELSER et E5. Configurez des tâches telles que l'incorporation de texte, les complétions, le reclassement et bien plus encore à l'aide de la fonction Créer une API d'inférence.", - "xpack.searchInferenceEndpoints.addEmptyPrompt.e5Description": "E5 est un modèle NLP tiers qui vous permet de réaliser des recherches sémantiques multilingues en utilisant des représentations vectorielles denses.", - "xpack.searchInferenceEndpoints.addEmptyPrompt.e5Title": "E5 multilingue", - "xpack.searchInferenceEndpoints.addEmptyPrompt.elserDescription": "ELSER est le modèle NLP vectoriel creux d'Elastic pour la recherche sémantique en anglais.", - "xpack.searchInferenceEndpoints.addEmptyPrompt.elserTitle": "ELSER", - "xpack.searchInferenceEndpoints.addEmptyPrompt.learnHowToCreateInferenceEndpoints": "Découvrez comment créer des points de terminaison d'inférence", - "xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithE5": "Recherche sémantique avec E5 multilingue", - "xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithElser": "Recherche sémantique avec ELSER", - "xpack.searchInferenceEndpoints.addEmptyPrompt.startWithPreparedEndpointsLabel": "En savoir plus sur les modèles NLP intégrés :", "xpack.searchInferenceEndpoints.allInferenceEndpoints.description": "Les points de terminaison d'inférence rationalisent le déploiement et la gestion des modèles d'apprentissage automatique dans Elasticsearch. Configurez et gérez des tâches NLP à l'aide de points de terminaison uniques afin de créer une recherche basée sur l'IA.", "xpack.searchInferenceEndpoints.apiDocumentationLink": "Documentation sur les API", "xpack.searchInferenceEndpoints.cancel": "Annuler", @@ -37228,8 +37095,6 @@ "xpack.securitySolution.assistant.quickPrompts.alertSummarizationTitle": "Synthèse de l’alerte", "xpack.securitySolution.assistant.quickPrompts.AutomationPrompt": "Quelle intégration d’Elastic Agent activée par Fleet dois-je utiliser pour collecter des logs et des évènements de :", "xpack.securitySolution.assistant.quickPrompts.AutomationTitle": "Conseil sur l’intégration d’agent", - "xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationPrompt": "En tant qu'utilisateur expert d'Elastic Security, veuillez générer une requête ESQL valide et précise pour détecter le cas d'utilisation ci-dessous. Votre réponse doit être formatée pour pouvoir être utilisée immédiatement dans une chronologie ou une règle de détection d’Elastic Security. Prenez votre temps pour répondre, vérifiez bien vos connaissances et toutes les fonctions que je vous demande. Pour les réponses ES|QL en particulier, vous devez toujours répondre uniquement avec ce qui est disponible dans vos connaissances personnelles. Je ne peux pas me permettre que les requêtes soient inexactes. Supposez que j'utilise le Elastic Common Schema et l'agent Elastic. Veillez à ce que les réponses soient formatées de manière à pouvoir être facilement copiées sous la forme d'un bloc de code distinct dans le markdown.", - "xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationTitle": "Génération de requête ES|QL", "xpack.securitySolution.assistant.quickPrompts.ruleCreationPrompt": "En tant qu’utilisateur expert d’Elastic Security, veuillez générer une requête EQL valide et précise pour détecter le cas d’utilisation ci-dessous. Votre réponse doit être formatée pour pouvoir être utilisée immédiatement dans une chronologie ou une règle de détection d’Elastic Security. Si Elastic Security a déjà une règle prédéfinie pour le cas d’utilisation ou pour un cas similaire, veuillez fournir un lien vers cette règle et la décrire.", "xpack.securitySolution.assistant.quickPrompts.ruleCreationTitle": "Génération de requête", "xpack.securitySolution.assistant.quickPrompts.splQueryConversionPrompt": "J’ai la requête suivante d’une plateforme SIEM précédente. En tant qu’utilisateur expert d’Elastic Security, veuillez suggérer un équivalent EQL Elastic. Je dois être capable de la copier immédiatement dans une chronologie Elastic Security.", @@ -38066,10 +37931,6 @@ "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlQueryFieldRequiredError": "Une requête EQL est requise.", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionDisableText": "La suppression n'est pas prise en charge pour les requêtes de séquence EQL.", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionValidationText": "{EQL_SEQUENCE_SUPPRESSION_DISABLE_TOOLTIP} Remplacez la requête EQL par une requête non séquentielle ou supprimez les champs de suppression.", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoAriaLabel": "Ouvrir une fenêtre contextuelle d'aide", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipContent": "Consultez {createEsqlRuleTypeLink} pour commencer à utiliser les règles ES|QL.", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipLink": "documentation", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlQueryLabel": "Requête ES|QL", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldAnomalyThresholdLabel": "Seuil de score d'anomalie", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldMachineLearningJobIdLabel": "Tâche de Machine Learning", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldQuerBarLabel": "Requête personnalisée", @@ -38173,10 +38034,6 @@ "xpack.securitySolution.detectionEngine.esqlRuleType.eqlSearchRequestDescription": "Requête EQL visant à trouver toutes les correspondances", "xpack.securitySolution.detectionEngine.esqlRuleType.esqlSearchRequestDescription": "Requête ES|QL visant à trouver toutes les correspondances", "xpack.securitySolution.detectionEngine.esqlRuleType.findSourceDocumentsRequestDescription": "Récupérer les documents sources lorsque la requête ES|QL ne peut être agrégée", - "xpack.securitySolution.detectionEngine.esqlValidation.errorMessage": "Erreur lors de la validation ES|QL : \"{message}\"", - "xpack.securitySolution.detectionEngine.esqlValidation.missingIdFieldInQueryError": "Les requêtes n'utilisant pas la fonction STATS...BY (requêtes non-agrégées) doivent inclurent l'opérateur \"metadata _id, _version, _index\" après la commande de la source. Par exemple : FROM logs* metadata _id, _version, _index. De plus, les propriétés de métadonnées (_id, _version et _index) doivent être renvoyées dans la réponse à la requête.", - "xpack.securitySolution.detectionEngine.esqlValidation.missingMetadataOperatorInQueryError": "Les requêtes n'utilisant pas la fonction STATS...BY (requêtes non-agrégées) doivent inclurent l'opérateur \"metadata _id, _version, _index\" après la commande de la source. Par exemple : FROM logs* metadata _id, _version, _index.", - "xpack.securitySolution.detectionEngine.esqlValidation.unknownError": "Erreur inconnue lors de la validation ES|QL", "xpack.securitySolution.detectionEngine.executionRunType.backfill": "Manuel", "xpack.securitySolution.detectionEngine.executionRunType.standard": "Planifié", "xpack.securitySolution.detectionEngine.goToDocumentationButton": "Afficher la documentation", @@ -40450,7 +40307,6 @@ "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.noPermissionTitle": "Privilèges d'index insuffisants pour effectuer le chargement de fichiers CSV", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.resultsStepTitle": "Résultats", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.selectFileStepTitle": "Sélectionner un fichier", - "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.subTitle": "Importer des entités à l'aide d'un fichier texte", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unavailable": "La fonctionnalité de chargement de fichiers CSV de criticité des ressources n'est pas disponible.", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unsupportedFileTypeError": "Format de fichier sélectionné non valide. Veuillez choisir un fichier {supportedFileExtensions} et réessayer", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.uploadFileSizeLimit": "La taille maximale de fichier est de : {maxFileSize}", @@ -40492,7 +40348,6 @@ "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.clearAllEntities": "Effacer toutes les entités", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.close": "Fermer", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.title": "Effacer les données des entités ?", - "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntityData": "Supprimez toutes les données d'entité extraites du stockage. Cette action supprimera définitivement les enregistrements d’utilisateur et d'hôte persistants, les données ne seront par ailleurs plus disponibles pour l'analyse. Procédez avec prudence, car cette opération est irréversible. Notez que cette opération ne supprimera pas les données sources, les scores de risque des entités ni les attributions de criticité des ressources.", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.featureFlagDisabled": "Les fonctionnalités du stockage d'entités ne sont pas disponibles", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.subTitle": "Permet un monitoring complet des hôtes et des utilisateurs de votre système.", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.title": "Stockage d'entités", @@ -44906,7 +44761,6 @@ "xpack.spaces.management.spacesGridPage.editSpaceActionDescription": "Modifier {spaceName}.", "xpack.spaces.management.spacesGridPage.editSpaceActionName": "Modifier", "xpack.spaces.management.spacesGridPage.errorTitle": "Erreur lors du chargement des espaces", - "xpack.spaces.management.spacesGridPage.identifierColumnName": "Identificateur", "xpack.spaces.management.spacesGridPage.loadingTitle": "chargement…", "xpack.spaces.management.spacesGridPage.searchPlaceholder": "Recherche", "xpack.spaces.management.spacesGridPage.solutionColumnName": "Afficher la solution", @@ -46314,7 +46168,6 @@ "xpack.synthetics.failedStep.label": "Étape ayant échoué", "xpack.synthetics.fcp.label": "FCP", "xpack.synthetics.featureRegistry.syntheticsFeatureName": "Synthetics et Uptime", - "xpack.synthetics.features.app": "Synthetics", "xpack.synthetics.features.elasticManagedLocations": "Emplacements gérés par Elastic activés", "xpack.synthetics.fieldLabels.cls": "Cumulative Layout Shift (CLS)", "xpack.synthetics.fieldLabels.dcl": "Événement DOMContentLoaded (DCL)", @@ -48689,7 +48542,6 @@ "xpack.triggersActionsUI.updateApiKeyConfirmModal.failureMessage": "Impossible de mettre à jour {idsToUpdate, plural, one {la clé} other {les clés}} de l'API", "xpack.triggersActionsUI.updateApiKeyConfirmModal.title": "Mettre à jour la clé d'API", "xpack.triggersActionsUI.urlSyncedAlertsSearchBar.invalidQueryTitle": "Chaîne de requête non valide", - "xpack.triggersActionsUI.useRuleAADFields.errorMessage": "Impossible de charger les champs d'alerte par type de règle", "xpack.upgradeAssistant.app.deniedPrivilegeDescription": "Afin d'utiliser l'assistant de mise à niveau et de résoudre les problèmes de déclassement, vous devez disposer d'un accès permettant de gérer tous les espaces Kibana.", "xpack.upgradeAssistant.app.deniedPrivilegeTitle": "Rôle d'administrateur Kibana requis", "xpack.upgradeAssistant.appTitle": "Assistant de mise à niveau", @@ -48895,7 +48747,6 @@ "xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle": "Appliquer les en-têtes de compatibilité d'API (facultatif)", "xpack.upgradeAssistant.overview.backupStepDescription": "Assurez-vous de disposer d'un snapshot actuel avant d'effectuer des modifications.", "xpack.upgradeAssistant.overview.backupStepTitle": "Sauvegarder vos données", - "xpack.upgradeAssistant.overview.checkUpcomingVersion": "Si vous ne travaillez pas sur la dernière version de la Suite Elastic, utilisez l'assistant de mise à niveau pour effectuer la préparation de la prochaine mise à niveau.", "xpack.upgradeAssistant.overview.cloudBackup.hasSnapshotMessage": "Dernier snapshot créé le {lastBackupTime}.", "xpack.upgradeAssistant.overview.cloudBackup.loadingError": "Une erreur s'est produite lors de la récupération du dernier statut de snapshot", "xpack.upgradeAssistant.overview.cloudBackup.noSnapshotMessage": "Vos données n'ont pas été sauvegardées.", @@ -48970,7 +48821,6 @@ "xpack.upgradeAssistant.overview.verifyChanges.retryButton": "Réessayer", "xpack.upgradeAssistant.overview.viewDiscoverResultsAction": "Analyser les logs dans Discover", "xpack.upgradeAssistant.overview.viewObservabilityResultsAction": "Afficher les logs d'obsolescence dans Logs Explorer", - "xpack.upgradeAssistant.overview.whatsNewLink": "Consulter les points forts de la toute dernière version", "xpack.upgradeAssistant.reindex.reindexPrivilegesErrorBatch": "Vous ne disposez pas des privilèges appropriés pour réindexer \"{indexName}\".", "xpack.upgradeAssistant.status.allDeprecationsResolvedMessage": "Tous les avertissements de déclassement ont été résolus.", "xpack.upgradeAssistant.status.deprecationsUnresolvedMessage": "Les problèmes suivants doivent être résolus avant la mise à niveau : {upgradeIssues}.", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 00e756f7bbfd..6d0ceeed9b77 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -191,14 +191,8 @@ "alertsUIShared.healthCheck.encryptionErrorTitle": "追加の設定が必要です", "alertsUIShared.healthCheck.healthCheck.apiKeysAndEncryptionErrorTitle": "追加の設定が必要です", "alertsUIShared.hooks.useAlertDataView.fetchErrorMessage": "アラートデータビューを読み込めません", - "alertsUIShared.hooks.useFindAlertsQuery.unableToFetchAlertsGroupingAggregations": "アラートグループ集約を取得できません。", "alertsUIShared.hooks.useFindAlertsQuery.unableToFindAlertsQueryMessage": "アラートが見つかりません", "alertsUIShared.hooks.useLoadRuleTypesQuery.unableToLoadRuleTypesMessage": "ルールタイプを読み込めません", - "alertsUIShared.hooks.useRuleAADFields.errorMessage": "ルールタイプごとにアラートフィールドを読み込めません", - "alertsUIShared.licenseCheck.actionTypeDisabledByConfigMessageTitle": "この機能は Kibana の構成で無効になっています。", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseLinkTitle": "ライセンスオプションを表示", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageDescription": "このアクションを再び有効にするには、ライセンスをアップグレードしてください。", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageTitle": "この機能には {minimumLicenseRequired} ライセンスが必要です。", "alertsUIShared.maintenanceWindowCallout.fetchError": "保守時間枠がアクティブであるかどうかを確認できませんでした", "alertsUIShared.maintenanceWindowCallout.fetchErrorDescription": "保守時間枠の実行中は、ルール通知が停止されます。", "alertsUIShared.maintenanceWindowCallout.maintenanceWindowActive": "{categories}ルールの{activeWindowCount, plural, other {保守時間枠}}が実行中です", @@ -2733,11 +2727,7 @@ "discover.advancedSettings.context.tieBreakerFieldsTitle": "タイブレーカーフィールド", "discover.advancedSettings.defaultColumnsText": "デフォルトでDiscoverアプリに表示される列。空の場合、ドキュメントの概要が表示されます。", "discover.advancedSettings.defaultColumnsTitle": "デフォルトの列", - "discover.advancedSettings.disableDocumentExplorer": "ドキュメントエクスプローラーまたはクラシックビュー", - "discover.advancedSettings.disableDocumentExplorerDescription": "クラシックビューではなく、新しい{documentExplorerDocs}を使用するには、このオプションをオフにします。ドキュメントエクスプローラーでは、データの並べ替え、列のサイズ変更、全画面表示といった優れた機能を使用できます。", - "discover.advancedSettings.discover.disableDocumentExplorerDeprecation": "この設定はサポートが終了し、Kibana 9.0では削除されます。", "discover.advancedSettings.discover.fieldStatisticsLinkText": "フィールド統計情報ビュー", - "discover.advancedSettings.discover.maxCellHeightDeprecation": "この設定はサポートが終了し、Kibana 9.0では削除されます。", "discover.advancedSettings.discover.modifyColumnsOnSwitchText": "新しいデータビューで使用できない列を削除します。", "discover.advancedSettings.discover.modifyColumnsOnSwitchTitle": "データビューを変更するときに列を修正", "discover.advancedSettings.discover.multiFieldsLinkText": "マルチフィールド", @@ -2750,13 +2740,10 @@ "discover.advancedSettings.discover.showMultifieldsDescription": "拡張ドキュメントビューに{multiFields}が表示されるかどうかを制御します。ほとんどの場合、マルチフィールドは元のフィールドと同じです。「searchFieldsFromSource」がオフのときにのみこのオプションを使用できます。", "discover.advancedSettings.docTableHideTimeColumnText": "Discover と、ダッシュボードのすべての保存された検索で、「時刻」列を非表示にします。", "discover.advancedSettings.docTableHideTimeColumnTitle": "「時刻」列を非表示", - "discover.advancedSettings.documentExplorerLinkText": "ドキュメントエクスプローラー", "discover.advancedSettings.fieldsPopularLimitText": "最も頻繁に使用されるフィールドのトップNを表示します", "discover.advancedSettings.fieldsPopularLimitTitle": "頻繁に使用されるフィールドの制限", "discover.advancedSettings.maxDocFieldsDisplayedText": "ドキュメント概要でレンダリングされるフィールドの最大数", "discover.advancedSettings.maxDocFieldsDisplayedTitle": "表示される最大ドキュメントフィールド数", - "discover.advancedSettings.params.maxCellHeightText": "表のセルが使用する高さの上限です。切り捨てを無効にするには0に設定します。", - "discover.advancedSettings.params.maxCellHeightTitle": "クラシック表の最大セル高さ", "discover.advancedSettings.params.rowHeightText": "行に追加できる線数。値-1は、コンテンツに合わせて、行の高さを自動的に調整します。値0はコンテンツが1行に表示されます。", "discover.advancedSettings.params.rowHeightTitle": "ドキュメントエクスプローラーの行高さ", "discover.advancedSettings.sampleRowsPerPageText": "ドキュメントテーブルのページごとの行数を制限します。", @@ -2772,7 +2759,6 @@ "discover.alerts.createSearchThreshold": "検索しきい値ルールの作成", "discover.alerts.manageRulesAndConnectors": "ルールとコネクターの管理", "discover.alerts.missedTimeFieldToolTip": "データビューには時間フィールドがありません。", - "discover.backToTopLinkText": "最上部へ戻る。", "discover.badge.readOnly.text": "読み取り専用", "discover.badge.readOnly.tooltip": "検索を保存できません", "discover.context.breadcrumb": "周りのドキュメント", @@ -2781,7 +2767,6 @@ "discover.context.failedToLoadAnchorDocumentErrorDescription": "アンカードキュメントの読み込みに失敗しました。", "discover.context.invalidTieBreakerFiledSetting": "無効なタイブレーカーフィールド設定", "discover.context.loadButtonLabel": "読み込み", - "discover.context.loadingDescription": "読み込み中...", "discover.context.newerDocumentsAriaLabel": "新しいドキュメントの数", "discover.context.newerDocumentsDescription": "新しいドキュメント", "discover.context.newerDocumentsWarning": "アンカーよりも新しいドキュメントは{docCount}件しか見つかりませんでした。", @@ -2818,38 +2803,8 @@ "discover.doc.pageTitle": "1つのドキュメント - #{id}", "discover.doc.somethingWentWrongDescription": "{indexName}が見つかりません。", "discover.doc.somethingWentWrongDescriptionAddon": "インデックスが存在することを確認してください。", - "discover.docExplorerCallout.closeButtonAriaLabel": "閉じる", - "discover.docExplorerCallout.documentExplorer": "ドキュメントエクスプローラー", - "discover.docExplorerCallout.headerMessage": "より効率的な探索方法", - "discover.docExplorerCallout.learnMore": "詳細", - "discover.docExplorerCallout.tryDocumentExplorer": "ドキュメントエクスプローラーを試す", - "discover.docTable.documentsNavigation": "ドキュメントナビゲーション", - "discover.docTable.limitedSearchResultLabel": "{resultCount}件の結果のみが表示されます。検索結果を絞り込みます。", - "discover.docTable.noResultsTitle": "結果が見つかりませんでした", - "discover.docTable.rows": "行", - "discover.docTable.tableHeader.documentHeader": "ドキュメント", - "discover.docTable.tableHeader.moveColumnLeftButtonAriaLabel": "{columnName}列を左に移動", - "discover.docTable.tableHeader.moveColumnLeftButtonTooltip": "列を左に移動", - "discover.docTable.tableHeader.moveColumnRightButtonAriaLabel": "{columnName}列を右に移動", - "discover.docTable.tableHeader.moveColumnRightButtonTooltip": "列を右に移動", - "discover.docTable.tableHeader.removeColumnButtonAriaLabel": "{columnName}列を削除", - "discover.docTable.tableHeader.removeColumnButtonTooltip": "列の削除", - "discover.docTable.tableHeader.sortByColumnAscendingAriaLabel": "{columnName}を昇順に並べ替える", - "discover.docTable.tableHeader.sortByColumnDescendingAriaLabel": "{columnName}を降順に並べ替える", - "discover.docTable.tableHeader.sortByColumnUnsortedAriaLabel": "{columnName}で並べ替えを止める", - "discover.docTable.tableHeader.timeFieldIconTooltip": "このフィールドはイベントの発生時刻を表します。", - "discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} - このフィールドはイベントの発生時刻を表します。", - "discover.docTable.tableRow.detailHeading": "拡張ドキュメント", - "discover.docTable.tableRow.filterForValueButtonAriaLabel": "値でフィルター", - "discover.docTable.tableRow.filterForValueButtonTooltip": "値でフィルター", - "discover.docTable.tableRow.filterOutValueButtonAriaLabel": "値を除外", - "discover.docTable.tableRow.filterOutValueButtonTooltip": "値を除外", - "discover.docTable.tableRow.toggleRowDetailsButtonAriaLabel": "行の詳細を切り替える", - "discover.docTable.tableRow.viewSingleDocumentLinkText": "単一のドキュメントを表示", - "discover.docTable.tableRow.viewSurroundingDocumentsLinkText": "周りのドキュメントを表示", "discover.documentsAriaLabel": "ドキュメント", "discover.docViews.logsOverview.title": "ログ概要", - "discover.docViews.table.scoreSortWarningTooltip": "_scoreの値を取得するには、並べ替える必要があります。", "discover.dropZoneTableLabel": "フィールドを列として表に追加するには、ゾーンをドロップします", "discover.embeddable.inspectorRequestDataTitle": "データ", "discover.embeddable.inspectorRequestDescription": "このリクエストはElasticsearchにクエリーをかけ、検索データを取得します。", @@ -2871,7 +2826,6 @@ "discover.globalSearch.esqlSearchTitle": "ES|QLクエリーを作成", "discover.goToDiscoverButtonText": "Discoverに移動", "discover.grid.tableRow.actionsLabel": "アクション", - "discover.grid.tableRow.esqlDetailHeading": "展開された結果", "discover.grid.tableRow.mobileFlyoutActionsButton": "アクション", "discover.grid.tableRow.moreFlyoutActionsButton": "さらにアクションを表示", "discover.grid.tableRow.viewSingleDocumentLinkLabel": "単一のドキュメントを表示", @@ -2882,7 +2836,6 @@ "discover.hitsCounter.hitsPluralTitle": "{formattedHits} {hits, plural, other {結果}}", "discover.hitsCounter.partialHits": "≥{formattedHits}", "discover.hitsCounter.partialHitsPluralTitle": "≥{formattedHits} {hits, plural, other {結果}}", - "discover.howToSeeOtherMatchingDocumentsDescription": "これらは検索条件に一致した初めの {sampleSize} 件のドキュメントです。他の結果を表示するには検索条件を絞ってください。", "discover.inspectorEsqlRequestDescription": "このリクエストはElasticsearchに対してクエリーを実行し、テーブルの結果を取得します。", "discover.inspectorEsqlRequestTitle": "表", "discover.inspectorRequestDataTitleDocuments": "ドキュメント", @@ -2891,7 +2844,6 @@ "discover.invalidFiltersWarnToast.description": "一部の適用されたフィルターのデータビューID参照は、現在のデータビューとは異なります。", "discover.invalidFiltersWarnToast.title": "別のインデックス参照", "discover.loadingDocuments": "ドキュメントを読み込み中", - "discover.loadingResults": "結果を読み込み中", "discover.localMenu.alertsDescription": "アラート", "discover.localMenu.esqlTooltipLabel": "ES|QLはElasticの強力な新しいパイプクエリ言語です。", "discover.localMenu.fallbackReportTitle": "無題のDiscover検索", @@ -8304,24 +8256,16 @@ "unifiedDocViewer.docView.table.searchPlaceHolder": "検索フィールド名または値", "unifiedDocViewer.docViews.json.jsonTitle": "JSON", "unifiedDocViewer.docViews.table.esqlMultivalueFilteringDisabled": "ES|QLでは、多値フィルタリングはサポートされていません。", - "unifiedDocViewer.docViews.table.filterForFieldPresentButtonAriaLabel": "フィールド表示のフィルター", "unifiedDocViewer.docViews.table.filterForFieldPresentButtonTooltip": "フィールド表示のフィルター", - "unifiedDocViewer.docViews.table.filterForValueButtonAriaLabel": "値でフィルター", "unifiedDocViewer.docViews.table.filterForValueButtonTooltip": "値でフィルター", - "unifiedDocViewer.docViews.table.filterOutValueButtonAriaLabel": "値を除外", "unifiedDocViewer.docViews.table.filterOutValueButtonTooltip": "値を除外", "unifiedDocViewer.docViews.table.ignored.multiValueLabel": "無視された値を含む", "unifiedDocViewer.docViews.table.ignored.singleValueLabel": "無視された値", "unifiedDocViewer.docViews.table.ignoredValuesCanNotBeSearchedWarningMessage": "無視された値は検索できません", "unifiedDocViewer.docViews.table.pinFieldLabel": "フィールドを固定", "unifiedDocViewer.docViews.table.tableTitle": "表", - "unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel": "表の列を切り替える", - "unifiedDocViewer.docViews.table.toggleColumnInTableButtonTooltip": "表の列を切り替える", "unifiedDocViewer.docViews.table.toggleColumnTableButtonTooltip": "表の列を切り替える", - "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip": "メタフィールドの有無でフィルタリングできません", - "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip": "スクリプトフィールドの有無でフィルタリングできません", "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsWarningMessage": "スクリプトフィールドの有無でフィルタリングできません", - "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "インデックスがないフィールドまたは無視された値は検索できません", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedWarningMessage": "インデックスがないフィールドは検索できません", "unifiedDocViewer.docViews.table.unpinFieldLabel": "フィールドを固定解除", "unifiedDocViewer.docViews.table.viewLessButton": "簡易表示", @@ -8331,7 +8275,6 @@ "unifiedDocViewer.fieldActions.filterForValue": "値でフィルター", "unifiedDocViewer.fieldActions.filterOutValue": "値を除外", "unifiedDocViewer.fieldActions.toggleColumn": "表の列を切り替える", - "unifiedDocViewer.fieldChooser.discoverField.actions": "アクション", "unifiedDocViewer.fieldChooser.discoverField.multiField": "複数フィールド", "unifiedDocViewer.fieldChooser.discoverField.multiFieldTooltipContent": "複数フィールドにはフィールドごとに複数の値を入力できます", "unifiedDocViewer.fieldChooser.discoverField.name": "フィールド", @@ -11510,7 +11453,6 @@ "xpack.apm.profiling.callout.dismiss": "閉じる", "xpack.apm.profiling.callout.learnMore": "詳細", "xpack.apm.profiling.callout.title": "{serviceName}サービスを実行しているホストからプロファイリングインサイトを表示しています", - "xpack.apm.profiling.flamegraph.filteredLabel": "サービスのホストからプロファイリングインサイトを表示しています", "xpack.apm.profiling.flamegraph.link": "ユニバーサルプロファイリングFlamegraphに移動", "xpack.apm.profiling.flamegraph.noDataFound": "データが見つかりません", "xpack.apm.profiling.tabs.flamegraph": "Flamegraph", @@ -15017,7 +14959,6 @@ "xpack.csp.fleetIntegration.azureAccountTypeDescriptionLabel": "Azure組織(テナントルートグループ)または単一のAzureサブスクリプションのオンボーディングのいずれかを選択し、この統合を識別するのに役立つ名前と説明を記入します。", "xpack.csp.fleetIntegration.cnvm.additionalChargesCalloutDescription": "このサービスを使用すると、使用量が増えるため、次回のクラウドプロバイダー請求明細書に料金が追加される場合があります。", "xpack.csp.fleetIntegration.cnvm.additionalChargesCalloutTitle": "クラウドプロバイダー請求アカウントへの追加料金。", - "xpack.csp.fleetIntegration.cnvm.configureIntegrationDescription": "監視するクラウドサービスプロバイダー(CSP)を選択し、この統合を識別するのに役立つ名前と説明を記入します", "xpack.csp.fleetIntegration.configureCspmIntegrationDescription": "監視するクラウドサービスプロバイダー(CSP)を選択し、この統合を識別するのに役立つ名前と説明を記入します", "xpack.csp.fleetIntegration.configureKspmIntegrationDescription": "監視するKubernetesクラスタータイプを選択し、この統合を識別するのに役立つ名前と説明を記入します", "xpack.csp.fleetIntegration.editWarning.calloutDescription": "監視するクラウドサービスプロバイダー(CSP)の変更、アカウントの追加、CSPMのデプロイ先(組織か単一のアカウントか)の変更には、新しいCSPM統合を追加してください。", @@ -15084,15 +15025,9 @@ "xpack.csp.grouping.nullGroupTooltip.groupingTitle": "グループ分けの条件", "xpack.csp.integrationDashboard.noFindings.promptTitle": "調査結果評価ステータス", "xpack.csp.integrationDashboard.noFindingsPrompt.promptDescription": "データの収集とインデックス作成を待機しています。このプロセスに想定よりも時間がかかる場合は、サポートまでお問い合わせください", - "xpack.csp.kspmIntegration.aksOption.benchmarkTitle": "CIS AKS", - "xpack.csp.kspmIntegration.aksOption.nameTitle": "AKS", - "xpack.csp.kspmIntegration.aksOption.tooltipContent": "Azure Kubernetes Service - まもなくリリース", "xpack.csp.kspmIntegration.eksOption.benchmarkTitle": "CIS EKS", "xpack.csp.kspmIntegration.eksOption.nameTitle": "EKS", "xpack.csp.kspmIntegration.eksOption.tooltipContent": "Elastic Kubernetes Service", - "xpack.csp.kspmIntegration.gkeOption.benchmarkTitle": "CIS GKE", - "xpack.csp.kspmIntegration.gkeOption.nameTitle": "GKE", - "xpack.csp.kspmIntegration.gkeOption.tooltipContent": "Google Kubernetes Engine - まもなくリリース", "xpack.csp.kspmIntegration.integration.nameTitle": "Kubernetesセキュリティ態勢管理", "xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM", "xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes", @@ -15227,10 +15162,6 @@ "xpack.csp.vulnerabilties.intergationNoInstalledEmptyPrompt.promptDescription": "Elasticのクラウドネイティブ{lineBreak}脆弱性管理(CNVM)統合により、お客様のクラウド資産における脆弱性の可能性を{lineBreak}検出し、修復します。{lineBreak} {learnMore}", "xpack.csp.vulnerabilties.intergationNoInstalledEmptyPrompt.promptTitle": "Elasticのクラウドネイティブ{lineBreak}脆弱性管理", "xpack.csp.vulnMgmtIntegration.awsOption.nameTitle": "Amazon Web Services", - "xpack.csp.vulnMgmtIntegration.azureOption.nameTitle": "Azure", - "xpack.csp.vulnMgmtIntegration.azureOption.tooltipContent": "まもなくリリース", - "xpack.csp.vulnMgmtIntegration.gcpOption.nameTitle": "GCP", - "xpack.csp.vulnMgmtIntegration.gcpOption.tooltipContent": "まもなくリリース", "xpack.customBranding.appName": "カスタムブランディング", "xpack.customBranding.customizedLogoDescription": "ロゴの横のテキストを置換します。画像が200 x 84ピクセル以下で、背景が透明のときに、画像が最適に表示されます。{subscriptionLink}", "xpack.customBranding.customizedLogoLabel": "組織名", @@ -15266,8 +15197,6 @@ "xpack.datasetQuality.degradedDocsColumnTooltip": "データセットにおける{ignoredProperty}プロパティのドキュメントの割合。", "xpack.datasetQuality.degradedDocsQualityDescription": "{quality} -{comparator} {minimimPercentage}%", "xpack.datasetQuality.detail.degradedFieldsSectionTitle": "品質の問題", - "xpack.datasetQuality.details.chartExploreDataInDiscoverText": "Discoverでデータを探索", - "xpack.datasetQuality.details.chartExploreDataInLogsExplorerText": "ログエクスプローラーでデータを探索", "xpack.datasetQuality.details.chartOpenInLensText": "Lensで開く", "xpack.datasetQuality.details.checkBreakdownFieldEcsFailed": "内訳フィールドメタデータを取得できませんでした。", "xpack.datasetQuality.details.datasetCreatedOnText": "作成日時", @@ -15303,7 +15232,6 @@ "xpack.datasetQuality.details.fetchDataStreamDetailsFailed": "データストリーム詳細を取得できませんでした。", "xpack.datasetQuality.details.fetchDataStreamSettingsFailed": "データストリーム設定を読み込めませんでした。", "xpack.datasetQuality.details.fetchIntegrationDashboardsFailed": "統合ダッシュボードを取得できませんでした。", - "xpack.datasetQuality.details.fetchIntegrationsFailed": "{integrationName}統合情報を取得できませんでした。", "xpack.datasetQuality.details.indexTemplateActionText": "インデックステンプレート", "xpack.datasetQuality.details.integrationActionsText": "統合アクション", "xpack.datasetQuality.details.integrationnameText": "統合", @@ -15410,7 +15338,6 @@ "xpack.datasetQuality.types.label": "タイプ", "xpack.dataUsage.charts.ingestedMax": "インジェストされたデータ", "xpack.dataUsage.charts.retainedMax": "ストレージに保持されたデータ", - "xpack.dataUsage.metrics.filter.clearAll": "すべて消去", "xpack.dataUsage.metrics.filter.dataStreams": "データストリーム", "xpack.dataUsage.metrics.filter.emptyMessage": "{filterName}がありません", "xpack.dataUsage.metrics.filter.metricTypes": "メトリックタイプ", @@ -17400,8 +17327,6 @@ "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done": "完了", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton": "キーを生成", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title": "分析APIキーを作成", - "xpack.enterpriseSearch.content.cannotConnect.body": "詳細。", - "xpack.enterpriseSearch.content.cannotConnect.title": "エンタープライズ サーチに接続できません", "xpack.enterpriseSearch.content.conectors.indexHealth": "正常", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.badgeType.connectorClient": "セルフマネージドコネクター", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.badgeType.nativeConnector": "Elasticマネージドコネクター", @@ -17426,7 +17351,6 @@ "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.callout.finishLaterButton.label": "後でデプロイを完了する", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.callout.title": "コネクターを待機しています", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.title": "コネクターのチェックインを待機しています", - "xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.apiKey.title": "API キー", "xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.configuration.title": "構成", "xpack.enterpriseSearch.content.connectors.breadcrumb": "コネクター", "xpack.enterpriseSearch.content.connectors.connectorDetail.configurationTabLabel": "構成", @@ -17456,10 +17380,6 @@ "xpack.enterpriseSearch.content.connectors.deleteModal.delete.crawler.description": "このコネクターを削除しようとしています:", "xpack.enterpriseSearch.content.connectors.deleteModal.syncsWarning.indexNameDescription": "この操作は元に戻すことができません。{connectorName}を入力して確認してください。", "xpack.enterpriseSearch.content.connectors.deleteModal.title": "\"{connectorCount}\"コネクターを削除しますか?", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.description.ariaLabel": "コネクターの説明を編集", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.description.placeholder": "説明を追加", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.name.ariaLabel": "コネクター名を編集", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.name.placeholder": "コネクターに名前を追加", "xpack.enterpriseSearch.content.connectors.overview.connectorErrorCallOut.title": "コネクターでエラーが発生しました", "xpack.enterpriseSearch.content.connectors.overview.connectorIndexDoesntExistCallOut.description": "コネクターは、次回の同期でインデックスを作成します。あるいは、任意の設定とマッピングを使用して、手動でインデックス{indexName}を作成できます。", "xpack.enterpriseSearch.content.connectors.overview.connectorIndexDoesntExistCallOut.title": "付けられたインデックスが存在しません", @@ -17597,8 +17517,6 @@ "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.description": "このコネクターをセルフホスティングしますか?独自のインフラで管理される{link}に変換します。Pythonフレームワークを使用してコードをカスタマイズしたい場合は、このコネクターを変換する必要があります。", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.linkTitle": "セルフマネージドコネクター", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.title": "このコネクターを自己管理", - "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.text": "Elasticマネージドコネクターは、実行中のエンタープライズ サーチインスタンスが必要です。", - "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.title": "実行中のエンタープライズ サーチインスタンスが検出されません", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnectorAdvancedConfiguration.description": "ワンタイム同期をトリガーするか、繰り返し同期スケジュールを設定して、コネクターを確定します。", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnectorAdvancedConfiguration.schedulingButtonLabel": "スケジュールを設定して同期", "xpack.enterpriseSearch.content.indices.configurationConnector.researchConfiguration.connectorDocumentationLinkLabel": "ドキュメント", @@ -17950,7 +17868,6 @@ "xpack.enterpriseSearch.content.playground.breadcrumb": "Playground", "xpack.enterpriseSearch.content.searchIndex.cancelSync.successMessage": "同期が正常にキャンセルされました", "xpack.enterpriseSearch.content.searchIndex.cancelSyncs.successMessage": "同期が正常にキャンセルされました", - "xpack.enterpriseSearch.content.searchIndex.cannotConnect.body": "Elastic Webクローラーにはエンタープライズ サーチが必要です。{link}", "xpack.enterpriseSearch.content.searchIndex.configurationTabLabel": "構成", "xpack.enterpriseSearch.content.searchIndex.connectorErrorCallOut.title": "コネクターでエラーが発生しました", "xpack.enterpriseSearch.content.searchIndex.crawlerConfigurationTabLabel": "構成", @@ -18284,14 +18201,10 @@ "xpack.enterpriseSearch.createConnector..title": "コネクターを作成する", "xpack.enterpriseSearch.createConnector.badgeType.ElasticManaged": "Elasticマネージド", "xpack.enterpriseSearch.createConnector.badgeType.selfManaged": "自己管理", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.BetaBadgeLabel": "ベータ", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.OnlySelfManagedBadgeLabel": "自己管理", "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.placeholder.text": "データソースを選択", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.thechPreviewBadgeLabel": "テクニカルプレビュー", "xpack.enterpriseSearch.createConnector.configurationStep.configurationLabel": "構成", "xpack.enterpriseSearch.createConnector.configurationStep.h4.finishUpLabel": "終了", "xpack.enterpriseSearch.createConnector.configurationStep.p.description": "データを手動で同期したり、繰り返し同期をスケジュールしたり、ドメインを管理したりできます。", - "xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.notAvailableTitle": "このコネクターは、Elasticマネージドコネクターとして利用できません。", "xpack.enterpriseSearch.createConnector.connectorDocsLinkLabel": "コネクター参照", "xpack.enterpriseSearch.createConnector.DeploymentStep.Configuration.description": "次に、Elasticクローラーを構成し、データを同期します。", "xpack.enterpriseSearch.createConnector.DeploymentStep.Configuration.title": "構成", @@ -18366,17 +18279,6 @@ "xpack.enterpriseSearch.enterpriseSearch.setupGuide.videoAlt": "エンタープライズ サーチの基本操作", "xpack.enterpriseSearch.enterpriseSearchCard.cta": "詳細", "xpack.enterpriseSearch.entSearch.productCardDescription": "よりシンプルで使いやすく、ビジネスに特化した検索エクスペリエンスを提供するスタンドアロンアプリケーション。", - "xpack.enterpriseSearch.errorConnectingCallout.setupGuideCta": "セットアップガイドを確認", - "xpack.enterpriseSearch.errorConnectingCallout.title": "エンタープライズ サーチに接続できません", - "xpack.enterpriseSearch.errorConnectingState.cloudErrorMessage": "クラウドデプロイのエンタープライズ サーチノードが実行中ですか?{deploymentSettingsLink}", - "xpack.enterpriseSearch.errorConnectingState.cloudErrorMessageLinkText": "デプロイ設定を確認", - "xpack.enterpriseSearch.errorConnectingState.description1": "次のエラーのため、ホストURL {enterpriseSearchUrl}では、エンタープライズ サーチへの接続を確立できません。", - "xpack.enterpriseSearch.errorConnectingState.description2": "ホストURLが{configFile}で正しく構成されていることを確認してください。", - "xpack.enterpriseSearch.errorConnectingState.description3": "エンタープライズ サーチサーバーが応答していることを確認してください。", - "xpack.enterpriseSearch.errorConnectingState.setupGuideCta": "セットアップガイドを確認", - "xpack.enterpriseSearch.errorConnectingState.title": "接続できません", - "xpack.enterpriseSearch.errorConnectingState.troubleshootAuth": "ユーザー認証を確認してください。", - "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthMessage": "管理者に連絡して、エンタープライズ サーチのロールマッピングを設定し、エンタープライズ サーチへのアクセスを許可してください", "xpack.enterpriseSearch.exampleConnectorLabel": "例", "xpack.enterpriseSearch.finishUpStep.euiButton.viewInDiscoverLabel": "Discoverに表示", "xpack.enterpriseSearch.getConnectorTypeBadge.connectorClientBadgeLabel": "セルフマネージド", @@ -18523,9 +18425,6 @@ "xpack.enterpriseSearch.navigation.contentPlaygroundLinkLabel": "Playground", "xpack.enterpriseSearch.navigation.contentWebcrawlersLinkLabel": "Webクローラー", "xpack.enterpriseSearch.navigation.relevanceInferenceEndpointsLinkLabel": "推論エンドポイント", - "xpack.enterpriseSearch.noEntSearch.noCrawler": "Elastic Webクローラーはエンタープライズ サーチなしでは利用できません。", - "xpack.enterpriseSearch.noEntSearch.setupGuideCta": "セットアップガイドを確認", - "xpack.enterpriseSearch.noEntSearchConfigured.title": "エンタープライズ サーチが構成されていません", "xpack.enterpriseSearch.notFound.action1": "ダッシュボードに戻す", "xpack.enterpriseSearch.notFound.action2": "サポートに問い合わせる", "xpack.enterpriseSearch.notFound.description": "お探しのページは見つかりませんでした。", @@ -18793,7 +18692,6 @@ "xpack.enterpriseSearch.searchApplications.searchApplication.indices.searchPlaceholder": "インデックスのフィルター", "xpack.enterpriseSearch.searchApplications.searchApplication.indices.someUnknownIndicesCallout.description": "この検索アプリケーションからは一部のデータに接続できない場合があります。影響を受けるインデックスで保留中の処理またはエラーがあるかどうかを確認するか、この検索アプリケーションで使用されないインデックスを削除してください。", "xpack.enterpriseSearch.searchApplications.searchApplication.indices.someUnknownIndicesCallout.title": "一部のインデックスが使用できません。", - "xpack.enterpriseSearch.searchApplications.searchApplication.notFound.action1": "検索アプリケーションに戻る", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.button": "不一致を表示", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.description": "スキーマフィールド型の競合は、ソースインデックスに直接移動し、競合するフィールドのフィールド型を他のソースインデックスのフィールド型と一致するように更新することで解決できます。", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.title": "フィールドマッピングに潜在的な問題が見つかりました", @@ -19006,10 +18904,6 @@ "xpack.enterpriseSearch.vectorSearch.guide.query.title": "ベクトル検索を実行", "xpack.enterpriseSearch.vectorSearch.navTitle": "ベクトル検索", "xpack.enterpriseSearch.vectorSearch.productName": "ベクトル検索", - "xpack.enterpriseSearch.versionMismatch.body": "Kibanaとエンタープライズ サーチのバージョンが一致しません。エンタープライズ サーチにアクセスするには、各サービスで同じメジャーおよびマイナーバージョンを使用してください。", - "xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText": "エンタープライズ サーチバージョン:{enterpriseSearchVersion}", - "xpack.enterpriseSearch.versionMismatch.kibanaVersionText": "Kibanaバージョン:{kibanaVersion}", - "xpack.enterpriseSearch.versionMismatch.title": "互換性のないバージョンエラー", "xpack.enterpriseSearch.welcomeBanner.header.greeting.customTitle": "👋 こんにちは、{name}さん!", "xpack.enterpriseSearch.welcomeBanner.header.greeting.defaultTitle": "👋 こんにちは", "xpack.enterpriseSearch.welcomeBanner.header.title": "Elasticsearchにデータを追加し、検索、ベクトル化、可視化", @@ -20464,7 +20358,6 @@ "xpack.fleet.agentPolicyForm.newAgentPolicyFieldLabel": "新しいエージェントポリシー名", "xpack.fleet.agentPolicyForm.outputOptionDisabledTypeNotSupportedText": "Fleet Server、Synthetics、APMではエージェント統合の{outputType}出力はサポートされていません。", "xpack.fleet.agentPolicyForm.outputOptionDisableOutputTypeText": "Fleet Server、Synthetics、APMではエージェント統合の{outputType}出力はサポートされていません。", - "xpack.fleet.agentPolicyForm.spaceDescription": "このポリシーに1つ以上のスペースを選択するか、新しいスペースを作成します。{link}", "xpack.fleet.agentPolicyForm.spaceFieldLabel": "スペース", "xpack.fleet.agentPolicyForm.systemMonitoringText": "システムログとメトリックの収集", "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "これにより、{system}統合も追加され、システムログとメトリックを収集します。", @@ -22556,8 +22449,6 @@ "xpack.idxMgmt.enrichPolicyCreate.configurationStep.queryLabel": "クエリー(任意)", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeOption": "Range", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeTypePopOver": "{type}は、番号、日付、またはIPアドレスの範囲と一致します。", - "xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesLabel": "ソースインデックス", - "xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesRequiredError": "ソースインデックスが最低1つ必要です。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.typeRequiredError": "ポリシータイプ値が必要です。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.typeTitlePopOver": "どのようにデータを受信ドキュメントに一致させるかを決定します。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.uploadFileLink": "ファイルをアップロード", @@ -22640,10 +22531,6 @@ "xpack.idxMgmt.home.componentTemplates.list.loadingMessage": "コンポーネントテンプレートを読み込んでいます…", "xpack.idxMgmt.home.componentTemplatesTabTitle": "コンポーネントテンプレート", "xpack.idxMgmt.home.dataStreamsTabTitle": "データストリーム", - "xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesDescription": "権限を確認中…", - "xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesErrorMessage": "サーバーからユーザー特権を取得中にエラーが発生。", - "xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeDescription": "エンリッチポリシーを使用するには、以下のクラスター権限が必要です:{missingPrivileges}。", - "xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeTitle": "必要なエンリッチ権限を管理", "xpack.idxMgmt.home.enrichPoliciesTabTitle": "エンリッチポリシー", "xpack.idxMgmt.home.idxMgmtDescription": "Elasticsearch インデックスを個々に、または一斉に更新します。{learnMoreLink}", "xpack.idxMgmt.home.idxMgmtDocsLinkText": "インデックス管理ドキュメント", @@ -23294,7 +23181,6 @@ "xpack.idxMgmt.mappingsEditor.parameters.validations.fieldDataFrequency.numberGreaterThanOneErrorMessage": "値は1よりも大きい値でなければなりません。", "xpack.idxMgmt.mappingsEditor.parameters.validations.greaterThanZeroErrorMessage": "スケーリングファクターは0よりも大きくなくてはなりません。", "xpack.idxMgmt.mappingsEditor.parameters.validations.ignoreAboveIsRequiredErrorMessage": "文字数制限が必要です。", - "xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage": "推論IDは必須です。", "xpack.idxMgmt.mappingsEditor.parameters.validations.localeFieldRequiredErrorMessage": "ロケールを指定します。", "xpack.idxMgmt.mappingsEditor.parameters.validations.maxInputLengthFieldRequiredErrorMessage": "最大入力長さを指定します。", "xpack.idxMgmt.mappingsEditor.parameters.validations.nameIsRequiredErrorMessage": "フィールドに名前を付けます。", @@ -23700,7 +23586,6 @@ "xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableExplanationText": "各インデックスシャードのセグメント数を減らし、削除したドキュメントをクリーンアップします。", "xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableText": "強制結合", "xpack.indexLifecycleMgmt.editPolicy.forcemerge.numberOfSegmentsRequiredError": "セグメント数の評価が必要です。", - "xpack.indexLifecycleMgmt.editPolicy.formErrorsMessage": "このページのエラーを修正してください。", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.activateFrozenPhaseSwitchLabel": "フローズンフェーズをアクティブ化", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.frozenPhaseDescription": "長期間保持する場合はデータをフローズンティアに移動します。フローズンティアはデータを格納し、検索することもできる最も費用対効果が高い方法です。", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.frozenPhaseTitle": "フローズンフェーズ", @@ -26156,7 +26041,6 @@ "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "エンティティで最後に受信したデータのタイムスタンプ(entity.lastSeenTimestamp)", "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "型", "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "エンティティのタイプ(entity.type)", - "xpack.inventory.entityActions.discoverLink": "Discoverで開く", "xpack.inventory.featureRegistry.inventoryFeatureName": "インベントリ", "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "アクティブアラート", "xpack.inventory.inventoryLinkTitle": "インベントリ", @@ -26337,7 +26221,6 @@ "xpack.lens.app.createVisualizationLabel": "ES|QL", "xpack.lens.app.docLoadingError": "保存されたドキュメントの保存中にエラーが発生", "xpack.lens.app.editLensEmbeddableLabel": "ビジュアライゼーションを編集", - "xpack.lens.app.editVisualizationLabel": "{lang}ビジュアライゼーションを編集", "xpack.lens.app.exploreDataInDiscover": "Discoverで探索", "xpack.lens.app.exploreDataInDiscoverDrilldown": "Discoverで開く", "xpack.lens.app.exploreDataInDiscoverDrilldown.newTabConfig": "新しいタブで開く", @@ -26496,14 +26379,6 @@ "xpack.lens.editorFrame.suggestionPanelTitle": "提案", "xpack.lens.editorFrame.tooManyDimensionsSingularWarningLabel": "{dimensionsTooMany, plural, other {{dimensionsTooMany} ディメンション}}を削除してください", "xpack.lens.editorFrame.workspaceLabel": "ワークスペース", - "xpack.lens.embeddable.failure": "ビジュアライゼーションを表示できませんでした", - "xpack.lens.embeddable.featureBadge.iconDescription": "{count}個のビジュアライゼーション{count, plural, other {修飾子}}", - "xpack.lens.embeddable.fixErrors": "Lensエディターで編集し、エラーを修正", - "xpack.lens.embeddable.legacyURLConflict.shortMessage": "URLの競合が発生しました", - "xpack.lens.embeddable.missingTimeRangeParam.longMessage": "指定された構成にはtimeRangeプロパティが必須です", - "xpack.lens.embeddable.missingTimeRangeParam.shortMessage": "timeRangeプロパティがありません", - "xpack.lens.embeddable.moreErrors": "Lensエディターで編集すると、エラーの詳細が表示されます", - "xpack.lens.embeddableDisplayName": "Lens", "xpack.lens.endValue.nearest": "最も近い", "xpack.lens.endValue.none": "非表示", "xpack.lens.endValue.zero": "ゼロ", @@ -26511,6 +26386,8 @@ "xpack.lens.endValueDescription.none": "系列をグラフの端まで拡張しない", "xpack.lens.endValueDescription.zero": "系列をゼロとしてグラフの端まで拡張", "xpack.lens.experimentalLabel": "テクニカルプレビュー", + "xpack.lens.failure": "ビジュアライゼーションを表示できませんでした", + "xpack.lens.featureBadge.iconDescription": "{count}個のビジュアライゼーション{count, plural, other {修飾子}}", "xpack.lens.fieldFormats.longSuffix.d": "日単位", "xpack.lens.fieldFormats.longSuffix.h": "時間単位", "xpack.lens.fieldFormats.longSuffix.m": "分単位", @@ -26530,6 +26407,7 @@ "xpack.lens.fittingFunctionsTitle.lookahead": "次へ", "xpack.lens.fittingFunctionsTitle.none": "非表示", "xpack.lens.fittingFunctionsTitle.zero": "ゼロ", + "xpack.lens.fixErrors": "Lensエディターで編集し、エラーを修正", "xpack.lens.formula.disableWordWrapLabel": "単語の折り返しを無効にする", "xpack.lens.formula.editorHelpInlineHideLabel": "関数リファレンスを非表示", "xpack.lens.formula.editorHelpInlineHideToolTip": "関数リファレンスを非表示", @@ -27012,7 +26890,7 @@ "xpack.lens.legacyMetric.titlePositions.bottom": "一番下", "xpack.lens.legacyMetric.titlePositions.top": "トップ", "xpack.lens.legacyUrlConflict.objectNoun": "Lensビジュアライゼーション", - "xpack.lens.lensSavedObjectLabel": "Lensビジュアライゼーション", + "xpack.lens.legacyURLConflict.shortMessage": "URLの競合が発生しました", "xpack.lens.lineCurve.smooth": "平滑化", "xpack.lens.lineCurve.step": "手順", "xpack.lens.lineCurve.straight": "直線", @@ -27067,11 +26945,14 @@ "xpack.lens.metric.supportingVisualization.none": "なし", "xpack.lens.metric.supportingVisualization.trendline": "折れ線", "xpack.lens.metric.timeField": "時間フィールド", + "xpack.lens.missingTimeRangeParam.longMessage": "指定された構成にはtimeRangeプロパティが必須です", + "xpack.lens.missingTimeRangeParam.shortMessage": "timeRangeプロパティがありません", "xpack.lens.modalTitle.revertAnnotationGroupTitle": "\"{title}\"の変更を元に戻しますか?", "xpack.lens.modalTitle.title.clearVis": "ビジュアライゼーションレイヤーを消去しますか?", "xpack.lens.modalTitle.title.deleteAnnotations": "注釈グループを削除しますか?", "xpack.lens.modalTitle.title.deleteReferenceLines": "基準線レイヤーを削除しますか?", "xpack.lens.modalTitle.title.deleteVis": "ビジュアライゼーションレイヤーを削除しますか?", + "xpack.lens.moreErrors": "Lensエディターで編集すると、エラーの詳細が表示されます", "xpack.lens.pageTitle": "Lens", "xpack.lens.paletteHeatmapGradient.label": "色", "xpack.lens.paletteMetricGradient.label": "色", @@ -35993,15 +35874,6 @@ "xpack.searchInferenceEndpoints.actions.endpointAddedSuccess": "エンドポイントが追加されました", "xpack.searchInferenceEndpoints.actions.endpointAddedSuccessDescription": "インターフェースエンドポイント\"{endpointId}\"が追加されました。", "xpack.searchInferenceEndpoints.actions.trainedModelsStatGatherFailed": "学習済みモデル統計情報を取得できませんでした", - "xpack.searchInferenceEndpoints.addEmptyPrompt.createFirstInferenceEndpointDescription": "推論エンドポイントを使用すると、サードパーティサービスが提供するNLPモデルや、ELSERやE5などのElasticの組み込みモデルを使用して推論タスクを実行できます。Create Inference APIを使用して、テキスト埋め込み、入力、再ランク付けなどのタスクを設定します。", - "xpack.searchInferenceEndpoints.addEmptyPrompt.e5Description": "E5は、密ベクトル表現を使用して、多言語のセマンティック検索を可能にするサードパーティNLPモデルです。", - "xpack.searchInferenceEndpoints.addEmptyPrompt.e5Title": "E5 Multilingual", - "xpack.searchInferenceEndpoints.addEmptyPrompt.elserDescription": "ELSERは、英語でのセマンティック検索向けにElasticの疎ベクトルNLPモデルです。", - "xpack.searchInferenceEndpoints.addEmptyPrompt.elserTitle": "ELSER", - "xpack.searchInferenceEndpoints.addEmptyPrompt.learnHowToCreateInferenceEndpoints": "推論エンドポイントを作成する方法", - "xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithE5": "E5 Multilingualを使用したセマンティック検索", - "xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithElser": "ELSERを使用したセマンティック検索", - "xpack.searchInferenceEndpoints.addEmptyPrompt.startWithPreparedEndpointsLabel": "組み込まれたNLPモデルの詳細:", "xpack.searchInferenceEndpoints.allInferenceEndpoints.description": "推論エンドポイントは、Elasticsearchにおける機械学習モデルのデプロイと管理を合理化します。独自のエンドポイントを使用してNLPタスクを設定および管理し、AIを活用した検索を構築します。", "xpack.searchInferenceEndpoints.apiDocumentationLink": "APIドキュメント", "xpack.searchInferenceEndpoints.cancel": "キャンセル", @@ -37196,8 +37068,6 @@ "xpack.securitySolution.assistant.quickPrompts.alertSummarizationTitle": "アラート要約", "xpack.securitySolution.assistant.quickPrompts.AutomationPrompt": "ログやイベントの収集には、どのFleet対応Elasticエージェント統合を使用すべきですか。", "xpack.securitySolution.assistant.quickPrompts.AutomationTitle": "エージェント統合のアドバイス", - "xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationPrompt": "Elasticセキュリティのエキスパートユーザーとして、以下のユースケースを検出するための正確で有効なESQLクエリを作成してください。回答は、Elasticセキュリティのタイムラインまたは検出ルールですぐに使用できるように書式設定してください。答えに時間をかけて、求められているすべての機能について、あなたの知識をよく確認してください。ES|QLの回答は、特に、あなたの個人的な知識で利用可能なもののみを答えてください。クエリが不正確であることは許容できません。Elastic Common SchemaとElasticエージェントを使用していると仮定します。回答がマークダウンの独立したコードブロックとして簡単にコピーできるように書式設定されていることを確認してください。", - "xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationTitle": "ES|QLクエリ生成", "xpack.securitySolution.assistant.quickPrompts.ruleCreationPrompt": "Elasticセキュリティのエキスパートユーザーとして、以下のユースケースを検出するための正確で有効なEQLクエリを作成してください。回答は、Elasticセキュリティのタイムラインまたは検出ルールですぐに使用できるように書式設定してください。そのユースケースに対応するルールがすでにElasticセキュリティに組み込まれている場合、または類似のルールが組み込まれている場合は、そのルールへのリンクと説明を入力してください。", "xpack.securitySolution.assistant.quickPrompts.ruleCreationTitle": "クエリ生成", "xpack.securitySolution.assistant.quickPrompts.splQueryConversionPrompt": "以前のSIEMプラットフォームから次のクエリを受け取りました。Elasticセキュリティのエキスパートユーザーとして、同等のElastic EQLを提案してください。すぐにそれをElasticのセキュリティタイムラインにコピーできます。", @@ -38033,10 +37903,6 @@ "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlQueryFieldRequiredError": "EQLクエリは必須です。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionDisableText": "EQLシーケンスクエリでは抑制はサポートされていません。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionValidationText": "{EQL_SEQUENCE_SUPPRESSION_DISABLE_TOOLTIP} EQLクエリを非シーケンスクエリに変更するか、抑制フィールドを削除してください。", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoAriaLabel": "ヘルプポップオーバーを開く", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipContent": "ES|QL ルールの使用を開始するには、{createEsqlRuleTypeLink}を確認してください。", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipLink": "ドキュメンテーション", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlQueryLabel": "ES|QLクエリ", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldAnomalyThresholdLabel": "異常スコアしきい値", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldMachineLearningJobIdLabel": "機械学習ジョブ", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldQuerBarLabel": "カスタムクエリー", @@ -38140,10 +38006,6 @@ "xpack.securitySolution.detectionEngine.esqlRuleType.eqlSearchRequestDescription": "すべての一致を検索するEQL要求", "xpack.securitySolution.detectionEngine.esqlRuleType.esqlSearchRequestDescription": "すべての一致を検索するES|QL要求", "xpack.securitySolution.detectionEngine.esqlRuleType.findSourceDocumentsRequestDescription": "ES|QLクエリが集約できないときにソースドキュメントを取得", - "xpack.securitySolution.detectionEngine.esqlValidation.errorMessage": "ES|QLの検証エラー:\"{message}\"", - "xpack.securitySolution.detectionEngine.esqlValidation.missingIdFieldInQueryError": "STATS...BY関数を使用しないクエリ(非集約クエリ)は、ソースコマンドの後にmetadata _id、_version、_index演算子を含める必要があります。例:FROM logs* metadata _id, _version, _index.さらに、メタデータプロパティ(_id、_version、_index)をクエリレスポンスで返さなければなりません。", - "xpack.securitySolution.detectionEngine.esqlValidation.missingMetadataOperatorInQueryError": "STATS...BY関数を使用しないクエリ(非集約クエリ)は、ソースコマンドの後にmetadata _id、_version、_index演算子を含める必要があります。例:FROM logs* metadata _id, _version, _index.", - "xpack.securitySolution.detectionEngine.esqlValidation.unknownError": "ES|QLの検証中の不明なエラー", "xpack.securitySolution.detectionEngine.executionRunType.backfill": "手動", "xpack.securitySolution.detectionEngine.executionRunType.standard": "スケジュール済み", "xpack.securitySolution.detectionEngine.goToDocumentationButton": "ドキュメンテーションを表示", @@ -40415,7 +40277,6 @@ "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.noPermissionTitle": "CSVアップロードを実行する十分なインデックス権限がありません", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.resultsStepTitle": "結果", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.selectFileStepTitle": "ファイルを選択", - "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.subTitle": "テキストファイルを使用してエンティティをインポート", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unavailable": "アセット重要度CSVファイルアップロード機能が利用できません。", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unsupportedFileTypeError": "無効なファイル形式が選択されました。{supportedFileExtensions}ファイルを選択して再試行してください。", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.uploadFileSizeLimit": "最大ファイルサイズ:{maxFileSize}", @@ -40457,7 +40318,6 @@ "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.clearAllEntities": "すべてのエンティティを消去", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.close": "閉じる", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.title": "エンティティデータを消去しますか?", - "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntityData": "すべての抽出されたエンティティデータをストアから削除します。このアクションにより、永続化されたユーザーおよびホストレコードが完全に削除され、データは分析で使用できなくなります。注意して続行してください。この操作は元に戻せません。この処理では、ソースデータ、エンティティリスクスコア、アセット重要度割り当ては削除されません。", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.featureFlagDisabled": "エンティティストア機能を利用できません", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.subTitle": "システムのホストとユーザーを包括的に監視できます。", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.title": "エンティティストア", @@ -44866,7 +44726,6 @@ "xpack.spaces.management.spacesGridPage.editSpaceActionDescription": "{spaceName} を編集。", "xpack.spaces.management.spacesGridPage.editSpaceActionName": "編集", "xpack.spaces.management.spacesGridPage.errorTitle": "スペースの読み込みエラー", - "xpack.spaces.management.spacesGridPage.identifierColumnName": "識別子", "xpack.spaces.management.spacesGridPage.loadingTitle": "読み込み中…", "xpack.spaces.management.spacesGridPage.searchPlaceholder": "検索", "xpack.spaces.management.spacesGridPage.solutionColumnName": "ソリューションビュー", @@ -46275,7 +46134,6 @@ "xpack.synthetics.failedStep.label": "失敗したステップ", "xpack.synthetics.fcp.label": "FCP", "xpack.synthetics.featureRegistry.syntheticsFeatureName": "Syntheticsとアップタイム", - "xpack.synthetics.features.app": "Synthetics", "xpack.synthetics.features.elasticManagedLocations": "Elasticで管理されている場所が有効です", "xpack.synthetics.fieldLabels.cls": "累積レイアウト変更(CLS)", "xpack.synthetics.fieldLabels.dcl": "DOMContentLoadedイベント(DCL)", @@ -48644,8 +48502,7 @@ "xpack.triggersActionsUI.updateApiKeyConfirmModal.description": "古いAPI {idsToUpdate, plural, other {キー}}は回復できません", "xpack.triggersActionsUI.updateApiKeyConfirmModal.failureMessage": "API {idsToUpdate, plural, other {キー}}を更新できませんでした", "xpack.triggersActionsUI.updateApiKeyConfirmModal.title": "APIキーの更新", - "xpack.triggersActionsUI.urlSyncedAlertsSearchBar.invalidQueryTitle": "無効なクエリー文字列", - "xpack.triggersActionsUI.useRuleAADFields.errorMessage": "ルールタイプごとにアラートフィールドを読み込めません", + "xpack.triggersActionsUI.urlSyncedAlertsSearchBar.invalidQueryTitle": "無効なクエリ文字列", "xpack.upgradeAssistant.app.deniedPrivilegeDescription": "アップグレードアシスタントを使用して、廃止予定の問題を解決するには、すべてのKibanaスペースを管理するためのアクセス権が必要です。", "xpack.upgradeAssistant.app.deniedPrivilegeTitle": "Kibana管理者ロールが必要です", "xpack.upgradeAssistant.appTitle": "アップグレードアシスタント", @@ -48852,7 +48709,6 @@ "xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle": "API互換性ヘッダーを適用(オプション)", "xpack.upgradeAssistant.overview.backupStepDescription": "変更を行う前に、現在のスナップショットがあることを確認してください。", "xpack.upgradeAssistant.overview.backupStepTitle": "データをバックアップ", - "xpack.upgradeAssistant.overview.checkUpcomingVersion": "最新バージョンのElastic Stackを使用していない場合は、アップグレードアシスタンスを使用して、次回のアップグレードを準備してください。", "xpack.upgradeAssistant.overview.cloudBackup.hasSnapshotMessage": "前回のスナップショットは{lastBackupTime}に作成されました。", "xpack.upgradeAssistant.overview.cloudBackup.loadingError": "最新のスナップショットステータスの取得中にエラーが発生しました", "xpack.upgradeAssistant.overview.cloudBackup.noSnapshotMessage": "データはバックアップされていません。", @@ -48927,7 +48783,6 @@ "xpack.upgradeAssistant.overview.verifyChanges.retryButton": "再試行", "xpack.upgradeAssistant.overview.viewDiscoverResultsAction": "Discoverでログを分析", "xpack.upgradeAssistant.overview.viewObservabilityResultsAction": "Logs Explorerで廃止予定ログを表示", - "xpack.upgradeAssistant.overview.whatsNewLink": "最新リリースのハイライトを確認", "xpack.upgradeAssistant.reindex.reindexPrivilegesErrorBatch": "「{indexName}」に再インデックスするための権限が不十分です。", "xpack.upgradeAssistant.status.allDeprecationsResolvedMessage": "すべての廃止予定の警告が解決されました。", "xpack.upgradeAssistant.status.deprecationsUnresolvedMessage": "アップグレード前に次の問題を解決する必要があります:{upgradeIssues}。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 3c5862018077..9c52ac8a5101 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -191,14 +191,8 @@ "alertsUIShared.healthCheck.encryptionErrorTitle": "需要其他设置", "alertsUIShared.healthCheck.healthCheck.apiKeysAndEncryptionErrorTitle": "需要其他设置", "alertsUIShared.hooks.useAlertDataView.fetchErrorMessage": "无法加载告警数据视图", - "alertsUIShared.hooks.useFindAlertsQuery.unableToFetchAlertsGroupingAggregations": "无法提取告警分组聚合", "alertsUIShared.hooks.useFindAlertsQuery.unableToFindAlertsQueryMessage": "无法找到告警", "alertsUIShared.hooks.useLoadRuleTypesQuery.unableToLoadRuleTypesMessage": "无法加载规则类型", - "alertsUIShared.hooks.useRuleAADFields.errorMessage": "无法按规则类型加载告警字段", - "alertsUIShared.licenseCheck.actionTypeDisabledByConfigMessageTitle": "此功能已由 Kibana 配置禁用。", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseLinkTitle": "查看许可证选项", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageDescription": "要重新启用此操作,请升级您的许可证。", - "alertsUIShared.licenseCheck.actionTypeDisabledByLicenseMessageTitle": "此功能需要{minimumLicenseRequired}许可证。", "alertsUIShared.maintenanceWindowCallout.fetchError": "无法检查维护窗口是否处于活动状态", "alertsUIShared.maintenanceWindowCallout.fetchErrorDescription": "维护窗口正在运行时会停止规则通知。", "alertsUIShared.maintenanceWindowCallout.maintenanceWindowActive": "{activeWindowCount, plural, other {维护窗口正}}针对 {categories} 规则运行", @@ -2694,11 +2688,7 @@ "discover.advancedSettings.context.tieBreakerFieldsTitle": "平分决胜字段", "discover.advancedSettings.defaultColumnsText": "Discover 应用中默认显示的列。如果为空,将显示文档摘要。", "discover.advancedSettings.defaultColumnsTitle": "默认列", - "discover.advancedSettings.disableDocumentExplorer": "Document Explorer 或经典视图", - "discover.advancedSettings.disableDocumentExplorerDescription": "要使用新的 {documentExplorerDocs},而非经典视图,请关闭此选项。Document Explorer 提供了更合理的数据排序、可调整大小的列和全屏视图。", - "discover.advancedSettings.discover.disableDocumentExplorerDeprecation": "此设置已过时,将在 Kibana 9.0 中移除。", "discover.advancedSettings.discover.fieldStatisticsLinkText": "字段统计信息视图", - "discover.advancedSettings.discover.maxCellHeightDeprecation": "此设置已过时,将在 Kibana 9.0 中移除。", "discover.advancedSettings.discover.modifyColumnsOnSwitchText": "移除新数据视图中不存在的列。", "discover.advancedSettings.discover.modifyColumnsOnSwitchTitle": "在更改数据视图时修改列", "discover.advancedSettings.discover.multiFieldsLinkText": "多字段", @@ -2711,13 +2701,10 @@ "discover.advancedSettings.discover.showMultifieldsDescription": "控制 {multiFields} 是否显示在展开的文档视图中。多数情况下,多字段与原始字段相同。此选项仅在 `searchFieldsFromSource` 关闭时可用。", "discover.advancedSettings.docTableHideTimeColumnText": "在 Discover 中和仪表板上的所有已保存搜索中隐藏'时间'列。", "discover.advancedSettings.docTableHideTimeColumnTitle": "隐藏'时间'列", - "discover.advancedSettings.documentExplorerLinkText": "Document Explorer", "discover.advancedSettings.fieldsPopularLimitText": "要显示的排名前 N 最常见字段", "discover.advancedSettings.fieldsPopularLimitTitle": "常见字段限制", "discover.advancedSettings.maxDocFieldsDisplayedText": "在文档摘要中渲染的最大字段数目", "discover.advancedSettings.maxDocFieldsDisplayedTitle": "显示的最大文档字段数", - "discover.advancedSettings.params.maxCellHeightText": "表单元格应占用的最大高度。设置为 0 可禁用截断。", - "discover.advancedSettings.params.maxCellHeightTitle": "经典表中的最大单元格高度", "discover.advancedSettings.params.rowHeightText": "一行中允许的文本行数。值为 -1 时,会自动调整行高以适应内容。值为 0 时,会在单文本行中显示内容。", "discover.advancedSettings.params.rowHeightTitle": "Document Explorer 中的行高", "discover.advancedSettings.sampleRowsPerPageText": "限制文档表中每页的行数。", @@ -2733,7 +2720,6 @@ "discover.alerts.createSearchThreshold": "创建搜索阈值规则", "discover.alerts.manageRulesAndConnectors": "管理规则和连接器", "discover.alerts.missedTimeFieldToolTip": "数据视图没有时间字段。", - "discover.backToTopLinkText": "返回顶部。", "discover.badge.readOnly.text": "只读", "discover.badge.readOnly.tooltip": "无法保存搜索", "discover.context.breadcrumb": "周围文档", @@ -2742,7 +2728,6 @@ "discover.context.failedToLoadAnchorDocumentErrorDescription": "无法加载定位点文档。", "discover.context.invalidTieBreakerFiledSetting": "无效的平分决胜字段设置", "discover.context.loadButtonLabel": "加载", - "discover.context.loadingDescription": "正在加载……", "discover.context.newerDocumentsAriaLabel": "较新文档数目", "discover.context.newerDocumentsDescription": "较新文档", "discover.context.newerDocumentsWarning": "仅可以找到 {docCount} 个比定位标记新的文档。", @@ -2779,34 +2764,8 @@ "discover.doc.pageTitle": "单个文档 - #{id}", "discover.doc.somethingWentWrongDescription": "{indexName} 缺失。", "discover.doc.somethingWentWrongDescriptionAddon": "请确保索引存在。", - "discover.docExplorerCallout.bodyMessage": "使用 {documentExplorer} 快速排序、选择和比较数据,调整列大小并以全屏方式查看文档。", - "discover.docExplorerCallout.closeButtonAriaLabel": "关闭", - "discover.docExplorerCallout.documentExplorer": "Document Explorer", - "discover.docExplorerCallout.headerMessage": "更好的浏览方式", - "discover.docExplorerCallout.learnMore": "了解详情", - "discover.docExplorerCallout.tryDocumentExplorer": "试用 Document Explorer", - "discover.docTable.documentsNavigation": "文档导航", - "discover.docTable.limitedSearchResultLabel": "仅限于 {resultCount} 个结果。优化您的搜索。", - "discover.docTable.noResultsTitle": "找不到结果", - "discover.docTable.rows": "行", - "discover.docTable.rowsPerPage": "每页行数:{pageSize}", - "discover.docTable.tableHeader.documentHeader": "文档", - "discover.docTable.tableHeader.moveColumnLeftButtonTooltip": "向左移动列", - "discover.docTable.tableHeader.moveColumnRightButtonTooltip": "向右移动列", - "discover.docTable.tableHeader.removeColumnButtonTooltip": "移除列", - "discover.docTable.tableHeader.timeFieldIconTooltip": "此字段表示事件发生的时间。", - "discover.docTable.tableHeader.timeFieldIconTooltipAriaLabel": "{timeFieldName} - 此字段表示事件发生的时间。", - "discover.docTable.tableRow.detailHeading": "已展开文档", - "discover.docTable.tableRow.filterForValueButtonAriaLabel": "筛留值", - "discover.docTable.tableRow.filterForValueButtonTooltip": "筛留值", - "discover.docTable.tableRow.filterOutValueButtonAriaLabel": "筛除值", - "discover.docTable.tableRow.filterOutValueButtonTooltip": "筛除值", - "discover.docTable.tableRow.toggleRowDetailsButtonAriaLabel": "切换行详细信息", - "discover.docTable.tableRow.viewSingleDocumentLinkText": "查看单个文档", - "discover.docTable.tableRow.viewSurroundingDocumentsLinkText": "查看周围文档", "discover.documentsAriaLabel": "文档", "discover.docViews.logsOverview.title": "日志概览", - "discover.docViews.table.scoreSortWarningTooltip": "要检索 _score 的值,必须按其筛选。", "discover.dropZoneTableLabel": "放置区域以将字段作为列添加到表中", "discover.embeddable.inspectorRequestDataTitle": "数据", "discover.embeddable.inspectorRequestDescription": "此请求将查询 Elasticsearch 以获取搜索的数据。", @@ -2828,7 +2787,6 @@ "discover.globalSearch.esqlSearchTitle": "创建 ES|QL 查询", "discover.goToDiscoverButtonText": "前往 Discover", "discover.grid.tableRow.actionsLabel": "操作", - "discover.grid.tableRow.esqlDetailHeading": "已展开结果", "discover.grid.tableRow.mobileFlyoutActionsButton": "操作", "discover.grid.tableRow.moreFlyoutActionsButton": "更多操作", "discover.grid.tableRow.viewSingleDocumentLinkLabel": "查看单个文档", @@ -2839,7 +2797,6 @@ "discover.hitsCounter.hitsPluralTitle": "{formattedHits} 个{hits, plural, other {结果}}", "discover.hitsCounter.partialHits": "≥{formattedHits}", "discover.hitsCounter.partialHitsPluralTitle": "≥{formattedHits} 个{hits, plural, other {结果}}", - "discover.howToSeeOtherMatchingDocumentsDescription": "下面是与您的搜索匹配的前 {sampleSize} 个文档,请优化您的搜索以查看其他文档。", "discover.inspectorEsqlRequestDescription": "此请求将查询 Elasticsearch 以获取该表的结果。", "discover.inspectorEsqlRequestTitle": "表", "discover.inspectorRequestDataTitleDocuments": "文档", @@ -2848,7 +2805,6 @@ "discover.invalidFiltersWarnToast.description": "某些应用的筛选中的数据视图 ID 引用与当前数据视图不同。", "discover.invalidFiltersWarnToast.title": "不同的索引引用", "discover.loadingDocuments": "正在加载文档", - "discover.loadingResults": "正在加载结果", "discover.localMenu.alertsDescription": "告警", "discover.localMenu.esqlTooltipLabel": "ES|QL 是 Elastic 支持的功能强大的全新管道查询语言。", "discover.localMenu.fallbackReportTitle": "未命名 Discover 搜索", @@ -8147,24 +8103,16 @@ "unifiedDocViewer.docView.table.searchPlaceHolder": "搜索字段名称或值", "unifiedDocViewer.docViews.json.jsonTitle": "JSON", "unifiedDocViewer.docViews.table.esqlMultivalueFilteringDisabled": "ES|QL 中不支持多值筛选", - "unifiedDocViewer.docViews.table.filterForFieldPresentButtonAriaLabel": "筛留存在的字段", "unifiedDocViewer.docViews.table.filterForFieldPresentButtonTooltip": "字段是否存在筛选", - "unifiedDocViewer.docViews.table.filterForValueButtonAriaLabel": "筛留值", "unifiedDocViewer.docViews.table.filterForValueButtonTooltip": "筛留值", - "unifiedDocViewer.docViews.table.filterOutValueButtonAriaLabel": "筛除值", "unifiedDocViewer.docViews.table.filterOutValueButtonTooltip": "筛除值", "unifiedDocViewer.docViews.table.ignored.multiValueLabel": "包含被忽略的值", "unifiedDocViewer.docViews.table.ignored.singleValueLabel": "被忽略的值", "unifiedDocViewer.docViews.table.ignoredValuesCanNotBeSearchedWarningMessage": "无法搜索被忽略的值", "unifiedDocViewer.docViews.table.pinFieldLabel": "固定字段", "unifiedDocViewer.docViews.table.tableTitle": "表", - "unifiedDocViewer.docViews.table.toggleColumnInTableButtonAriaLabel": "在表中切换列", - "unifiedDocViewer.docViews.table.toggleColumnInTableButtonTooltip": "在表中切换列", "unifiedDocViewer.docViews.table.toggleColumnTableButtonTooltip": "在表中切换列", - "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfMetaFieldsTooltip": "无法筛选元数据字段是否存在", - "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsTooltip": "无法筛选脚本字段是否存在", "unifiedDocViewer.docViews.table.unableToFilterForPresenceOfScriptedFieldsWarningMessage": "无法筛选脚本字段是否存在", - "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedTooltip": "无法搜索未编入索引的字段或被忽略的值", "unifiedDocViewer.docViews.table.unindexedFieldsCanNotBeSearchedWarningMessage": "无法搜索未编入索引的字段", "unifiedDocViewer.docViews.table.unpinFieldLabel": "取消固定字段", "unifiedDocViewer.docViews.table.viewLessButton": "查看更少", @@ -8174,7 +8122,6 @@ "unifiedDocViewer.fieldActions.filterForValue": "筛留值", "unifiedDocViewer.fieldActions.filterOutValue": "筛除值", "unifiedDocViewer.fieldActions.toggleColumn": "在表中切换列", - "unifiedDocViewer.fieldChooser.discoverField.actions": "操作", "unifiedDocViewer.fieldChooser.discoverField.multiField": "多字段", "unifiedDocViewer.fieldChooser.discoverField.multiFieldTooltipContent": "多字段的每个字段可以有多个值", "unifiedDocViewer.fieldChooser.discoverField.name": "字段", @@ -11294,7 +11241,6 @@ "xpack.apm.profiling.callout.dismiss": "关闭", "xpack.apm.profiling.callout.learnMore": "了解详情", "xpack.apm.profiling.callout.title": "正在显示运行 {serviceName} 服务的主机中的分析洞见", - "xpack.apm.profiling.flamegraph.filteredLabel": "正在显示服务主机中的分析洞见", "xpack.apm.profiling.flamegraph.link": "前往 Universal Profiling 火焰图", "xpack.apm.profiling.flamegraph.noDataFound": "未找到任何数据", "xpack.apm.profiling.tabs.flamegraph": "火焰图", @@ -14711,7 +14657,6 @@ "xpack.csp.fleetIntegration.azureAccountTypeDescriptionLabel": "选择载入 Azure 组织(租户根组)或单个 Azure 订阅,然后填写名称和描述以帮助标识此集成。", "xpack.csp.fleetIntegration.cnvm.additionalChargesCalloutDescription": "请注意,由于使用量增加,使用此服务可能导致在您的下一份云服务提供商计费结算单上出现其他收费。", "xpack.csp.fleetIntegration.cnvm.additionalChargesCalloutTitle": "云服务提供商计费帐户上的其他收费。", - "xpack.csp.fleetIntegration.cnvm.configureIntegrationDescription": "选择您要监测的云服务提供商 (CSP),然后填写名称和描述以帮助标识此集成", "xpack.csp.fleetIntegration.configureCspmIntegrationDescription": "选择您要监测的云服务提供商 (CSP),然后填写名称和描述以帮助标识此集成", "xpack.csp.fleetIntegration.configureKspmIntegrationDescription": "选择您要监测的 Kubernetes 集群类型,然后填写名称和描述以帮助标识此集成", "xpack.csp.fleetIntegration.editWarning.calloutDescription": "为了更改您要监测的云服务提供商 (CSP),添加更多帐户或更改 CSPM 的部署位置(组织与单个帐户),请添加新的 CSPM 集成。", @@ -14779,15 +14724,9 @@ "xpack.csp.grouping.nullGroupTooltip.groupingTitle": "分组依据", "xpack.csp.integrationDashboard.noFindings.promptTitle": "结果评估状态", "xpack.csp.integrationDashboard.noFindingsPrompt.promptDescription": "正在等待要收集和索引的数据。如果此进程花费的时间长于预期,请联系我们的支持人员", - "xpack.csp.kspmIntegration.aksOption.benchmarkTitle": "CIS AKS", - "xpack.csp.kspmIntegration.aksOption.nameTitle": "AKS", - "xpack.csp.kspmIntegration.aksOption.tooltipContent": "Azure Kubernetes 服务 - 即将推出", "xpack.csp.kspmIntegration.eksOption.benchmarkTitle": "CIS EKS", "xpack.csp.kspmIntegration.eksOption.nameTitle": "EKS", "xpack.csp.kspmIntegration.eksOption.tooltipContent": "Elastic Kubernetes 服务", - "xpack.csp.kspmIntegration.gkeOption.benchmarkTitle": "CIS GKE", - "xpack.csp.kspmIntegration.gkeOption.nameTitle": "GKE", - "xpack.csp.kspmIntegration.gkeOption.tooltipContent": "Google Kubernetes Engine - 即将推出", "xpack.csp.kspmIntegration.integration.nameTitle": "Kubernetes 安全态势管理", "xpack.csp.kspmIntegration.integration.shortNameTitle": "KSPM", "xpack.csp.kspmIntegration.vanillaOption.benchmarkTitle": "CIS Kubernetes", @@ -14922,10 +14861,6 @@ "xpack.csp.vulnerabilties.intergationNoInstalledEmptyPrompt.promptDescription": "使用我们的{lineBreak}云原生漏洞管理 (CNVM) 集成,{lineBreak}检测并缓解您的云资产中的潜在漏洞。{lineBreak} {learnMore}", "xpack.csp.vulnerabilties.intergationNoInstalledEmptyPrompt.promptTitle": "Elastic 的云原生{lineBreak}漏洞管理", "xpack.csp.vulnMgmtIntegration.awsOption.nameTitle": "Amazon Web Services", - "xpack.csp.vulnMgmtIntegration.azureOption.nameTitle": "Azure", - "xpack.csp.vulnMgmtIntegration.azureOption.tooltipContent": "即将推出", - "xpack.csp.vulnMgmtIntegration.gcpOption.nameTitle": "GCP", - "xpack.csp.vulnMgmtIntegration.gcpOption.tooltipContent": "即将推出", "xpack.customBranding.appName": "定制品牌", "xpack.customBranding.customizedLogoDescription": "替换徽标旁的文本。图像不大于 200 x 84 像素并采用透明背景时,图像的显示效果最佳。{subscriptionLink}", "xpack.customBranding.customizedLogoLabel": "组织名称", @@ -14960,8 +14895,6 @@ "xpack.datasetQuality.degradedDocsColumnTooltip": "您的数据集中包含 {ignoredProperty} 属性的文档的百分比。", "xpack.datasetQuality.degradedDocsQualityDescription": "{quality} -{comparator} {minimimPercentage}%", "xpack.datasetQuality.detail.degradedFieldsSectionTitle": "质量问题", - "xpack.datasetQuality.details.chartExploreDataInDiscoverText": "在 Discover 中浏览数据", - "xpack.datasetQuality.details.chartExploreDataInLogsExplorerText": "在日志浏览器中浏览数据", "xpack.datasetQuality.details.chartOpenInLensText": "在 Lens 中打开", "xpack.datasetQuality.details.checkBreakdownFieldEcsFailed": "无法检索细目字段元数据。", "xpack.datasetQuality.details.datasetCreatedOnText": "创建日期", @@ -14997,7 +14930,6 @@ "xpack.datasetQuality.details.fetchDataStreamDetailsFailed": "无法获取数据流详情。", "xpack.datasetQuality.details.fetchDataStreamSettingsFailed": "无法加载数据流设置。", "xpack.datasetQuality.details.fetchIntegrationDashboardsFailed": "无法获取集成仪表板。", - "xpack.datasetQuality.details.fetchIntegrationsFailed": "无法获取 {integrationName} 集成信息。", "xpack.datasetQuality.details.indexTemplateActionText": "索引模板", "xpack.datasetQuality.details.integrationActionsText": "集成操作", "xpack.datasetQuality.details.integrationnameText": "集成", @@ -15104,7 +15036,6 @@ "xpack.datasetQuality.types.label": "类型", "xpack.dataUsage.charts.ingestedMax": "已采集的数据", "xpack.dataUsage.charts.retainedMax": "保留在存储中的数据", - "xpack.dataUsage.metrics.filter.clearAll": "全部清除", "xpack.dataUsage.metrics.filter.dataStreams": "数据流", "xpack.dataUsage.metrics.filter.emptyMessage": "无 {filterName} 可用", "xpack.dataUsage.metrics.filter.metricTypes": "指标类型", @@ -17068,8 +16999,6 @@ "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.done": "完成", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.generateButton": "生成密钥", "xpack.enterpriseSearch.content.analytics.api.generateAnalyticsApiKeyModal.title": "创建分析 API 密钥", - "xpack.enterpriseSearch.content.cannotConnect.body": "更多信息。", - "xpack.enterpriseSearch.content.cannotConnect.title": "无法连接到 Enterprise Search", "xpack.enterpriseSearch.content.conectors.indexHealth": "运行正常", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.badgeType.connectorClient": "自管型连接器", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.badgeType.nativeConnector": "Elastic 托管连接器", @@ -17094,7 +17023,6 @@ "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.callout.finishLaterButton.label": "稍后完成部署", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.callout.title": "等候您的连接器", "xpack.enterpriseSearch.content.connector_detail.configurationConnector.steps.waitingForConnector.title": "等待您的连接器签入", - "xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.apiKey.title": "API 密钥", "xpack.enterpriseSearch.content.connector_detail.nativeConfigurationConnector.configuration.title": "配置", "xpack.enterpriseSearch.content.connectors.breadcrumb": "连接器", "xpack.enterpriseSearch.content.connectors.connectorDetail.configurationTabLabel": "配置", @@ -17124,10 +17052,6 @@ "xpack.enterpriseSearch.content.connectors.deleteModal.delete.crawler.description": "您即将删除此网络爬虫:", "xpack.enterpriseSearch.content.connectors.deleteModal.syncsWarning.indexNameDescription": "此操作无法撤消。请尝试 {connectorName} 以确认。", "xpack.enterpriseSearch.content.connectors.deleteModal.title": "删除 {connectorCount} 个连接器?", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.description.ariaLabel": "编辑连接器描述", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.description.placeholder": "添加描述", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.name.ariaLabel": "编辑连接器名称", - "xpack.enterpriseSearch.content.connectors.nameAndDescription.name.placeholder": "为连接器添加名称", "xpack.enterpriseSearch.content.connectors.overview.connectorErrorCallOut.title": "您的连接器报告了错误", "xpack.enterpriseSearch.content.connectors.overview.connectorIndexDoesntExistCallOut.description": "此连接器将在其下次同步时创建索引,或者,您也可以使用所需设置和映射手动创建索引 {indexName}。", "xpack.enterpriseSearch.content.connectors.overview.connectorIndexDoesntExistCallOut.title": "附加的索引不存在", @@ -17265,8 +17189,6 @@ "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.description": "是否要自我托管此连接器?将其转换为将在您自己的基础设施上进行托管的 {link}。如果希望使用我们的 Python 框架定制代码,您需要转换此连接器。", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.linkTitle": "自管型连接器", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.convertConnector.title": "自我管理此连接器", - "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.text": "Elastic 托管连接器需要正在运行的 Enterprise Search 实例。", - "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnector.entSearchWarning.title": "未检测到正在运行的 Enterprise Search 实例", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnectorAdvancedConfiguration.description": "通过触发一次时间同步或设置重复同步计划来最终确定您的连接器。", "xpack.enterpriseSearch.content.indices.configurationConnector.nativeConnectorAdvancedConfiguration.schedulingButtonLabel": "设置计划并同步", "xpack.enterpriseSearch.content.indices.configurationConnector.researchConfiguration.connectorDocumentationLinkLabel": "文档", @@ -17616,7 +17538,6 @@ "xpack.enterpriseSearch.content.playground.breadcrumb": "Playground", "xpack.enterpriseSearch.content.searchIndex.cancelSync.successMessage": "已成功取消同步", "xpack.enterpriseSearch.content.searchIndex.cancelSyncs.successMessage": "已成功取消同步", - "xpack.enterpriseSearch.content.searchIndex.cannotConnect.body": "Elastic 网络爬虫需要 Enterprise Search。{link}", "xpack.enterpriseSearch.content.searchIndex.configurationTabLabel": "配置", "xpack.enterpriseSearch.content.searchIndex.connectorErrorCallOut.title": "您的连接器报告了错误", "xpack.enterpriseSearch.content.searchIndex.crawlerConfigurationTabLabel": "配置", @@ -17947,14 +17868,10 @@ "xpack.enterpriseSearch.createConnector..title": "创建连接器", "xpack.enterpriseSearch.createConnector.badgeType.ElasticManaged": "Elastic 托管", "xpack.enterpriseSearch.createConnector.badgeType.selfManaged": "自管型", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.BetaBadgeLabel": "公测版", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.OnlySelfManagedBadgeLabel": "自管型", "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.placeholder.text": "选择数据源", - "xpack.enterpriseSearch.createConnector.chooseConnectorSelectable.thechPreviewBadgeLabel": "技术预览", "xpack.enterpriseSearch.createConnector.configurationStep.configurationLabel": "配置", "xpack.enterpriseSearch.createConnector.configurationStep.h4.finishUpLabel": "结束", "xpack.enterpriseSearch.createConnector.configurationStep.p.description": "您可以手动同步数据,计划重复同步或管理您的域。", - "xpack.enterpriseSearch.createConnector.connectorDescriptionBadge.notAvailableTitle": "此连接器不可用作 Elastic 托管连接器", "xpack.enterpriseSearch.createConnector.connectorDocsLinkLabel": "连接器参考", "xpack.enterpriseSearch.createConnector.DeploymentStep.Configuration.description": "立即配置您的 Elastic 网络爬虫并同步数据。", "xpack.enterpriseSearch.createConnector.DeploymentStep.Configuration.title": "配置", @@ -18029,17 +17946,6 @@ "xpack.enterpriseSearch.enterpriseSearch.setupGuide.videoAlt": "企业搜索入门", "xpack.enterpriseSearch.enterpriseSearchCard.cta": "了解详情", "xpack.enterpriseSearch.entSearch.productCardDescription": "为构建更简单、用户友好且以业务为中心的搜索体验而量身定制的独立应用程序。", - "xpack.enterpriseSearch.errorConnectingCallout.setupGuideCta": "阅读设置指南", - "xpack.enterpriseSearch.errorConnectingCallout.title": "无法连接到 Enterprise Search", - "xpack.enterpriseSearch.errorConnectingState.cloudErrorMessage": "您的云部署是否正在运行 Enterprise Search 节点?{deploymentSettingsLink}", - "xpack.enterpriseSearch.errorConnectingState.cloudErrorMessageLinkText": "检查您的部署设置", - "xpack.enterpriseSearch.errorConnectingState.description1": "由于以下错误,我们无法与主机 URL {enterpriseSearchUrl} 的 Enterprise Search 建立连接:", - "xpack.enterpriseSearch.errorConnectingState.description2": "确保在 {configFile} 中已正确配置主机 URL。", - "xpack.enterpriseSearch.errorConnectingState.description3": "确认企业搜索服务器响应。", - "xpack.enterpriseSearch.errorConnectingState.setupGuideCta": "阅读设置指南", - "xpack.enterpriseSearch.errorConnectingState.title": "无法连接", - "xpack.enterpriseSearch.errorConnectingState.troubleshootAuth": "检查您的用户身份验证:", - "xpack.enterpriseSearch.errorConnectingState.troubleshootAuthMessage": "请联系管理员设置 Enterprise Search 角色映射,为您提供 Enterprise Search 的访问权限", "xpack.enterpriseSearch.exampleConnectorLabel": "示例", "xpack.enterpriseSearch.finishUpStep.euiButton.viewInDiscoverLabel": "在 Discover 中查看", "xpack.enterpriseSearch.getConnectorTypeBadge.connectorClientBadgeLabel": "自管型", @@ -18187,9 +18093,6 @@ "xpack.enterpriseSearch.navigation.contentPlaygroundLinkLabel": "Playground", "xpack.enterpriseSearch.navigation.contentWebcrawlersLinkLabel": "网络爬虫", "xpack.enterpriseSearch.navigation.relevanceInferenceEndpointsLinkLabel": "推理终端", - "xpack.enterpriseSearch.noEntSearch.noCrawler": "如果没有 Enterprise Search,Elastic 网络爬虫将不可用。", - "xpack.enterpriseSearch.noEntSearch.setupGuideCta": "阅读设置指南", - "xpack.enterpriseSearch.noEntSearchConfigured.title": "尚未配置 Enterprise Search", "xpack.enterpriseSearch.notFound.action1": "返回到您的仪表板", "xpack.enterpriseSearch.notFound.action2": "联系支持人员", "xpack.enterpriseSearch.notFound.description": "找不到您要查找的页面。", @@ -18458,7 +18361,6 @@ "xpack.enterpriseSearch.searchApplications.searchApplication.indices.searchPlaceholder": "筛选索引", "xpack.enterpriseSearch.searchApplications.searchApplication.indices.someUnknownIndicesCallout.description": "可能无法从此搜索应用程序访问某些数据。在受影响的索引上检查任何待处理操作或错误,或移除应不再被此搜索应用程序使用的索引。", "xpack.enterpriseSearch.searchApplications.searchApplication.indices.someUnknownIndicesCallout.title": "您的某些索引不可用。", - "xpack.enterpriseSearch.searchApplications.searchApplication.notFound.action1": "返回到搜索应用程序", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.button": "查看冲突", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.description": "可以通过直接导航到源索引并更新冲突字段的字段类型,使其与其他源索引的字段类型相匹配,从而解决架构字段类型冲突。", "xpack.enterpriseSearch.searchApplications.searchApplication.schema.conflictsCallOut.title": "发现潜在的字段映射问题", @@ -18671,10 +18573,6 @@ "xpack.enterpriseSearch.vectorSearch.guide.query.title": "执行向量搜索", "xpack.enterpriseSearch.vectorSearch.navTitle": "矢量搜索", "xpack.enterpriseSearch.vectorSearch.productName": "矢量搜索", - "xpack.enterpriseSearch.versionMismatch.body": "您的 Kibana 和 Enterprise Search 版本不匹配。要访问 Enterprise Search,请对每项服务使用相同的主要和次要版本。", - "xpack.enterpriseSearch.versionMismatch.enterpriseSearchVersionText": "Enterprise Search 版本:{enterpriseSearchVersion}", - "xpack.enterpriseSearch.versionMismatch.kibanaVersionText": "Kibana 版本:{kibanaVersion}", - "xpack.enterpriseSearch.versionMismatch.title": "版本不兼容错误", "xpack.enterpriseSearch.welcomeBanner.header.greeting.customTitle": "👋 {name} 您好!", "xpack.enterpriseSearch.welcomeBanner.header.greeting.defaultTitle": "👋 您好", "xpack.enterpriseSearch.welcomeBanner.header.title": "将数据添加到 Elasticsearch,然后进行搜索、向量化或可视化", @@ -20119,7 +20017,6 @@ "xpack.fleet.agentPolicyForm.newAgentPolicyFieldLabel": "新代理策略名称", "xpack.fleet.agentPolicyForm.outputOptionDisabledTypeNotSupportedText": "Fleet 服务器、Synthetics 或 APM 不支持代理集成的 {outputType} 输出。", "xpack.fleet.agentPolicyForm.outputOptionDisableOutputTypeText": "Fleet 服务器、Synthetics 或 APM 不支持代理集成的 {outputType} 输出。", - "xpack.fleet.agentPolicyForm.spaceDescription": "为此策略选择一个或多个工作区,或创建新工作区。{link}", "xpack.fleet.agentPolicyForm.spaceFieldLabel": "工作区", "xpack.fleet.agentPolicyForm.systemMonitoringText": "收集系统日志和指标", "xpack.fleet.agentPolicyForm.systemMonitoringTooltipText": "这还会添加 {system} 集成以收集系统日志和指标。", @@ -22166,8 +22063,6 @@ "xpack.idxMgmt.enrichPolicyCreate.configurationStep.queryLabel": "查询(可选)", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeOption": "范围", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.rangeTypePopOver": "{type} 匹配一个数字、日期或 IP 地址范围。", - "xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesLabel": "源索引", - "xpack.idxMgmt.enrichPolicyCreate.configurationStep.sourceIndicesRequiredError": "至少需要一个源索引。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.typeRequiredError": "策略类型值必填。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.typeTitlePopOver": "确定如何将数据匹配到传入文档。", "xpack.idxMgmt.enrichPolicyCreate.configurationStep.uploadFileLink": "上传文件", @@ -22248,10 +22143,6 @@ "xpack.idxMgmt.home.componentTemplates.list.loadingMessage": "正在加载组件模板……", "xpack.idxMgmt.home.componentTemplatesTabTitle": "组件模板", "xpack.idxMgmt.home.dataStreamsTabTitle": "数据流", - "xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesDescription": "正在检查权限……", - "xpack.idxMgmt.home.enrichPolicies.checkingPrivilegesErrorMessage": "从服务器获取用户权限时出错。", - "xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeDescription": "要使用扩充策略,必须具有以下集群权限:{missingPrivileges}。", - "xpack.idxMgmt.home.enrichPolicies.deniedPrivilegeTitle": "管理所需的扩充权限", "xpack.idxMgmt.home.enrichPoliciesTabTitle": "扩充策略", "xpack.idxMgmt.home.idxMgmtDescription": "分别或批量更新您的 Elasticsearch 索引。{learnMoreLink}", "xpack.idxMgmt.home.idxMgmtDocsLinkText": "索引管理文档", @@ -22898,7 +22789,6 @@ "xpack.idxMgmt.mappingsEditor.parameters.validations.fieldDataFrequency.numberGreaterThanOneErrorMessage": "值必须大于 1。", "xpack.idxMgmt.mappingsEditor.parameters.validations.greaterThanZeroErrorMessage": "缩放因数必须大于 0。", "xpack.idxMgmt.mappingsEditor.parameters.validations.ignoreAboveIsRequiredErrorMessage": "字符长度限制必填。", - "xpack.idxMgmt.mappingsEditor.parameters.validations.inferenceIdIsRequiredErrorMessage": "'推理 ID'必填。", "xpack.idxMgmt.mappingsEditor.parameters.validations.localeFieldRequiredErrorMessage": "指定区域设置。", "xpack.idxMgmt.mappingsEditor.parameters.validations.maxInputLengthFieldRequiredErrorMessage": "指定最大输入长度。", "xpack.idxMgmt.mappingsEditor.parameters.validations.nameIsRequiredErrorMessage": "为字段提供名称。", @@ -23299,7 +23189,6 @@ "xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableExplanationText": "减少每个索引分片中的分段数目,并清除删除的文档。", "xpack.indexLifecycleMgmt.editPolicy.forceMerge.enableText": "强制合并", "xpack.indexLifecycleMgmt.editPolicy.forcemerge.numberOfSegmentsRequiredError": "必须指定分段数的值。", - "xpack.indexLifecycleMgmt.editPolicy.formErrorsMessage": "请修复此页面上的错误。", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.activateFrozenPhaseSwitchLabel": "激活冻结阶段", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.frozenPhaseDescription": "将数据移到冻层以长期保留。冻层提供最有成本效益的方法存储数据,并且仍能够搜索数据。", "xpack.indexLifecycleMgmt.editPolicy.frozenPhase.frozenPhaseTitle": "冻结阶段", @@ -25686,7 +25575,6 @@ "xpack.inventory.entitiesGrid.euiDataGrid.lastSeenTooltip": "上次接收的实体数据的时间戳 (entity.lastSeenTimestamp)", "xpack.inventory.entitiesGrid.euiDataGrid.typeLabel": "类型", "xpack.inventory.entitiesGrid.euiDataGrid.typeTooltip": "实体的类型 (entity.type)", - "xpack.inventory.entityActions.discoverLink": "在 Discover 中打开", "xpack.inventory.featureRegistry.inventoryFeatureName": "库存", "xpack.inventory.home.serviceAlertsTable.tooltip.activeAlertsExplanation": "活动告警", "xpack.inventory.inventoryLinkTitle": "库存", @@ -25866,7 +25754,6 @@ "xpack.lens.app.createVisualizationLabel": "ES|QL", "xpack.lens.app.docLoadingError": "加载已保存文档时出错", "xpack.lens.app.editLensEmbeddableLabel": "编辑可视化", - "xpack.lens.app.editVisualizationLabel": "编辑 {lang} 可视化", "xpack.lens.app.exploreDataInDiscover": "在 Discover 中浏览", "xpack.lens.app.exploreDataInDiscoverDrilldown": "在 Discover 中打开", "xpack.lens.app.exploreDataInDiscoverDrilldown.newTabConfig": "在新选项卡中打开", @@ -26025,14 +25912,6 @@ "xpack.lens.editorFrame.suggestionPanelTitle": "建议", "xpack.lens.editorFrame.tooManyDimensionsSingularWarningLabel": "请移除{dimensionsTooMany, plural, one {一个维度} other {{dimensionsTooMany} 个维度}}", "xpack.lens.editorFrame.workspaceLabel": "工作区", - "xpack.lens.embeddable.failure": "无法显示可视化", - "xpack.lens.embeddable.featureBadge.iconDescription": "{count} 个可视化{count, plural, other {修饰符}}", - "xpack.lens.embeddable.fixErrors": "在 Lens 编辑器中编辑以修复该错误", - "xpack.lens.embeddable.legacyURLConflict.shortMessage": "您遇到了 URL 冲突", - "xpack.lens.embeddable.missingTimeRangeParam.longMessage": "给定配置需要包含 timeRange 属性", - "xpack.lens.embeddable.missingTimeRangeParam.shortMessage": "缺少 timeRange 属性", - "xpack.lens.embeddable.moreErrors": "在 Lens 编辑器中编辑以查看更多错误", - "xpack.lens.embeddableDisplayName": "Lens", "xpack.lens.endValue.nearest": "最近", "xpack.lens.endValue.none": "隐藏", "xpack.lens.endValue.zero": "零", @@ -26040,6 +25919,7 @@ "xpack.lens.endValueDescription.none": "不将序列扩展到图表边缘", "xpack.lens.endValueDescription.zero": "将为零序列扩展到图表边缘", "xpack.lens.experimentalLabel": "技术预览", + "xpack.lens.featureBadge.iconDescription": "{count} 个可视化{count, plural, other {修饰符}}", "xpack.lens.fieldFormats.longSuffix.d": "每天", "xpack.lens.fieldFormats.longSuffix.h": "每小时", "xpack.lens.fieldFormats.longSuffix.m": "每分钟", @@ -26059,6 +25939,7 @@ "xpack.lens.fittingFunctionsTitle.lookahead": "下一个", "xpack.lens.fittingFunctionsTitle.none": "隐藏", "xpack.lens.fittingFunctionsTitle.zero": "零", + "xpack.lens.fixErrors": "在 Lens 编辑器中编辑以修复该错误", "xpack.lens.formula.disableWordWrapLabel": "禁用自动换行", "xpack.lens.formula.editorHelpInlineHideLabel": "隐藏函数引用", "xpack.lens.formula.editorHelpInlineHideToolTip": "隐藏函数引用", @@ -26542,7 +26423,6 @@ "xpack.lens.legacyMetric.titlePositions.bottom": "底部", "xpack.lens.legacyMetric.titlePositions.top": "顶部", "xpack.lens.legacyUrlConflict.objectNoun": "Lens 可视化", - "xpack.lens.lensSavedObjectLabel": "Lens 可视化", "xpack.lens.lineCurve.smooth": "平滑", "xpack.lens.lineCurve.step": "步骤", "xpack.lens.lineCurve.straight": "直线", @@ -26602,6 +26482,7 @@ "xpack.lens.modalTitle.title.deleteAnnotations": "删除标注组?", "xpack.lens.modalTitle.title.deleteReferenceLines": "删除参考线图层?", "xpack.lens.modalTitle.title.deleteVis": "删除可视化图层?", + "xpack.lens.moreErrors": "在 Lens 编辑器中编辑以查看更多错误", "xpack.lens.pageTitle": "Lens", "xpack.lens.paletteHeatmapGradient.label": "颜色", "xpack.lens.paletteMetricGradient.label": "颜色", @@ -35433,15 +35314,6 @@ "xpack.searchInferenceEndpoints.actions.endpointAddedFailure": "终端创建失败", "xpack.searchInferenceEndpoints.actions.endpointAddedSuccess": "已添加终端", "xpack.searchInferenceEndpoints.actions.trainedModelsStatGatherFailed": "无法检索已训练模型统计信息", - "xpack.searchInferenceEndpoints.addEmptyPrompt.createFirstInferenceEndpointDescription": "利用推理终端,您可以使用由第三方服务提供的 NLP 模型或 ELSER 和 E5 等 Elastic 内置模型来执行推理任务。通过使用创建推理 API 来设置任务,如文本嵌入、完成、重新排名等。", - "xpack.searchInferenceEndpoints.addEmptyPrompt.e5Description": "E5 是一个第三方 NLP 模型,它允许您通过使用密集向量表示方法来执行多语言语义搜索。", - "xpack.searchInferenceEndpoints.addEmptyPrompt.e5Title": "E5 多语言", - "xpack.searchInferenceEndpoints.addEmptyPrompt.elserDescription": "ELSER 是 Elastic 的英文版稀疏向量语义搜索 NLP 模型。", - "xpack.searchInferenceEndpoints.addEmptyPrompt.elserTitle": "ELSER", - "xpack.searchInferenceEndpoints.addEmptyPrompt.learnHowToCreateInferenceEndpoints": "了解如何创建推理终端", - "xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithE5": "利用 E5 多语言版进行语义搜索", - "xpack.searchInferenceEndpoints.addEmptyPrompt.semanticSearchWithElser": "利用 ELSER 进行语义搜索", - "xpack.searchInferenceEndpoints.addEmptyPrompt.startWithPreparedEndpointsLabel": "详细了解内置 NLP 模型:", "xpack.searchInferenceEndpoints.allInferenceEndpoints.description": "推理终端简化了 Elasticsearch 中的 Machine Learning 模型部署和管理。使用唯一的终端来设置和管理 NLP 任务,以构建 AI 驱动式搜索。", "xpack.searchInferenceEndpoints.apiDocumentationLink": "API 文档", "xpack.searchInferenceEndpoints.cancel": "取消", @@ -36595,8 +36467,6 @@ "xpack.securitySolution.assistant.quickPrompts.alertSummarizationTitle": "告警汇总", "xpack.securitySolution.assistant.quickPrompts.AutomationPrompt": "我应使用哪个启用 Fleet 的 Elastic 代理集成从以下项中收集日志和事件:", "xpack.securitySolution.assistant.quickPrompts.AutomationTitle": "代理集成建议", - "xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationPrompt": "作为 Elastic Security 的专家用户,请生成准确、有效的 ESQL 查询来检测以下用例。应对您的响应进行格式化,以便可以立即在 Elastic Security 时间线或检测规则中使用。请花点时间提供答案,检验您是否清楚了解我所询问的所有功能。具体来说,对于 ES|QL 答案,您应仅根据自己的个人观点进行解答。我无法承担查询不准确的后果。假设我正使用 Elastic Common Schema 和 Elastic 代理。确保以可轻松复制为 Markdown 中的独立代码块的方式设置答案的格式。", - "xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationTitle": "ES|QL 查询生成", "xpack.securitySolution.assistant.quickPrompts.ruleCreationPrompt": "作为 Elastic Security 的专家用户,请生成准确、有效的 EQL 查询来检测以下用例。应对您的响应进行格式化,以便可以立即在 Elastic Security 时间线或检测规则中使用。如果 Elastic Security 已经为此用例预构建了规则,或具有类似规则,请提供该规则的链接并做出描述。", "xpack.securitySolution.assistant.quickPrompts.ruleCreationTitle": "查询生成", "xpack.securitySolution.assistant.quickPrompts.splQueryConversionPrompt": "我具有以下来自之前 SIEM 平台的查询。作为 Elastic Security 的专家用户,请提议一个 Elastic EQL 等价查询。我应能够立即将其复制到 Elastic Security 时间线。", @@ -37430,10 +37300,6 @@ "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlQueryFieldRequiredError": "EQL 查询必填。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionDisableText": "EQL 序列查询不支持阻止。", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.eqlSequenceSuppressionValidationText": "{EQL_SEQUENCE_SUPPRESSION_DISABLE_TOOLTIP} 将 EQL 查询更改为非序列查询,或移除阻止字段。", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoAriaLabel": "打开帮助弹出框", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipContent": "请访问我们的{createEsqlRuleTypeLink}以开始使用 ES|QL 规则。", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlInfoTooltipLink": "文档", - "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.esqlQueryLabel": "ES|QL 查询", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldAnomalyThresholdLabel": "异常分数阈值", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldMachineLearningJobIdLabel": "Machine Learning 作业", "xpack.securitySolution.detectionEngine.createRule.stepDefineRule.fieldQuerBarLabel": "定制查询", @@ -37536,9 +37402,6 @@ "xpack.securitySolution.detectionEngine.esqlRuleType.eqlSearchRequestDescription": "用于查找所有匹配项的 EQL 查询", "xpack.securitySolution.detectionEngine.esqlRuleType.esqlSearchRequestDescription": "用于查找所有匹配项的 ES|QL 查询", "xpack.securitySolution.detectionEngine.esqlRuleType.findSourceDocumentsRequestDescription": "当 ES|QL 查询不可聚集时检索源文档", - "xpack.securitySolution.detectionEngine.esqlValidation.missingIdFieldInQueryError": "未使用 STATS...BY 函数的查询(非聚合查询)必须在源命令后包括'metadata _id, _version, _index'运算符。例如:FROM logs* metadata _id, _version, _index。此外,还必须在查询响应中返回元数据属性(_id、_version 和 _index)。", - "xpack.securitySolution.detectionEngine.esqlValidation.missingMetadataOperatorInQueryError": "未使用 STATS...BY 函数的查询(非聚合查询)必须在源命令后包括'metadata _id, _version, _index'运算符。例如:FROM logs* metadata _id, _version, _index。", - "xpack.securitySolution.detectionEngine.esqlValidation.unknownError": "验证 ES|QL 时发生未知错误", "xpack.securitySolution.detectionEngine.executionRunType.backfill": "手动", "xpack.securitySolution.detectionEngine.executionRunType.standard": "已计划", "xpack.securitySolution.detectionEngine.goToDocumentationButton": "查看文档", @@ -39790,7 +39653,6 @@ "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.noPermissionTitle": "索引权限不足,无法执行 CSV 上传", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.resultsStepTitle": "结果", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.selectFileStepTitle": "选择文件", - "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.subTitle": "使用文本文件导入实体", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unavailable": "资产关键度 CSV 文件上传功能不可用。", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.unsupportedFileTypeError": "选定的文件格式无效。请选择 {supportedFileExtensions} 文件,然后重试", "xpack.securitySolution.entityAnalytics.assetCriticalityUploadPage.uploadFileSizeLimit": "最大文件大小:{maxFileSize}", @@ -39832,7 +39694,6 @@ "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.clearAllEntities": "清除所有实体", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.close": "关闭", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntitiesModal.title": "清除实体数据?", - "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.clearEntityData": "移除从仓库中提取的所有实体数据。此操作将永久删除持久化用户和主机记录,并且数据将不再可用于分析。请谨慎操作,因为此操作无法撤消。请注意,此操作不会删除源数据、实体风险分数或资产关键度分配。", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.featureFlagDisabled": "实体仓库功能不可用", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.subTitle": "允许全面监测您系统的主机和用户。", "xpack.securitySolution.entityAnalytics.entityStoreManagementPage.title": "实体仓库", @@ -44180,7 +44041,6 @@ "xpack.spaces.management.spacesGridPage.editSpaceActionDescription": "编辑 {spaceName}。", "xpack.spaces.management.spacesGridPage.editSpaceActionName": "编辑", "xpack.spaces.management.spacesGridPage.errorTitle": "加载工作区时出错", - "xpack.spaces.management.spacesGridPage.identifierColumnName": "标识符", "xpack.spaces.management.spacesGridPage.loadingTitle": "正在加载……", "xpack.spaces.management.spacesGridPage.searchPlaceholder": "搜索", "xpack.spaces.management.spacesGridPage.solutionColumnName": "解决方案视图", @@ -45563,7 +45423,6 @@ "xpack.synthetics.failedStep.label": "失败的步骤", "xpack.synthetics.fcp.label": "FCP", "xpack.synthetics.featureRegistry.syntheticsFeatureName": "Synthetics 和 Uptime", - "xpack.synthetics.features.app": "Synthetics", "xpack.synthetics.features.elasticManagedLocations": "已启用 Elastic 托管位置", "xpack.synthetics.fieldLabels.cls": "累计布局偏移 (CLS)", "xpack.synthetics.fieldLabels.dcl": "DOMContentLoaded 事件 (DCL)", @@ -47901,7 +47760,6 @@ "xpack.triggersActionsUI.updateApiKeyConfirmModal.failureMessage": "无法更新 API {idsToUpdate, plural, other {密钥}}", "xpack.triggersActionsUI.updateApiKeyConfirmModal.title": "更新 API 密钥", "xpack.triggersActionsUI.urlSyncedAlertsSearchBar.invalidQueryTitle": "字符串查询无效", - "xpack.triggersActionsUI.useRuleAADFields.errorMessage": "无法按规则类型加载告警字段", "xpack.upgradeAssistant.app.deniedPrivilegeDescription": "要使用升级助手并解决弃用问题,必须具有管理所有 Kibana 工作区的访问权限。", "xpack.upgradeAssistant.app.deniedPrivilegeTitle": "需要 Kibana 管理员角色", "xpack.upgradeAssistant.appTitle": "升级助手", @@ -48108,7 +47966,6 @@ "xpack.upgradeAssistant.overview.apiCompatibilityNoteTitle": "应用 API 兼容性标头(可选)", "xpack.upgradeAssistant.overview.backupStepDescription": "做出更改之前,请确保具有当前快照。", "xpack.upgradeAssistant.overview.backupStepTitle": "备份您的数据", - "xpack.upgradeAssistant.overview.checkUpcomingVersion": "如果您未使用最新版本的 Elastic Stack,请使用升级助手准备下次升级。", "xpack.upgradeAssistant.overview.cloudBackup.hasSnapshotMessage": "上次创建快照的时间为 {lastBackupTime}。", "xpack.upgradeAssistant.overview.cloudBackup.loadingError": "检索最新快照状态时出错", "xpack.upgradeAssistant.overview.cloudBackup.noSnapshotMessage": "您的数据未备份。", @@ -48183,7 +48040,6 @@ "xpack.upgradeAssistant.overview.verifyChanges.retryButton": "重试", "xpack.upgradeAssistant.overview.viewDiscoverResultsAction": "在 Discover 中分析日志", "xpack.upgradeAssistant.overview.viewObservabilityResultsAction": "在日志浏览器中查看弃用日志", - "xpack.upgradeAssistant.overview.whatsNewLink": "查看最新发布亮点", "xpack.upgradeAssistant.status.allDeprecationsResolvedMessage": "所有弃用警告均已解决。", "xpack.upgradeAssistant.status.deprecationsUnresolvedMessage": "在升级之前必须解决以下问题:{upgradeIssues}。", "xpack.upgradeAssistant.status.esTotalCriticalDepsMessage": "{esTotalCriticalDeps} 个 Elasticsearch 弃用{esTotalCriticalDeps, plural, other {问题}}", diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_select.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_select.test.tsx index 1a5e3f278eb5..845234554314 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_select.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_bulk_edit_select.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook, act } from '@testing-library/react-hooks'; +import { renderHook, act } from '@testing-library/react'; import { useBulkEditSelect } from './use_bulk_edit_select'; import { RuleTableItem } from '../../types'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_create_connector.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_create_connector.test.tsx index 5fe09dd8ae90..f33092c3dea9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_create_connector.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_create_connector.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../common/lib/kibana'; import { useCreateConnector } from './use_create_connector'; @@ -29,7 +29,7 @@ describe('useCreateConnector', () => { }); it('executes correctly', async () => { - const { result, waitForNextUpdate } = renderHook(() => useCreateConnector()); + const { result } = renderHook(() => useCreateConnector()); act(() => { result.current.createConnector({ @@ -40,10 +40,10 @@ describe('useCreateConnector', () => { }); }); - await waitForNextUpdate(); - - expect(useKibanaMock().services.http.post).toHaveBeenCalledWith('/api/actions/connector', { - body: '{"name":"test","config":{},"secrets":{},"connector_type_id":".test"}', - }); + await waitFor(() => + expect(useKibanaMock().services.http.post).toHaveBeenCalledWith('/api/actions/connector', { + body: '{"name":"test","config":{},"secrets":{},"connector_type_id":".test"}', + }) + ); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_execute_connector.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_execute_connector.test.tsx index 4b93900ea6b4..a381296e6bc9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_execute_connector.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_execute_connector.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../common/lib/kibana'; import { useExecuteConnector } from './use_execute_connector'; @@ -29,17 +29,17 @@ describe('useExecuteConnector', () => { }); it('executes correctly', async () => { - const { result, waitForNextUpdate } = renderHook(() => useExecuteConnector()); + const { result } = renderHook(() => useExecuteConnector()); act(() => { result.current.executeConnector({ connectorId: 'test-id', params: {} }); }); - await waitForNextUpdate(); - - expect(useKibanaMock().services.http.post).toHaveBeenCalledWith( - '/api/actions/connector/test-id/_execute', - { body: '{"params":{}}' } + await waitFor(() => + expect(useKibanaMock().services.http.post).toHaveBeenCalledWith( + '/api/actions/connector/test-id/_execute', + { body: '{"params":{}}' } + ) ); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx index 4b65e355b9c8..231b9b9be49d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_get_query_delay_setting.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useGetQueryDelaySettings } from './use_get_query_delay_settings'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_license.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_license.test.ts index 1b2fc7784f4e..ec203e4bdacf 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_license.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_license.test.ts @@ -6,7 +6,7 @@ */ import { BehaviorSubject } from 'rxjs'; import { licensingMock } from '@kbn/licensing-plugin/public/mocks'; -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useLicense } from './use_license'; import { useKibana } from '../../common/lib/kibana'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.test.ts index e56c8aa1348b..b21439038cd7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; -import { ValidFeatureId } from '@kbn/rule-data-utils'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../common/lib/kibana'; import { mockedAlertSummaryResponse, @@ -18,7 +17,7 @@ jest.mock('../../common/lib/kibana'); const useKibanaMock = useKibana as jest.Mocked; describe('useLoadAlertSummary', () => { - const featureIds: ValidFeatureId[] = ['apm']; + const ruleTypeIds: string[] = ['apm']; const mockedPostAPI = jest.fn(); beforeAll(() => { @@ -34,9 +33,9 @@ describe('useLoadAlertSummary', () => { ...mockedAlertSummaryResponse, }); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useLoadAlertSummary({ - featureIds, + ruleTypeIds, timeRange: mockedAlertSummaryTimeRange, }) ); @@ -49,7 +48,7 @@ describe('useLoadAlertSummary', () => { }, }); - await waitForNextUpdate(); + await waitFor(() => new Promise((resolve) => resolve(null))); const { alertSummary, error } = result.current; expect(alertSummary).toEqual({ @@ -70,28 +69,29 @@ describe('useLoadAlertSummary', () => { ...mockedAlertSummaryResponse, }); - const { waitForNextUpdate } = renderHook(() => + renderHook(() => useLoadAlertSummary({ - featureIds, + ruleTypeIds, timeRange: mockedAlertSummaryTimeRange, filter, }) ); - await waitForNextUpdate(); - const body = JSON.stringify({ fixed_interval: fixedInterval, gte: utcFrom, lte: utcTo, - featureIds, + ruleTypeIds, filter: [filter], }); - expect(mockedPostAPI).toHaveBeenCalledWith( - '/internal/rac/alerts/_alert_summary', - expect.objectContaining({ - body, - }) + + await waitFor(() => + expect(mockedPostAPI).toHaveBeenCalledWith( + '/internal/rac/alerts/_alert_summary', + expect.objectContaining({ + body, + }) + ) ); }); @@ -99,15 +99,13 @@ describe('useLoadAlertSummary', () => { const error = new Error('Fetch Alert Summary Failed'); mockedPostAPI.mockRejectedValueOnce(error); - const { result, waitForNextUpdate } = renderHook(() => + const { result } = renderHook(() => useLoadAlertSummary({ - featureIds, + ruleTypeIds, timeRange: mockedAlertSummaryTimeRange, }) ); - await waitForNextUpdate(); - - expect(result.current.error).toMatch(error.message); + await waitFor(() => expect(result.current.error).toMatch(error.message)); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.ts index 10ce20188509..c8053ca57147 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_alert_summary.ts @@ -6,7 +6,6 @@ */ import { useEffect, useState, useCallback, useRef } from 'react'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; import { estypes } from '@elastic/elasticsearch'; import { AsApiContract } from '@kbn/actions-plugin/common'; import { HttpSetup } from '@kbn/core/public'; @@ -15,7 +14,8 @@ import { useKibana } from '../../common/lib/kibana'; import { Alert, AlertSummaryTimeRange } from '../sections/alert_summary_widget/types'; interface UseLoadAlertSummaryProps { - featureIds?: ValidFeatureId[]; + ruleTypeIds?: string[]; + consumers?: string[]; timeRange: AlertSummaryTimeRange; filter?: estypes.QueryDslQueryContainer; } @@ -32,7 +32,12 @@ interface LoadAlertSummaryResponse { error?: string; } -export function useLoadAlertSummary({ featureIds, timeRange, filter }: UseLoadAlertSummaryProps) { +export function useLoadAlertSummary({ + ruleTypeIds, + consumers, + timeRange, + filter, +}: UseLoadAlertSummaryProps) { const { http } = useKibana().services; const [alertSummary, setAlertSummary] = useState({ isLoading: true, @@ -45,14 +50,15 @@ export function useLoadAlertSummary({ featureIds, timeRange, filter }: UseLoadAl const isCancelledRef = useRef(false); const abortCtrlRef = useRef(new AbortController()); const loadAlertSummary = useCallback(async () => { - if (!featureIds) return; + if (!ruleTypeIds) return; isCancelledRef.current = false; abortCtrlRef.current.abort(); abortCtrlRef.current = new AbortController(); try { const { activeAlertCount, activeAlerts, recoveredAlertCount } = await fetchAlertSummary({ - featureIds, + ruleTypeIds, + consumers, filter, http, signal: abortCtrlRef.current.signal, @@ -80,7 +86,7 @@ export function useLoadAlertSummary({ featureIds, timeRange, filter }: UseLoadAl } } } - }, [featureIds, filter, http, timeRange]); + }, [ruleTypeIds, consumers, filter, http, timeRange]); useEffect(() => { loadAlertSummary(); @@ -90,26 +96,29 @@ export function useLoadAlertSummary({ featureIds, timeRange, filter }: UseLoadAl } async function fetchAlertSummary({ - featureIds, + ruleTypeIds, + consumers, filter, http, signal, timeRange: { utcFrom, utcTo, fixedInterval }, }: { http: HttpSetup; - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; signal: AbortSignal; timeRange: AlertSummaryTimeRange; filter?: estypes.QueryDslQueryContainer; }): Promise { - const res = featureIds.length + const res = ruleTypeIds.length ? await http.post>(`${BASE_RAC_ALERTS_API_PATH}/_alert_summary`, { signal, body: JSON.stringify({ fixed_interval: fixedInterval, gte: utcFrom, lte: utcTo, - featureIds, + ruleTypeIds, + consumers, filter: [filter], }), }) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx index c0e143119f6f..b84e1b529b49 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations.test.tsx @@ -5,13 +5,15 @@ * 2.0. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks/dom'; -import { useLoadRuleAggregationsQuery as useLoadRuleAggregations } from './use_load_rule_aggregations_query'; +import { waitFor, renderHook } from '@testing-library/react'; +import { + UseLoadRuleAggregationsQueryProps, + useLoadRuleAggregationsQuery as useLoadRuleAggregations, +} from './use_load_rule_aggregations_query'; import { RuleStatus } from '../../types'; import { useKibana } from '../../common/lib/kibana'; import { IToasts } from '@kbn/core-notifications-browser'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { waitFor } from '@testing-library/react'; jest.mock('../../common/lib/kibana'); jest.mock('../lib/rule_api/aggregate_kuery_filter', () => ({ @@ -60,10 +62,9 @@ describe('useLoadRuleAggregations', () => { }); it('should call loadRuleAggregations API and handle result', async () => { - const params = { + const params: UseLoadRuleAggregationsQueryProps = { filters: { searchText: '', - types: [], actionTypes: [], ruleExecutionStatuses: [], ruleLastRunOutcomes: [], @@ -73,9 +74,11 @@ describe('useLoadRuleAggregations', () => { }, enabled: true, refresh: undefined, + ruleTypeIds: [], + consumers: [], }; - const { rerender, result, waitForNextUpdate } = renderHook( + const { rerender, result } = renderHook( () => { return useLoadRuleAggregations(params); }, @@ -83,27 +86,28 @@ describe('useLoadRuleAggregations', () => { ); rerender(); - await waitForNextUpdate(); - expect(loadRuleAggregationsWithKueryFilter).toBeCalledWith( - expect.objectContaining({ - searchText: '', - typesFilter: [], - actionTypesFilter: [], - ruleExecutionStatusesFilter: [], - ruleLastRunOutcomesFilter: [], - ruleStatusesFilter: [], - tagsFilter: [], - }) - ); - expect(result.current.rulesStatusesTotal).toEqual(MOCK_AGGS.ruleExecutionStatus); + await waitFor(() => { + expect(loadRuleAggregationsWithKueryFilter).toBeCalledWith( + expect.objectContaining({ + searchText: '', + actionTypesFilter: [], + ruleExecutionStatusesFilter: [], + ruleLastRunOutcomesFilter: [], + ruleStatusesFilter: [], + tagsFilter: [], + ruleTypeIds: [], + consumers: [], + }) + ); + expect(result.current.rulesStatusesTotal).toEqual(MOCK_AGGS.ruleExecutionStatus); + }); }); it('should call loadRuleAggregation API with params and handle result', async () => { - const params = { + const params: UseLoadRuleAggregationsQueryProps = { filters: { searchText: 'test', - types: ['type1', 'type2'], actionTypes: ['action1', 'action2'], ruleExecutionStatuses: ['status1', 'status2'], ruleParams: {}, @@ -113,30 +117,31 @@ describe('useLoadRuleAggregations', () => { }, enabled: true, refresh: undefined, + ruleTypeIds: ['foo'], + consumers: ['bar'], }; - const { rerender, result, waitForNextUpdate } = renderHook( - () => useLoadRuleAggregations(params), - { - wrapper, - } - ); + const { rerender, result } = renderHook(() => useLoadRuleAggregations(params), { + wrapper, + }); rerender(); - await waitForNextUpdate(); - expect(loadRuleAggregationsWithKueryFilter).toBeCalledWith( - expect.objectContaining({ - searchText: 'test', - typesFilter: ['type1', 'type2'], - actionTypesFilter: ['action1', 'action2'], - ruleExecutionStatusesFilter: ['status1', 'status2'], - ruleStatusesFilter: ['enabled', 'snoozed'] as RuleStatus[], - tagsFilter: ['tag1', 'tag2'], - ruleLastRunOutcomesFilter: ['outcome1', 'outcome2'], - }) - ); - expect(result.current.rulesStatusesTotal).toEqual(MOCK_AGGS.ruleExecutionStatus); + await waitFor(() => { + expect(loadRuleAggregationsWithKueryFilter).toBeCalledWith( + expect.objectContaining({ + searchText: 'test', + actionTypesFilter: ['action1', 'action2'], + ruleExecutionStatusesFilter: ['status1', 'status2'], + ruleStatusesFilter: ['enabled', 'snoozed'] as RuleStatus[], + tagsFilter: ['tag1', 'tag2'], + ruleLastRunOutcomesFilter: ['outcome1', 'outcome2'], + ruleTypeIds: ['foo'], + consumers: ['bar'], + }) + ); + expect(result.current.rulesStatusesTotal).toEqual(MOCK_AGGS.ruleExecutionStatus); + }); }); it('should call onError if API fails', async () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations_query.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations_query.ts index b7f5be032572..c588959dedf5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations_query.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rule_aggregations_query.ts @@ -22,15 +22,16 @@ const initializeAggregationResult = (values: readonly string[]) => { ); }; -interface UseLoadRuleAggregationsQueryProps { +export interface UseLoadRuleAggregationsQueryProps { filters: RulesListFilters; enabled: boolean; - filterConsumers?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; refresh?: Date; } export const useLoadRuleAggregationsQuery = (props: UseLoadRuleAggregationsQueryProps) => { - const { filters, enabled, refresh, filterConsumers } = props; + const { filters, enabled, refresh, ruleTypeIds, consumers } = props; const { http, @@ -41,13 +42,13 @@ export const useLoadRuleAggregationsQuery = (props: UseLoadRuleAggregationsQuery return loadRuleAggregationsWithKueryFilter({ http, searchText: filters.searchText, - typesFilter: filters.types, actionTypesFilter: filters.actionTypes, ruleExecutionStatusesFilter: filters.ruleExecutionStatuses, ruleLastRunOutcomesFilter: filters.ruleLastRunOutcomes, ruleStatusesFilter: filters.ruleStatuses, tagsFilter: filters.tags, - filterConsumers, + ruleTypeIds, + consumers, }); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx index 8cc07c87e241..3c87b04cb62e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor, renderHook } from '@testing-library/react'; import { useLoadRulesQuery as useLoadRules } from './use_load_rules_query'; import { RuleExecutionStatusErrorReasons, @@ -15,7 +15,6 @@ import { RuleStatus } from '../../types'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useKibana } from '../../common/lib/kibana'; import { IToasts } from '@kbn/core-notifications-browser'; -import { waitFor } from '@testing-library/react'; jest.mock('../../common/lib/kibana'); jest.mock('../lib/rule_api/rules_kuery_filter', () => ({ @@ -282,7 +281,7 @@ describe('useLoadRules', () => { sort: { field: 'name', direction: 'asc' }, }; - const { result, waitForNextUpdate, rerender } = renderHook(() => useLoadRules(params), { + const { result, rerender } = renderHook(() => useLoadRules(params), { wrapper, }); @@ -291,11 +290,10 @@ describe('useLoadRules', () => { expect(result.current.rulesState.isLoading).toBeTruthy(); rerender(); - await waitForNextUpdate(); + await waitFor(() => expect(result.current.rulesState.isLoading).toBeFalsy()); expect(result.current.rulesState.initialLoad).toBeFalsy(); expect(result.current.hasData).toBeTruthy(); - expect(result.current.rulesState.isLoading).toBeFalsy(); expect(onPage).toBeCalledTimes(0); expect(loadRulesWithKueryFilter).toBeCalledWith( @@ -339,29 +337,29 @@ describe('useLoadRules', () => { sort: { field: 'name', direction: 'asc' }, }; - const { waitForNextUpdate, rerender } = renderHook(() => useLoadRules(params), { + const { rerender } = renderHook(() => useLoadRules(params), { wrapper, }); rerender(); - await waitForNextUpdate(); - - expect(loadRulesWithKueryFilter).toBeCalledWith( - expect.objectContaining({ - page: { - index: 0, - size: 25, - }, - searchText: 'test', - typesFilter: ['type1', 'type2'], - actionTypesFilter: ['action1', 'action2'], - ruleExecutionStatusesFilter: ['status1', 'status2'], - ruleLastRunOutcomesFilter: ['outcome1', 'outcome2'], - ruleParamsFilter: {}, - ruleStatusesFilter: ['enabled', 'snoozed'], - tagsFilter: ['tag1', 'tag2'], - sort: { field: 'name', direction: 'asc' }, - }) + await waitFor(() => + expect(loadRulesWithKueryFilter).toBeCalledWith( + expect.objectContaining({ + page: { + index: 0, + size: 25, + }, + searchText: 'test', + typesFilter: ['type1', 'type2'], + actionTypesFilter: ['action1', 'action2'], + ruleExecutionStatusesFilter: ['status1', 'status2'], + ruleLastRunOutcomesFilter: ['outcome1', 'outcome2'], + ruleParamsFilter: {}, + ruleStatusesFilter: ['enabled', 'snoozed'], + tagsFilter: ['tag1', 'tag2'], + sort: { field: 'name', direction: 'asc' }, + }) + ) ); }); @@ -391,7 +389,7 @@ describe('useLoadRules', () => { sort: { field: 'name', direction: 'asc' }, }; - const { rerender, waitForNextUpdate } = renderHook( + const { rerender } = renderHook( () => { return useLoadRules(params); }, @@ -399,12 +397,12 @@ describe('useLoadRules', () => { ); rerender(); - await waitForNextUpdate(); - - expect(onPage).toHaveBeenCalledWith({ - index: 0, - size: 25, - }); + await waitFor(() => + expect(onPage).toHaveBeenCalledWith({ + index: 0, + size: 25, + }) + ); }); it('should call onError if API fails', async () => { @@ -459,16 +457,14 @@ describe('useLoadRules', () => { sort: { field: 'name', direction: 'asc' }, }; - const { rerender, result, waitForNextUpdate } = renderHook(() => useLoadRules(params), { + const { rerender, result } = renderHook(() => useLoadRules(params), { wrapper, }); expect(result.current.hasData).toBeFalsy(); rerender(); - await waitForNextUpdate(); - - expect(result.current.hasData).toBeFalsy(); + await waitFor(() => expect(result.current.hasData).toBeFalsy()); }); it('hasData should be false, if there is rule types filter and no rules with hasDefaultRuleTypesFiltersOn = true', async () => { @@ -494,16 +490,14 @@ describe('useLoadRules', () => { hasDefaultRuleTypesFiltersOn: true, }; - const { rerender, result, waitForNextUpdate } = renderHook(() => useLoadRules(params), { + const { rerender, result } = renderHook(() => useLoadRules(params), { wrapper, }); expect(result.current.hasData).toBeFalsy(); rerender(); - await waitForNextUpdate(); - - expect(result.current.hasData).toBeFalsy(); + await waitFor(() => expect(result.current.hasData).toBeFalsy()); }); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules_query.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules_query.ts index 795e31678689..7806e6ce1e6a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules_query.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_rules_query.ts @@ -20,7 +20,8 @@ type UseLoadRulesQueryProps = Omit & { sort: LoadRulesProps['sort']; enabled: boolean; refresh?: Date; - filterConsumers?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; hasReference?: { type: string; id: string; @@ -28,7 +29,8 @@ type UseLoadRulesQueryProps = Omit & { }; export const useLoadRulesQuery = (props: UseLoadRulesQueryProps) => { - const { filterConsumers, filters, page, sort, onPage, enabled, refresh, hasReference } = props; + const { ruleTypeIds, consumers, filters, page, sort, onPage, enabled, refresh, hasReference } = + props; const { http, notifications: { toasts }, @@ -56,7 +58,7 @@ export const useLoadRulesQuery = (props: UseLoadRulesQueryProps) => { { refresh: refresh?.toISOString(), }, - filterConsumers, + ruleTypeIds, hasReference, ], queryFn: () => { @@ -73,7 +75,8 @@ export const useLoadRulesQuery = (props: UseLoadRulesQueryProps) => { tagsFilter: filters.tags, kueryNode: filters.kueryNode, sort, - filterConsumers, + ruleTypeIds, + consumers, hasReference, }); }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx index 081538d1432e..3aa1bcbf07b2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_load_tags_query.test.tsx @@ -5,12 +5,11 @@ * 2.0. */ import React from 'react'; -import { renderHook } from '@testing-library/react-hooks/dom'; +import { waitFor, renderHook } from '@testing-library/react'; import { useLoadTagsQuery } from './use_load_tags_query'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { useKibana } from '../../common/lib/kibana'; import { IToasts } from '@kbn/core-notifications-browser'; -import { waitFor } from '@testing-library/react'; const MOCK_TAGS = ['a', 'b', 'c']; @@ -53,7 +52,7 @@ describe('useLoadTagsQuery', () => { }); it('should call loadRuleTags API and handle result', async () => { - const { rerender, result, waitForNextUpdate } = renderHook( + const { rerender, result } = renderHook( () => useLoadTagsQuery({ enabled: true, @@ -67,18 +66,18 @@ describe('useLoadTagsQuery', () => { ); rerender(); - await waitForNextUpdate(); - - expect(loadRuleTags).toHaveBeenLastCalledWith( - expect.objectContaining({ - search: 'test', - perPage: 50, - page: 1, - }) - ); + await waitFor(() => { + expect(loadRuleTags).toHaveBeenLastCalledWith( + expect.objectContaining({ + search: 'test', + perPage: 50, + page: 1, + }) + ); - expect(result.current.tags).toEqual(MOCK_TAGS); - expect(result.current.hasNextPage).toEqual(false); + expect(result.current.tags).toEqual(MOCK_TAGS); + expect(result.current.hasNextPage).toEqual(false); + }); }); it('should support pagination', async () => { @@ -88,7 +87,7 @@ describe('useLoadTagsQuery', () => { perPage: 5, total: 10, }); - const { rerender, result, waitForNextUpdate } = renderHook( + const { rerender, result } = renderHook( () => useLoadTagsQuery({ enabled: true, @@ -101,17 +100,17 @@ describe('useLoadTagsQuery', () => { ); rerender(); - await waitForNextUpdate(); - - expect(loadRuleTags).toHaveBeenLastCalledWith( - expect.objectContaining({ - perPage: 5, - page: 1, - }) - ); + await waitFor(() => { + expect(loadRuleTags).toHaveBeenLastCalledWith( + expect.objectContaining({ + perPage: 5, + page: 1, + }) + ); - expect(result.current.tags).toEqual(['a', 'b', 'c', 'd', 'e']); - expect(result.current.hasNextPage).toEqual(true); + expect(result.current.tags).toEqual(['a', 'b', 'c', 'd', 'e']); + expect(result.current.hasNextPage).toEqual(true); + }); loadRuleTags.mockResolvedValue({ data: ['a', 'b', 'c', 'd', 'e'], @@ -119,6 +118,7 @@ describe('useLoadTagsQuery', () => { perPage: 5, total: 10, }); + result.current.fetchNextPage(); expect(loadRuleTags).toHaveBeenLastCalledWith( @@ -129,9 +129,7 @@ describe('useLoadTagsQuery', () => { ); rerender(); - await waitForNextUpdate(); - - expect(result.current.hasNextPage).toEqual(false); + await waitFor(() => expect(result.current.hasNextPage).toEqual(false)); }); it('should support pagination when there are no tags', async () => { @@ -142,7 +140,7 @@ describe('useLoadTagsQuery', () => { total: 0, }); - const { rerender, result, waitForNextUpdate } = renderHook( + const { rerender, result } = renderHook( () => useLoadTagsQuery({ enabled: true, @@ -155,17 +153,17 @@ describe('useLoadTagsQuery', () => { ); rerender(); - await waitForNextUpdate(); - - expect(loadRuleTags).toHaveBeenLastCalledWith( - expect.objectContaining({ - perPage: 5, - page: 1, - }) - ); + await waitFor(() => { + expect(loadRuleTags).toHaveBeenLastCalledWith( + expect.objectContaining({ + perPage: 5, + page: 1, + }) + ); - expect(result.current.tags).toEqual([]); - expect(result.current.hasNextPage).toEqual(false); + expect(result.current.tags).toEqual([]); + expect(result.current.hasNextPage).toEqual(false); + }); }); it('should call onError if API fails', async () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts deleted file mode 100644 index 91aaf19776d8..000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_rule_aad_fields.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { DataViewField } from '@kbn/data-views-plugin/common'; -import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { useQuery } from '@tanstack/react-query'; -import { i18n } from '@kbn/i18n'; -import { useMemo } from 'react'; -import { fetchRuleTypeAadTemplateFields } from '@kbn/alerts-ui-shared/src/common/apis/fetch_rule_type_aad_template_fields'; -import { TriggersAndActionsUiServices } from '../..'; - -const EMPTY_AAD_FIELDS: DataViewField[] = []; - -export function useRuleAADFields(ruleTypeId?: string): { - aadFields: DataViewField[]; - loading: boolean; -} { - const { - http, - notifications: { toasts }, - } = useKibana().services; - - const queryAadFieldsFn = () => { - return fetchRuleTypeAadTemplateFields({ http, ruleTypeId }); - }; - - const onErrorFn = () => { - toasts.addDanger( - i18n.translate('xpack.triggersActionsUI.useRuleAADFields.errorMessage', { - defaultMessage: 'Unable to load alert fields per rule type', - }) - ); - }; - - const { - data: aadFields = EMPTY_AAD_FIELDS, - isInitialLoading, - isLoading, - } = useQuery({ - queryKey: ['loadAlertAadFieldsPerRuleType', ruleTypeId], - queryFn: queryAadFieldsFn, - onError: onErrorFn, - refetchOnWindowFocus: false, - enabled: ruleTypeId !== undefined, - }); - - return useMemo( - () => ({ - aadFields, - loading: ruleTypeId === undefined ? false : isInitialLoading || isLoading, - }), - [aadFields, isInitialLoading, isLoading, ruleTypeId] - ); -} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_sub_action.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_sub_action.test.tsx index 1f2552511de0..161f1564b1dd 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_sub_action.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_sub_action.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../common/lib/kibana'; import { useSubAction, UseSubActionParams } from './use_sub_action'; @@ -30,102 +30,96 @@ describe('useSubAction', () => { }); it('init', async () => { - const { result, waitForNextUpdate } = renderHook(() => useSubAction(params)); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - isLoading: false, - response: {}, - error: null, - }); + const { result } = renderHook(() => useSubAction(params)); + await waitFor(() => + expect(result.current).toEqual({ + isLoading: false, + response: {}, + error: null, + }) + ); }); it('executes the sub action correctly', async () => { - const { waitForNextUpdate } = renderHook(() => useSubAction(params)); - await waitForNextUpdate(); - - expect(mockHttpPost).toHaveBeenCalledWith('/api/actions/connector/test-id/_execute', { - body: '{"params":{"subAction":"test","subActionParams":{"foo":"bar"}}}', - signal: new AbortController().signal, - }); + renderHook(() => useSubAction(params)); + await waitFor(() => + expect(mockHttpPost).toHaveBeenCalledWith('/api/actions/connector/test-id/_execute', { + body: '{"params":{"subAction":"test","subActionParams":{"foo":"bar"}}}', + signal: new AbortController().signal, + }) + ); }); it('executes sub action if subAction parameter changes', async () => { - const { rerender, waitForNextUpdate } = renderHook(useSubAction, { initialProps: params }); - await waitForNextUpdate(); - - expect(mockHttpPost).toHaveBeenCalledTimes(1); + const { rerender } = renderHook(useSubAction, { initialProps: params }); + await waitFor(() => expect(mockHttpPost).toHaveBeenCalledTimes(1)); await act(async () => { rerender({ ...params, subAction: 'test-2' }); - await waitForNextUpdate(); }); - expect(mockHttpPost).toHaveBeenCalledTimes(2); + await waitFor(() => expect(mockHttpPost).toHaveBeenCalledTimes(2)); }); it('executes sub action if connectorId parameter changes', async () => { - const { rerender, waitForNextUpdate } = renderHook(useSubAction, { initialProps: params }); - await waitForNextUpdate(); - - expect(mockHttpPost).toHaveBeenCalledTimes(1); + const { rerender } = renderHook(useSubAction, { initialProps: params }); + await waitFor(() => expect(mockHttpPost).toHaveBeenCalledTimes(1)); await act(async () => { rerender({ ...params, connectorId: 'test-id-2' }); - await waitForNextUpdate(); }); - expect(mockHttpPost).toHaveBeenCalledTimes(2); + await waitFor(() => expect(mockHttpPost).toHaveBeenCalledTimes(2)); }); it('returns memoized response if subActionParams changes but values are equal', async () => { - const { result, rerender, waitForNextUpdate } = renderHook(useSubAction, { + const { result, rerender } = renderHook(useSubAction, { initialProps: { ...params, subActionParams: { foo: 'bar' } }, }); - await waitForNextUpdate(); + await waitFor(() => expect(mockHttpPost).toHaveBeenCalledTimes(1)); - expect(mockHttpPost).toHaveBeenCalledTimes(1); const previous = result.current; await act(async () => { rerender({ ...params, subActionParams: { foo: 'bar' } }); - await waitForNextUpdate(); }); - expect(result.current.response).toBe(previous.response); - expect(mockHttpPost).toHaveBeenCalledTimes(1); + await waitFor(() => { + expect(result.current.response).toBe(previous.response); + expect(mockHttpPost).toHaveBeenCalledTimes(1); + }); }); it('executes sub action if subActionParams changes and values are not equal', async () => { - const { result, rerender, waitForNextUpdate } = renderHook(useSubAction, { + const { result, rerender } = renderHook(useSubAction, { initialProps: { ...params, subActionParams: { foo: 'bar' } }, }); - await waitForNextUpdate(); + await waitFor(() => expect(mockHttpPost).toHaveBeenCalledTimes(1)); - expect(mockHttpPost).toHaveBeenCalledTimes(1); const previous = result.current; await act(async () => { rerender({ ...params, subActionParams: { foo: 'baz' } }); - await waitForNextUpdate(); }); - expect(result.current.response).not.toBe(previous.response); - expect(mockHttpPost).toHaveBeenCalledTimes(2); + await waitFor(() => { + expect(result.current.response).not.toBe(previous.response); + expect(mockHttpPost).toHaveBeenCalledTimes(2); + }); }); it('returns an error correctly', async () => { const error = new Error('error executing'); mockHttpPost.mockRejectedValueOnce(error); - const { result, waitForNextUpdate } = renderHook(() => useSubAction(params)); - await waitForNextUpdate(); - - expect(result.current).toEqual({ - isLoading: false, - response: undefined, - error, - }); + const { result } = renderHook(() => useSubAction(params)); + await waitFor(() => + expect(result.current).toEqual({ + isLoading: false, + response: undefined, + error, + }) + ); }); it('should abort on unmount', async () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx index c5f61885addd..e1a04ea929b5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/hooks/use_update_rules_settings.test.tsx @@ -6,8 +6,7 @@ */ import React from 'react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { act, renderHook } from '@testing-library/react-hooks/dom'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook, act } from '@testing-library/react'; import { useUpdateRuleSettings } from './use_update_rules_settings'; const mockAddDanger = jest.fn(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/check_rule_type_enabled.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/lib/check_rule_type_enabled.test.tsx index 0668fb56c4ef..5771b505ae0c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/check_rule_type_enabled.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/check_rule_type_enabled.test.tsx @@ -33,6 +33,7 @@ describe('checkRuleTypeEnabled', () => { authorizedConsumers: {}, minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', }; expect(checkRuleTypeEnabled(alertType)).toMatchInlineSnapshot(` Object { @@ -57,6 +58,7 @@ describe('checkRuleTypeEnabled', () => { authorizedConsumers: {}, minimumLicenseRequired: 'gold', enabledInLicense: false, + category: 'my-category', }; expect(checkRuleTypeEnabled(alertType)).toMatchInlineSnapshot(` Object { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/execution_duration_utils.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/execution_duration_utils.test.ts index f7ade3778f28..7bce422f5f9f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/execution_duration_utils.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/execution_duration_utils.test.ts @@ -63,6 +63,7 @@ function mockRuleType(overwrites: Partial = {}): RuleType { producer: 'alerts', minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', ...overwrites, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.test.ts index a5ae973f14d9..b546748d695e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.test.ts @@ -113,7 +113,7 @@ describe('loadRuleAggregations', () => { `); }); - test('should call aggregate API with typesFilter', async () => { + test('should call aggregate API with ruleTypeIds', async () => { const resolvedValue = { rule_execution_status: { ok: 4, @@ -127,7 +127,7 @@ describe('loadRuleAggregations', () => { const result = await loadRuleAggregations({ http, - typesFilter: ['foo', 'bar'], + ruleTypeIds: ['foo', 'bar'], }); expect(result).toEqual({ ruleExecutionStatus: { @@ -142,13 +142,13 @@ describe('loadRuleAggregations', () => { Array [ "/internal/alerting/rules/_aggregate", Object { - "body": "{\\"filter\\":\\"alert.attributes.alertTypeId:(foo or bar)\\",\\"default_search_operator\\":\\"AND\\"}", + "body": "{\\"default_search_operator\\":\\"AND\\",\\"rule_type_ids\\":[\\"foo\\",\\"bar\\"]}", }, ] `); }); - test('should call aggregate API with actionTypesFilter and typesFilter', async () => { + test('should call aggregate API with actionTypesFilter and ruleTypeIds', async () => { const resolvedValue = { rule_execution_status: { ok: 4, @@ -164,7 +164,7 @@ describe('loadRuleAggregations', () => { http, searchText: 'baz', actionTypesFilter: ['action', 'type'], - typesFilter: ['foo', 'bar'], + ruleTypeIds: ['foo', 'bar'], }); expect(result).toEqual({ ruleExecutionStatus: { @@ -179,7 +179,7 @@ describe('loadRuleAggregations', () => { Array [ "/internal/alerting/rules/_aggregate", Object { - "body": "{\\"search_fields\\":\\"[\\\\\\"name\\\\\\",\\\\\\"tags\\\\\\"]\\",\\"search\\":\\"baz\\",\\"filter\\":\\"alert.attributes.alertTypeId:(foo or bar) and (alert.attributes.actions:{ actionTypeId:action } OR alert.attributes.actions:{ actionTypeId:type })\\",\\"default_search_operator\\":\\"AND\\"}", + "body": "{\\"search_fields\\":\\"[\\\\\\"name\\\\\\",\\\\\\"tags\\\\\\"]\\",\\"search\\":\\"baz\\",\\"filter\\":\\"(alert.attributes.actions:{ actionTypeId:action } OR alert.attributes.actions:{ actionTypeId:type })\\",\\"default_search_operator\\":\\"AND\\",\\"rule_type_ids\\":[\\"foo\\",\\"bar\\"]}", }, ] `); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts index 8edb10811bd8..af855075cca8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate.ts @@ -39,15 +39,14 @@ export async function loadRuleTags({ export async function loadRuleAggregations({ http, searchText, - typesFilter, actionTypesFilter, ruleExecutionStatusesFilter, ruleStatusesFilter, tagsFilter, - filterConsumers, + ruleTypeIds, + consumers, }: LoadRuleAggregationsProps): Promise { const filters = mapFiltersToKql({ - typesFilter, actionTypesFilter, ruleExecutionStatusesFilter, ruleStatusesFilter, @@ -61,7 +60,8 @@ export async function loadRuleAggregations({ search: searchText, filter: filters.length ? filters.join(' and ') : undefined, default_search_operator: 'AND', - filter_consumers: filterConsumers, + rule_type_ids: ruleTypeIds, + consumers, }), } ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_helpers.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_helpers.ts index 29462f07d5ee..fb787c249aeb 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_helpers.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_helpers.ts @@ -61,13 +61,13 @@ export const rewriteTagsBodyRes: RewriteRequestCase = ({ export interface LoadRuleAggregationsProps { http: HttpSetup; searchText?: string; - typesFilter?: string[]; actionTypesFilter?: string[]; ruleExecutionStatusesFilter?: string[]; ruleLastRunOutcomesFilter?: string[]; ruleStatusesFilter?: RuleStatus[]; tagsFilter?: string[]; - filterConsumers?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; } export interface LoadRuleTagsProps { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.test.ts new file mode 100644 index 000000000000..a76147033fe6 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.test.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { httpServiceMock } from '@kbn/core/public/mocks'; +import { loadRuleAggregationsWithKueryFilter } from './aggregate_kuery_filter'; + +const http = httpServiceMock.createStartContract(); + +describe('loadRuleAggregationsWithKueryFilter', () => { + beforeEach(() => jest.resetAllMocks()); + + test('should call aggregate API with base parameters', async () => { + const resolvedValue = { + rule_execution_status: { + ok: 4, + active: 2, + error: 1, + pending: 1, + unknown: 0, + }, + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRuleAggregationsWithKueryFilter({ http }); + expect(result).toEqual({ + ruleExecutionStatus: { + ok: 4, + active: 2, + error: 1, + pending: 1, + unknown: 0, + }, + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_aggregate", + Object { + "body": "{\\"default_search_operator\\":\\"AND\\"}", + }, + ] + `); + }); + + test('should call aggregate API with ruleTypeIds', async () => { + const resolvedValue = { + rule_execution_status: { + ok: 4, + active: 2, + error: 1, + pending: 1, + unknown: 0, + }, + }; + + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRuleAggregationsWithKueryFilter({ http, ruleTypeIds: ['foo'] }); + expect(result).toEqual({ + ruleExecutionStatus: { + ok: 4, + active: 2, + error: 1, + pending: 1, + unknown: 0, + }, + }); + + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_aggregate", + Object { + "body": "{\\"rule_type_ids\\":[\\"foo\\"],\\"default_search_operator\\":\\"AND\\"}", + }, + ] + `); + }); + + test('should call aggregate API with consumers', async () => { + const resolvedValue = { + rule_execution_status: { + ok: 4, + active: 2, + error: 1, + pending: 1, + unknown: 0, + }, + }; + + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRuleAggregationsWithKueryFilter({ http, consumers: ['foo'] }); + expect(result).toEqual({ + ruleExecutionStatus: { + ok: 4, + active: 2, + error: 1, + pending: 1, + unknown: 0, + }, + }); + + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_aggregate", + Object { + "body": "{\\"default_search_operator\\":\\"AND\\",\\"consumers\\":[\\"foo\\"]}", + }, + ] + `); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.ts index a0e270ddf2f6..dce41afcc811 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/aggregate_kuery_filter.ts @@ -16,15 +16,14 @@ import { mapFiltersToKueryNode } from './map_filters_to_kuery_node'; export async function loadRuleAggregationsWithKueryFilter({ http, searchText, - typesFilter, actionTypesFilter, ruleExecutionStatusesFilter, ruleStatusesFilter, tagsFilter, - filterConsumers, + ruleTypeIds, + consumers, }: LoadRuleAggregationsProps): Promise { const filtersKueryNode = mapFiltersToKueryNode({ - typesFilter, actionTypesFilter, tagsFilter, ruleExecutionStatusesFilter, @@ -37,8 +36,9 @@ export async function loadRuleAggregationsWithKueryFilter({ { body: JSON.stringify({ ...(filtersKueryNode ? { filter: JSON.stringify(filtersKueryNode) } : {}), - filter_consumers: filterConsumers, + rule_type_ids: ruleTypeIds, default_search_operator: 'AND', + consumers, }), } ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_fields.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_fields.ts deleted file mode 100644 index 7be5b3eec0e6..000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_fields.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { ValidFeatureId } from '@kbn/rule-data-utils'; -import { HttpSetup } from '@kbn/core/public'; -import { FieldSpec } from '@kbn/data-views-plugin/common'; -import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; - -export async function fetchAlertFields({ - http, - featureIds, -}: { - http: HttpSetup; - featureIds: ValidFeatureId[]; -}): Promise { - const { fields: alertFields = [] } = await http.get<{ fields: FieldSpec[] }>( - `${BASE_RAC_ALERTS_API_PATH}/browser_fields`, - { - query: { featureIds }, - } - ); - return alertFields; -} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_index.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_index.ts deleted file mode 100644 index 8ac678664168..000000000000 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/alert_index.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { BASE_RAC_ALERTS_API_PATH } from '@kbn/rule-registry-plugin/common'; -import { HttpSetup } from '@kbn/core/public'; - -export async function fetchAlertIndexNames({ - http, - features, -}: { - http: HttpSetup; - features: string; -}): Promise { - const { index_name: indexNamesStr = [] } = await http.get<{ index_name: string[] }>( - `${BASE_RAC_ALERTS_API_PATH}/index`, - { - query: { features }, - } - ); - return indexNamesStr; -} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_types.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_types.test.ts index cd9e829c8045..0c42a21d7d43 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_types.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rule_types.test.ts @@ -30,6 +30,7 @@ describe('loadRuleTypes', () => { authorizedConsumers: {}, minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', }, ]; http.get.mockResolvedValueOnce(resolvedValue); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.test.ts index b5a09e5a716f..5fa4f8350965 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.test.ts @@ -240,6 +240,55 @@ describe('loadRules', () => { `); }); + test('should call find API with searchText and tagsFilter and ruleTypeIds and consumers', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadRules({ + http, + searchText: 'apples, foo, baz', + typesFilter: ['foo', 'bar'], + ruleTypeIds: ['one', 'two'], + consumers: ['my-consumer'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "query": Object { + "consumers": Array [ + "my-consumer", + ], + "default_search_operator": "AND", + "filter": "alert.attributes.alertTypeId:(foo or bar)", + "page": 1, + "per_page": 10, + "rule_type_ids": Array [ + "one", + "two", + ], + "search": "apples, foo, baz", + "search_fields": "[\\"name\\",\\"tags\\"]", + "sort_field": "name", + "sort_order": "asc", + }, + }, + ] + `); + }); + test('should call find API with ruleStatusesFilter', async () => { const resolvedValue = { page: 1, @@ -374,4 +423,90 @@ describe('loadRules', () => { ] `); }); + + test('should call find API with ruleTypeIds', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadRules({ + http, + ruleTypeIds: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "query": Object { + "default_search_operator": "AND", + "filter": undefined, + "page": 1, + "per_page": 10, + "rule_type_ids": Array [ + "foo", + "bar", + ], + "search": undefined, + "search_fields": undefined, + "sort_field": "name", + "sort_order": "asc", + }, + }, + ] + `); + }); + + test('should call find API with consumers', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.get.mockResolvedValueOnce(resolvedValue); + + const result = await loadRules({ + http, + consumers: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.get.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "query": Object { + "consumers": Array [ + "foo", + "bar", + ], + "default_search_operator": "AND", + "filter": undefined, + "page": 1, + "per_page": 10, + "search": undefined, + "search_fields": undefined, + "sort_field": "name", + "sort_order": "asc", + }, + }, + ] + `); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.ts index 07a992c66c96..8c17f18065c8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules.ts @@ -21,6 +21,8 @@ export async function loadRules({ ruleStatusesFilter, tagsFilter, sort = { field: 'name', direction: 'asc' }, + ruleTypeIds, + consumers, }: LoadRulesProps): Promise<{ page: number; perPage: number; @@ -51,6 +53,8 @@ export async function loadRules({ default_search_operator: 'AND', sort_field: sort.field, sort_order: sort.direction, + ...(ruleTypeIds ? { rule_type_ids: ruleTypeIds } : {}), + ...(consumers ? { consumers } : {}), }, }); return { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_helpers.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_helpers.ts index 4f8a8627bab5..aa1e2d1dac26 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_helpers.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_helpers.ts @@ -24,7 +24,8 @@ export interface LoadRulesProps { ruleStatusesFilter?: RuleStatus[]; sort?: Sorting; kueryNode?: KueryNode; - filterConsumers?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; hasReference?: { type: string; id: string; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.test.ts new file mode 100644 index 000000000000..9e9821b8d82c --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.test.ts @@ -0,0 +1,384 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { httpServiceMock } from '@kbn/core/public/mocks'; +import { loadRulesWithKueryFilter } from './rules_kuery_filter'; + +const http = httpServiceMock.createStartContract(); + +describe('loadRulesWithKueryFilter', () => { + beforeEach(() => jest.resetAllMocks()); + + test('should call find API with base parameters', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ http, page: { index: 0, size: 10 } }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with searchText', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + searchText: 'apples', + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.name\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"apples\\\\\\"}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"apples\\\\\\"}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with actionTypesFilter', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + searchText: 'foo', + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.name\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"foo\\\\\\"}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"foo\\\\\\"}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with typesFilter', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + typesFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"foo\\\\\\",\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"bar\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with actionTypesFilter and typesFilter', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + searchText: 'baz', + typesFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"and\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"foo\\\\\\",\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"bar\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.name\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"baz\\\\\\"}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"baz\\\\\\"}]}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with searchText and tagsFilter and typesFilter', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + searchText: 'apples, foo, baz', + typesFilter: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"and\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"foo\\\\\\",\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"bar\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.name\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"apples, foo, baz\\\\\\"}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"apples, foo, baz\\\\\\"}]}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with searchText and tagsFilter and ruleTypeIds and consumers', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + searchText: 'apples, foo, baz', + typesFilter: ['foo', 'bar'], + ruleTypeIds: ['one', 'two'], + consumers: ['my-consumer'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"and\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"foo\\\\\\",\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.alertTypeId\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"bar\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.name\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"apples, foo, baz\\\\\\"}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"wildcard\\\\\\",\\\\\\"value\\\\\\":\\\\\\"apples, foo, baz\\\\\\"}]}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\",\\"rule_type_ids\\":[\\"one\\",\\"two\\"],\\"consumers\\":[\\"my-consumer\\"]}", + }, + ] + `); + }); + + test('should call find API with ruleStatusesFilter', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValue(resolvedValue); + + let result = await loadRulesWithKueryFilter({ + http, + ruleStatusesFilter: ['enabled', 'snoozed'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.enabled\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":true,\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.muteAll\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":true,\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"nested\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.snoozeSchedule\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"range\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"duration\\\\\\",\\\\\\"isQuoted\\\\\\":false},\\\\\\"gt\\\\\\",{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"0\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + + result = await loadRulesWithKueryFilter({ + http, + ruleStatusesFilter: ['disabled'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[1]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.enabled\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":false,\\\\\\"isQuoted\\\\\\":false}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + + result = await loadRulesWithKueryFilter({ + http, + ruleStatusesFilter: ['enabled', 'disabled', 'snoozed'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[2]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.enabled\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":true,\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.enabled\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":false,\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.muteAll\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":true,\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"nested\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.snoozeSchedule\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"range\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"duration\\\\\\",\\\\\\"isQuoted\\\\\\":false},\\\\\\"gt\\\\\\",{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"0\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with tagsFilter', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + const result = await loadRulesWithKueryFilter({ + http, + tagsFilter: ['a', 'b', 'c'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"filter\\":\\"{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"or\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"a\\\\\\",\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"b\\\\\\",\\\\\\"isQuoted\\\\\\":false}]},{\\\\\\"type\\\\\\":\\\\\\"function\\\\\\",\\\\\\"function\\\\\\":\\\\\\"is\\\\\\",\\\\\\"arguments\\\\\\":[{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"alert.attributes.tags\\\\\\",\\\\\\"isQuoted\\\\\\":false},{\\\\\\"type\\\\\\":\\\\\\"literal\\\\\\",\\\\\\"value\\\\\\":\\\\\\"c\\\\\\",\\\\\\"isQuoted\\\\\\":false}]}]}\\",\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\"}", + }, + ] + `); + }); + + test('should call find API with ruleTypeIds', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + ruleTypeIds: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\",\\"rule_type_ids\\":[\\"foo\\",\\"bar\\"]}", + }, + ] + `); + }); + + test('should call find API with consumers', async () => { + const resolvedValue = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + http.post.mockResolvedValueOnce(resolvedValue); + + const result = await loadRulesWithKueryFilter({ + http, + consumers: ['foo', 'bar'], + page: { index: 0, size: 10 }, + }); + expect(result).toEqual({ + page: 1, + perPage: 10, + total: 0, + data: [], + }); + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"page\\":1,\\"per_page\\":10,\\"sort_field\\":\\"name\\",\\"sort_order\\":\\"asc\\",\\"consumers\\":[\\"foo\\",\\"bar\\"]}", + }, + ] + `); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.ts index 7c731dbfb016..c765f8f47804 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/rules_kuery_filter.ts @@ -24,8 +24,9 @@ export async function loadRulesWithKueryFilter({ tagsFilter, sort = { field: 'name', direction: 'asc' }, kueryNode, - filterConsumers, + ruleTypeIds, hasReference, + consumers, }: LoadRulesProps): Promise<{ page: number; perPage: number; @@ -58,8 +59,9 @@ export async function loadRulesWithKueryFilter({ ...(filtersKueryNode ? { filter: JSON.stringify(filtersKueryNode) } : {}), sort_field: sort.field, sort_order: sort.direction, - filter_consumers: filterConsumers, ...(hasReference ? { has_reference: hasReference } : {}), + ...(ruleTypeIds ? { rule_type_ids: ruleTypeIds } : {}), + ...(consumers ? { consumers } : {}), }), }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/search_filters.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/search_filters.ts index 3ae6a01633e4..532f49a159c8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/search_filters.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/search_filters.ts @@ -11,72 +11,78 @@ import { AlertConsumers, DefaultAlertFieldName, } from '@kbn/rule-data-utils'; -import { FILTERS, FilterStateStore, PhraseFilter, PhrasesFilter } from '@kbn/es-query'; +import { FILTERS, FilterStateStore, PhrasesFilter } from '@kbn/es-query'; const $state = { store: FilterStateStore.APP_STATE, }; export type AlertsFeatureIdsFilter = PhrasesFilter & { - meta: Pick & { alertsFeatureIds: AlertConsumers[] }; + meta: PhrasesFilter['meta'] & { ruleTypeIds: string[]; consumers: string[] }; }; /** * Creates a match_phrase filter without an index pattern */ -export const createMatchPhraseFilter = (field: DefaultAlertFieldName, value: unknown) => - ({ - meta: { - field, - type: FILTERS.PHRASE, - key: field, - alias: null, - disabled: false, - index: undefined, - negate: false, - params: { query: value }, - value: undefined, - }, - $state, - query: { - match_phrase: { - [field]: value, - }, +export const createMatchPhraseFilter = ( + field: DefaultAlertFieldName, + value: string +): AlertsFeatureIdsFilter => ({ + meta: { + field, + type: FILTERS.PHRASE, + key: field, + alias: null, + disabled: false, + index: undefined, + negate: false, + // @ts-expect-error + params: { query: value }, + value: undefined, + ruleTypeIds: [], + consumers: [], + }, + $state, + query: { + match_phrase: { + [field]: value, }, - } as PhraseFilter); + }, +}); /** * Creates a match_phrases filter without an index pattern */ export const createMatchPhrasesFilter = ( field: DefaultAlertFieldName, - values: unknown[], + values: string[], alias: string | null = null -) => - ({ - meta: { - field, - type: FILTERS.PHRASES, - key: field, - alias, - disabled: false, - index: undefined, - negate: false, - params: values, - value: undefined, - }, - $state, - query: { - bool: { - minimum_should_match: 1, - should: values.map((v) => ({ - match_phrase: { - [field]: v, - }, - })), - }, +): AlertsFeatureIdsFilter => ({ + meta: { + field, + type: FILTERS.PHRASES, + key: field, + alias, + disabled: false, + index: undefined, + negate: false, + params: values, + value: undefined, + ruleTypeIds: [], + consumers: [], + }, + $state, + query: { + bool: { + minimum_should_match: 1, + should: values.map((v) => ({ + match_phrase: { + [field]: v, + }, + })), }, - } as PhrasesFilter); + }, +}); /** * Creates a match_phrase filter targeted to filtering alerts by producer @@ -88,15 +94,12 @@ export const createRuleProducerFilter = (producer: AlertConsumers) => * Creates a match_phrase filter targeted to filtering alerts by rule type ids */ export const createRuleTypesFilter = ( - featureIds: AlertConsumers[], - alias: string, - ruleTypeIds: string[] + ruleTypeIds: string[], + consumers: string[], + alias: string ) => { - const filter = createMatchPhrasesFilter( - ALERT_RULE_TYPE_ID, - ruleTypeIds, - alias - ) as AlertsFeatureIdsFilter; - filter.meta.alertsFeatureIds = featureIds; + const filter = createMatchPhrasesFilter(ALERT_RULE_TYPE_ID, ruleTypeIds, alias); + filter.meta.ruleTypeIds = ruleTypeIds; + filter.meta.consumers = consumers; return filter; }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx index 74b528ba7a64..2c5f159d0a76 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_form.test.tsx @@ -399,6 +399,7 @@ describe('action_form', () => { } actionTypeRegistry={actionTypeRegistry} setHasActionsWithBrokenConnector={setHasActionsWithBrokenConnector} + ruleTypeId=".es-query" /> ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx index 116b416ac98f..945ab23c4361 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.test.tsx @@ -136,6 +136,7 @@ describe('action_type_form', () => { const wrapper = mountWithIntl( getActionTypeForm({ index: 1, + ruleTypeId: '.es-query', actionItem: { id: '123', actionTypeId: '.pagerduty', @@ -190,6 +191,7 @@ describe('action_type_form', () => { {getActionTypeForm({ index: 1, + ruleTypeId: '.es-query', actionItem: { id: '123', actionTypeId: '.pagerduty', @@ -239,6 +241,7 @@ describe('action_type_form', () => { {getActionTypeForm({ index: 1, + ruleTypeId: 'siem.esqlRule', actionItem: { id: '123', actionTypeId: '.pagerduty', @@ -288,6 +291,7 @@ describe('action_type_form', () => { const wrapper = mountWithIntl( getActionTypeForm({ index: 1, + ruleTypeId: '.es-query', actionItem: { id: '123', actionTypeId: '.pagerduty', @@ -340,6 +344,7 @@ describe('action_type_form', () => { const wrapper = mountWithIntl( getActionTypeForm({ index: 1, + ruleTypeId: '.es-query', actionItem: { id: '123', actionTypeId: '.pagerduty', @@ -413,6 +418,7 @@ describe('action_type_form', () => { {getActionTypeForm({ index: 1, actionItem, + ruleTypeId: '.es-query', setActionFrequencyProperty: () => { actionItem.frequency = { notifyWhen: RuleNotifyWhen.ACTIVE, @@ -551,6 +557,7 @@ describe('action_type_form', () => { {getActionTypeForm({ index: 1, + ruleTypeId: '.es-query', actionItem, notifyWhenSelectOptions: CUSTOM_NOTIFY_WHEN_OPTIONS, })} @@ -604,6 +611,7 @@ describe('action_type_form', () => { {getActionTypeForm({ index: 1, + ruleTypeId: '.es-query', actionItem, notifyWhenSelectOptions: CUSTOM_NOTIFY_WHEN_OPTIONS, })} @@ -664,7 +672,7 @@ function getActionTypeForm({ messageVariables?: ActionVariables; summaryMessageVariables?: ActionVariables; notifyWhenSelectOptions?: NotifyWhenSelectOptions[]; - ruleTypeId?: string; + ruleTypeId: string; producerId?: string; featureId?: string; }) { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx index 9af97b713dff..8e95473ceca4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/action_type_form.tsx @@ -8,7 +8,7 @@ import React, { Suspense, useEffect, useState, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { ValidFeatureId, AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertConsumers } from '@kbn/rule-data-utils'; import { EuiFlexGroup, EuiFlexItem, @@ -507,7 +507,6 @@ export const ActionTypeForm = ({ setActionAlertsFilterProperty('query', query, index)} - featureIds={[producerId as ValidFeatureId]} appName={featureId!} ruleTypeId={ruleTypeId} plugins={{ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_rules_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_rules_list.tsx index c2e89eb31fe8..719cd0fef237 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_rules_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/connector_rules_list.tsx @@ -73,7 +73,6 @@ export const ConnectorRulesList = (props: ConnectorRulesListProps) => { const ruleFilters = useMemo(() => { const baseFilters = { searchText: searchFilter, - types: ruleTypeIds, }; if (connector.isPreconfigured) { @@ -105,10 +104,11 @@ export const ConnectorRulesList = (props: ConnectorRulesListProps) => { id: connector.id, }, }; - }, [connector, searchFilter, ruleTypeIds]); + }, [connector, searchFilter]); const { rulesState } = useLoadRulesQuery({ ...ruleFilters, + ruleTypeIds, hasDefaultRuleTypesFiltersOn: ruleTypeIds.length === 0, page, sort, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx index 3fb8207e45ef..440e24017fab 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.test.tsx @@ -209,4 +209,64 @@ describe('action_type_form', () => { expect(setActionParamsProperty).toHaveBeenCalledWith('my-key', 'my-value', 1); }); + + describe('licensing', () => { + const actionTypeIndexDefaultWithLicensing = { + ...actionTypeIndexDefault, + '.test-system-action': { + ...actionTypeIndexDefault['.test-system-action'], + enabledInLicense: false, + minimumLicenseRequired: 'platinum' as const, + }, + }; + + beforeEach(() => { + const actionType = actionTypeRegistryMock.createMockActionTypeModel({ + id: '.test-system-action-with-license', + iconClass: 'test', + selectMessage: 'test', + validateParams: (): Promise> => { + const validationResult = { errors: {} }; + return Promise.resolve(validationResult); + }, + actionConnectorFields: null, + actionParamsFields: mockedActionParamsFields, + defaultActionParams: { + dedupKey: 'test', + eventAction: 'resolve', + }, + isSystemActionType: true, + }); + + actionTypeRegistry.get.mockReturnValue(actionType); + + jest.clearAllMocks(); + }); + + it('should render the licensing message if the user does not have the sufficient license', async () => { + render( + + + + ); + + expect( + await screen.findByText('This feature requires a Platinum license.') + ).toBeInTheDocument(); + }); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx index d869449bcd92..36da1b594433 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/action_connector_form/system_action_type_form.tsx @@ -28,6 +28,7 @@ import { isEmpty, partition, some } from 'lodash'; import { ActionVariable, RuleActionParam } from '@kbn/alerting-plugin/common'; import { ActionGroupWithMessageVariables } from '@kbn/triggers-actions-ui-types'; import { transformActionVariables } from '@kbn/alerts-ui-shared/src/action_variables/transforms'; +import { checkActionFormActionTypeEnabled } from '@kbn/alerts-ui-shared/src/rule_form/utils/check_action_type_enabled'; import { TECH_PREVIEW_DESCRIPTION, TECH_PREVIEW_LABEL } from '../translations'; import { IErrorObject, @@ -167,8 +168,12 @@ export const SystemActionTypeForm = ({ }; const ParamsFieldsComponent = actionTypeRegistered.actionParamsFields; + const checkEnabledResult = checkActionFormActionTypeEnabled( + actionTypesIndex[actionConnector.actionTypeId], + [] + ); - const accordionContent = ( + const accordionContent = checkEnabledResult.isEnabled ? ( <> {ParamsFieldsComponent ? ( @@ -212,6 +217,8 @@ export const SystemActionTypeForm = ({ ) : null} + ) : ( + checkEnabledResult.messageCard ); return ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.test.tsx index 743c475a287b..84c2e4c5468a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/alert_summary_widget.test.tsx @@ -52,7 +52,7 @@ describe('AlertSummaryWidget', () => { {}, @@ -34,7 +35,8 @@ export const AlertSummaryWidget = ({ isLoading, error, } = useLoadAlertSummary({ - featureIds, + ruleTypeIds, + consumers, filter, timeRange, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts index 2393ff9c16a6..88b40289cb6e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alert_summary_widget/types.ts @@ -8,7 +8,7 @@ import type { BrushEndListener, PartialTheme, SettingsProps, Theme } from '@elastic/charts'; import { estypes } from '@elastic/elasticsearch'; import { IUiSettingsClient } from '@kbn/core-ui-settings-browser'; -import { AlertStatus, ValidFeatureId } from '@kbn/rule-data-utils'; +import { AlertStatus } from '@kbn/rule-data-utils'; import { ChartsPluginStart } from '@kbn/charts-plugin/public'; export interface Alert { @@ -48,7 +48,8 @@ export interface DependencyProps { } export interface AlertSummaryWidgetProps { - featureIds?: ValidFeatureId[]; + ruleTypeIds?: string[]; + consumers?: string[]; filter?: estypes.QueryDslQueryContainer; fullSize?: boolean; onClick?: (status?: AlertStatus) => void; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/components/stack_alerts_page.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/components/stack_alerts_page.tsx index 26f4c3fd43bf..f5a39ab5ac0d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/components/stack_alerts_page.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/components/stack_alerts_page.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { lazy, Suspense, useEffect, useMemo, useState } from 'react'; +import React, { lazy, Suspense, useCallback, useEffect, useMemo, useState } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiBetaBadge, @@ -21,9 +21,10 @@ import { ALERT_STATUS_RECOVERED, ALERT_STATUS_UNTRACKED, AlertConsumers, + isSiemRuleType, } from '@kbn/rule-data-utils'; import { QueryClientProvider } from '@tanstack/react-query'; -import { BoolQuery } from '@kbn/es-query'; +import { BoolQuery, Filter } from '@kbn/es-query'; import { FormattedMessage } from '@kbn/i18n-react'; import { ALERTS_PAGE_ID } from '../../../../common/constants'; import { QuickFiltersMenuItem } from '../../alerts_search_bar/quick_filters'; @@ -31,7 +32,6 @@ import { NoPermissionPrompt } from '../../../components/prompts/no_permission_pr import { ALERT_TABLE_GLOBAL_CONFIG_ID } from '../../../constants'; import { useRuleStats } from '../hooks/use_rule_stats'; import { getAlertingSectionBreadcrumb } from '../../../lib/breadcrumb'; -import { NON_SIEM_FEATURE_IDS } from '../../alerts_search_bar/constants'; import { alertProducersData } from '../../alerts_table/constants'; import { UrlSyncedAlertsSearchBar } from '../../alerts_search_bar/url_synced_alerts_search_bar'; import { useKibana } from '../../../../common/lib/kibana'; @@ -41,11 +41,21 @@ import { Provider, } from '../../alerts_search_bar/use_alert_search_bar_state_container'; import { getCurrentDocTitle } from '../../../lib/doc_title'; -import { createMatchPhraseFilter, createRuleTypesFilter } from '../../../lib/search_filters'; +import { + AlertsFeatureIdsFilter, + createMatchPhraseFilter, + createRuleTypesFilter, +} from '../../../lib/search_filters'; import { useLoadRuleTypesQuery } from '../../../hooks/use_load_rule_types_query'; import { nonNullable } from '../../../../../common/utils'; -import { useRuleTypeIdsByFeatureId } from '../hooks/use_rule_type_ids_by_feature_id'; +import { + RuleTypeIdsByFeatureId, + useRuleTypeIdsByFeatureId, +} from '../hooks/use_rule_type_ids_by_feature_id'; import { TECH_PREVIEW_DESCRIPTION, TECH_PREVIEW_LABEL } from '../../translations'; +import { AlertsTableSupportedConsumers } from '../../alerts_table/types'; +import { NON_SIEM_CONSUMERS } from '../../alerts_search_bar/constants'; + const AlertsTable = lazy(() => import('../../alerts_table/alerts_table_state')); /** @@ -55,7 +65,7 @@ export const StackAlertsPage = () => { return ( - + ); @@ -69,61 +79,121 @@ const getFeatureFilterLabel = (featureName: string) => }, }); -const PageContent = () => { +const PageContentWrapperComponent: React.FC = () => { const { chrome: { docTitle }, setBreadcrumbs, - alertsTableConfigurationRegistry, } = useKibana().services; - const [esQuery, setEsQuery] = useState({ bool: {} } as { bool: BoolQuery }); - const [activeFeatureFilters, setActiveFeatureFilters] = useState([]); - const ruleStats = useRuleStats(); const { ruleTypesState: { data: ruleTypesIndex, initialLoad: isInitialLoadingRuleTypes }, authorizedToReadAnyRules, } = useLoadRuleTypesQuery({ filteredRuleTypes: [] }); + const ruleTypeIdsByFeatureId = useRuleTypeIdsByFeatureId(ruleTypesIndex); - const browsingSiem = useMemo( - () => activeFeatureFilters.length === 1 && activeFeatureFilters[0] === AlertConsumers.SIEM, - [activeFeatureFilters] - ); - const filteringBySolution = useMemo( - () => activeFeatureFilters.length > 0, - [activeFeatureFilters.length] + useEffect(() => { + setBreadcrumbs([getAlertingSectionBreadcrumb('alerts')]); + docTitle.change(getCurrentDocTitle('alerts')); + }, [docTitle, setBreadcrumbs]); + + return !isInitialLoadingRuleTypes ? ( + + ) : null; +}; + +const PageContentWrapper = React.memo(PageContentWrapperComponent); + +interface PageContentProps { + isLoading: boolean; + authorizedToReadAnyRules: boolean; + ruleTypeIdsByFeatureId: RuleTypeIdsByFeatureId; +} + +const PageContentComponent: React.FC = ({ + isLoading, + authorizedToReadAnyRules, + ruleTypeIdsByFeatureId, +}) => { + const { alertsTableConfigurationRegistry } = useKibana().services; + const ruleTypeIdsByFeatureIdEntries = Object.entries(ruleTypeIdsByFeatureId); + + const [esQuery, setEsQuery] = useState({ bool: {} } as { bool: BoolQuery }); + const [ruleTypeIds, setRuleTypeIds] = useState(() => + getInitialRuleTypeIds(ruleTypeIdsByFeatureId) ); - const featureIds = useMemo( - () => - filteringBySolution - ? browsingSiem - ? [AlertConsumers.SIEM] - : activeFeatureFilters - : NON_SIEM_FEATURE_IDS, - [activeFeatureFilters, browsingSiem, filteringBySolution] + + const [consumers, setConsumers] = useState(NON_SIEM_CONSUMERS); + + const [selectedFilters, setSelectedFilters] = useState([]); + const ruleStats = useRuleStats({ ruleTypeIds }); + const isFilteringSecurityRules = ruleTypeIds.every(isSiemRuleType); + + const onFilterSelected = useCallback( + (filters: Filter[]) => { + const newRuleTypeIds = [ + ...new Set( + filters + .flatMap((ruleTypeId) => (ruleTypeId as AlertsFeatureIdsFilter).meta.ruleTypeIds) + .filter(nonNullable) + ), + ]; + + const newConsumers = [ + ...new Set( + filters + .flatMap((ruleTypeId) => (ruleTypeId as AlertsFeatureIdsFilter).meta.consumers) + .filter(nonNullable) + ), + ]; + + setSelectedFilters(filters as AlertsFeatureIdsFilter[]); + + if (newRuleTypeIds.length > 0) { + setRuleTypeIds(newRuleTypeIds); + setConsumers(newConsumers); + return; + } + + setRuleTypeIds(getInitialRuleTypeIds(ruleTypeIdsByFeatureId)); + setConsumers(NON_SIEM_CONSUMERS); + }, + [ruleTypeIdsByFeatureId] ); + const quickFilters = useMemo(() => { const filters: QuickFiltersMenuItem[] = []; - if (Object.values(ruleTypeIdsByFeatureId).length > 0) { + if (ruleTypeIdsByFeatureIdEntries.length > 0) { filters.push( - ...Object.entries(ruleTypeIdsByFeatureId) - .map(([featureId, ruleTypeIds]) => { - const producerData = alertProducersData[featureId as AlertConsumers]; + ...ruleTypeIdsByFeatureIdEntries + .map(([consumer, _ruleTypeIds]) => { + const producerData = alertProducersData[consumer as AlertsTableSupportedConsumers]; if (!producerData) { return null; } + const filterLabel = getFeatureFilterLabel(producerData.displayName); - const disabled = - filteringBySolution && featureId === AlertConsumers.SIEM - ? !browsingSiem - : browsingSiem; + const shouldDisable = + (isFilteringSecurityRules && consumer !== AlertConsumers.SIEM) || + (!isFilteringSecurityRules && consumer === AlertConsumers.SIEM); + + const isQuickFilterSelected = _ruleTypeIds.every((ruleTypeId) => + ruleTypeIds.includes(ruleTypeId) + ); + + const disabled = selectedFilters.length > 0 && (shouldDisable || isQuickFilterSelected); + return { name: filterLabel, icon: producerData.icon, filter: createRuleTypesFilter( - producerData.subFeatureIds ?? [featureId as AlertConsumers], - filterLabel, - ruleTypeIds + _ruleTypeIds, + producerData.subFeatureIds ?? [consumer], + filterLabel ), disabled, }; @@ -131,6 +201,7 @@ const PageContent = () => { .filter(nonNullable) ); } + filters.push({ title: i18n.translate('xpack.triggersActionsUI.sections.globalAlerts.quickFilters.status', { defaultMessage: 'Status', @@ -142,17 +213,12 @@ const PageContent = () => { })), }); return filters; - }, [browsingSiem, filteringBySolution, ruleTypeIdsByFeatureId]); - const tableConfigurationId = useMemo( - // TODO in preparation for using solution-specific configurations - () => ALERT_TABLE_GLOBAL_CONFIG_ID, - [] - ); - - useEffect(() => { - setBreadcrumbs([getAlertingSectionBreadcrumb('alerts')]); - docTitle.change(getCurrentDocTitle('alerts')); - }, [docTitle, setBreadcrumbs]); + }, [ + isFilteringSecurityRules, + ruleTypeIds, + ruleTypeIdsByFeatureIdEntries, + selectedFilters.length, + ]); return ( <> @@ -177,28 +243,29 @@ const PageContent = () => { rightSideItems={ruleStats} /> - {!isInitialLoadingRuleTypes && !authorizedToReadAnyRules ? ( + {!isLoading && !authorizedToReadAnyRules ? ( ) : ( }> { ); }; + +const PageContent = React.memo(PageContentComponent); + +const getInitialRuleTypeIds = (ruleTypeIdsByFeatureId: RuleTypeIdsByFeatureId): string[] => + Object.entries(ruleTypeIdsByFeatureId) + .filter(([featureId]) => featureId !== AlertConsumers.SIEM) + .map(([_, _ruleTypeIds]) => _ruleTypeIds) + .flat(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_stats.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_stats.tsx index 06e371979d98..4d3841672def 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_stats.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_stats.tsx @@ -23,7 +23,12 @@ const Divider = styled.div` height: 100%; `; -export const useRuleStats = () => { +interface Props { + ruleTypeIds?: string[]; + consumers?: string[]; +} + +export const useRuleStats = ({ ruleTypeIds, consumers }: Props = {}) => { const { http, notifications: { toasts }, @@ -46,7 +51,10 @@ export const useRuleStats = () => { try { const response = await loadRuleAggregations({ http, + ruleTypeIds, + consumers, }); + const { ruleExecutionStatus, ruleMutedStatus, ruleEnabledStatus, ruleSnoozedStatus } = response; if (ruleExecutionStatus && ruleMutedStatus && ruleEnabledStatus && ruleSnoozedStatus) { @@ -73,7 +81,7 @@ export const useRuleStats = () => { } finally { setLoading(false); } - }, [http, toasts]); + }, [consumers, http, ruleTypeIds, toasts]); useEffect(() => { loadRuleStats(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.test.ts index 3fd8ec70d9ff..03f1f66ede9f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.test.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks/dom'; +import { renderHook } from '@testing-library/react'; import { useRuleTypeIdsByFeatureId } from './use_rule_type_ids_by_feature_id'; import { ruleTypesIndex } from '../../../mock/rule_types_index'; import { MULTI_CONSUMER_RULE_TYPE_IDS } from '../../../constants'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.ts index c8c5eedc3054..1380f9655d47 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_page/hooks/use_rule_type_ids_by_feature_id.ts @@ -12,7 +12,7 @@ import { observabilityFeatureIds, stackFeatureIds } from '../../alerts_table/con import { MULTI_CONSUMER_RULE_TYPE_IDS } from '../../../constants'; import { RuleTypeIndex } from '../../../../types'; -type RuleTypeIdsByFeatureId = Partial< +export type RuleTypeIdsByFeatureId = Partial< Record< | typeof AlertConsumers.SIEM | typeof AlertConsumers.OBSERVABILITY @@ -22,17 +22,20 @@ type RuleTypeIdsByFeatureId = Partial< > >; +const EMPTY_OBJECT = {}; + /** * Groups all rule type ids under their respective feature id */ export const useRuleTypeIdsByFeatureId = (ruleTypesIndex: RuleTypeIndex) => useMemo((): RuleTypeIdsByFeatureId => { if (!ruleTypesIndex?.size) { - return {}; + return EMPTY_OBJECT; } + const map = Array.from(ruleTypesIndex.entries()).reduce>>( - (types, [key, value]) => { - let producer = value.producer as keyof RuleTypeIdsByFeatureId; + (types, [ruleTypeId, ruleType]) => { + let producer = ruleType.producer as keyof RuleTypeIdsByFeatureId; // Some o11y apps are listed under 'observability' to create a grouped filter if (observabilityFeatureIds.includes(producer)) { producer = AlertConsumers.OBSERVABILITY; @@ -41,14 +44,15 @@ export const useRuleTypeIdsByFeatureId = (ruleTypesIndex: RuleTypeIndex) => if (stackFeatureIds.includes(producer)) { producer = AlertConsumers.STACK_ALERTS; } + // Multi consumer rule type ids should be listed both in Observability and Stack alerts - if (MULTI_CONSUMER_RULE_TYPE_IDS.includes(value.id)) { + if (MULTI_CONSUMER_RULE_TYPE_IDS.includes(ruleType.id)) { (types[AlertConsumers.OBSERVABILITY] = - types[AlertConsumers.OBSERVABILITY] || new Set()).add(key); + types[AlertConsumers.OBSERVABILITY] || new Set()).add(ruleTypeId); (types[AlertConsumers.STACK_ALERTS] = - types[AlertConsumers.STACK_ALERTS] || new Set()).add(key); + types[AlertConsumers.STACK_ALERTS] || new Set()).add(ruleTypeId); } else { - (types[producer] = types[producer] || new Set()).add(key); + (types[producer] = types[producer] || new Set()).add(ruleTypeId); } return types; }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx index 61fceacead34..3f285de6ead7 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.test.tsx @@ -12,14 +12,10 @@ import { Filter, FilterStateStore } from '@kbn/es-query'; import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; import { NotificationsStart } from '@kbn/core-notifications-browser'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { useLoadRuleTypesQuery } from '../../hooks/use_load_rule_types_query'; -import { useRuleAADFields } from '../../hooks/use_rule_aad_fields'; import { AlertsSearchBar } from './alerts_search_bar'; const mockDataPlugin = dataPluginMock.createStartContract(); jest.mock('@kbn/kibana-utils-plugin/public'); -jest.mock('../../hooks/use_load_rule_types_query'); -jest.mock('../../hooks/use_rule_aad_fields'); jest.mock('@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view'); jest.mock('@kbn/kibana-react-plugin/public', () => ({ ...jest.requireActual('@kbn/kibana-react-plugin/public'), @@ -41,43 +37,28 @@ jest.mocked(useAlertsDataView).mockReturnValue({ }, }); -jest.mocked(useLoadRuleTypesQuery).mockReturnValue({ - ruleTypesState: { - initialLoad: false, - data: new Map(), - isLoading: false, - error: undefined, - }, - authorizedToReadAnyRules: false, - hasAnyAuthorizedRuleType: false, - authorizedRuleTypes: [], - authorizedToCreateAnyRules: false, - isSuccess: false, -}); - -jest.mocked(useRuleAADFields).mockReturnValue({ - aadFields: [], - loading: false, -}); - const mockUseKibana = useKibana as jest.Mock; +const unifiedSearchBarMock = jest.fn().mockImplementation((props) => ( + +)); + describe('AlertsSearchBar', () => { beforeEach(() => { + jest.clearAllMocks(); + mockUseKibana.mockReturnValue({ services: { data: mockDataPlugin, unifiedSearch: { ui: { - SearchBar: jest.fn().mockImplementation((props) => ( - - )), + SearchBar: unifiedSearchBarMock, }, }, notifications: { toasts: { addWarning: jest.fn() } } as unknown as NotificationsStart, @@ -85,10 +66,6 @@ describe('AlertsSearchBar', () => { }); }); - beforeEach(() => { - jest.clearAllMocks(); - }); - it('renders correctly', async () => { render( { onSavedQueryUpdated={jest.fn()} onClearSavedQuery={jest.fn()} appName={'test'} - featureIds={['observability', 'stackAlerts']} /> ); expect(await screen.findByTestId('querySubmitButton')).toBeInTheDocument(); @@ -119,7 +95,6 @@ describe('AlertsSearchBar', () => { onSavedQueryUpdated={jest.fn()} onClearSavedQuery={jest.fn()} appName={'test'} - featureIds={['observability', 'stackAlerts']} /> ); @@ -176,7 +151,6 @@ describe('AlertsSearchBar', () => { onSavedQueryUpdated={jest.fn()} onClearSavedQuery={jest.fn()} appName={'test'} - featureIds={['observability', 'stackAlerts']} /> ); @@ -187,4 +161,136 @@ describe('AlertsSearchBar', () => { expect(mockDataPlugin.query.filterManager.setFilters).toHaveBeenCalledWith(filters); }); }); + + it('calls the unifiedSearchBar correctly for security rule types', async () => { + render( + + ); + + await waitFor(() => { + expect(unifiedSearchBarMock).toHaveBeenCalledWith( + expect.objectContaining({ + suggestionsAbstraction: undefined, + }), + {} + ); + }); + }); + + it('calls the unifiedSearchBar correctly for NON security rule types', async () => { + render( + + ); + + await waitFor(() => { + expect(unifiedSearchBarMock).toHaveBeenCalledWith( + expect.objectContaining({ + suggestionsAbstraction: { type: 'alerts', fields: {} }, + }), + {} + ); + }); + }); + + it('calls the unifiedSearchBar with correct index patters', async () => { + render( + + ); + + await waitFor(() => { + expect(unifiedSearchBarMock).toHaveBeenCalledWith( + expect.objectContaining({ + indexPatterns: [ + { + fields: [ + { aggregatable: true, name: 'event.action', searchable: true, type: 'string' }, + ], + title: '.esQuery,apm.anomaly', + }, + ], + }), + {} + ); + }); + }); + + it('calls the unifiedSearchBar with correct index patters without rule types', async () => { + render( + + ); + + await waitFor(() => { + expect(unifiedSearchBarMock).toHaveBeenCalledWith( + expect.objectContaining({ + indexPatterns: [ + { + fields: [ + { aggregatable: true, name: 'event.action', searchable: true, type: 'string' }, + ], + title: '.alerts-*', + }, + ], + }), + {} + ); + }); + }); + + it('calls the unifiedSearchBar with correct index patters without data views', async () => { + jest.mocked(useAlertsDataView).mockReturnValue({ + isLoading: false, + dataView: undefined, + }); + + render( + + ); + + await waitFor(() => { + expect(unifiedSearchBarMock).toHaveBeenCalledWith( + expect.objectContaining({ + indexPatterns: [], + }), + {} + ); + }); + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx index 5e2880e65231..0a5c18fab9d8 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/alerts_search_bar.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo, useState } from 'react'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { compareFilters, Query, TimeRange } from '@kbn/es-query'; import { SuggestionsAbstraction } from '@kbn/unified-search-plugin/public/typeahead/suggestions_component'; -import { AlertConsumers, ValidFeatureId } from '@kbn/rule-data-utils'; +import { isSiemRuleType } from '@kbn/rule-data-utils'; import { EuiContextMenuPanelDescriptor, EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; import { useAlertsDataView } from '@kbn/alerts-ui-shared/src/common/hooks/use_alerts_data_view'; import { isQuickFiltersGroup, QuickFiltersMenuItem } from './quick_filters'; @@ -17,19 +17,15 @@ import { NO_INDEX_PATTERNS } from './constants'; import { SEARCH_BAR_PLACEHOLDER } from './translations'; import { AlertsSearchBarProps, QueryLanguageType } from './types'; import { TriggersAndActionsUiServices } from '../../..'; -import { useRuleAADFields } from '../../hooks/use_rule_aad_fields'; -import { useLoadRuleTypesQuery } from '../../hooks/use_load_rule_types_query'; const SA_ALERTS = { type: 'alerts', fields: {} } as SuggestionsAbstraction; -const EMPTY_FEATURE_IDS: ValidFeatureId[] = []; // TODO Share buildEsQuery to be used between AlertsSearchBar and AlertsStateTable component https://github.com/elastic/kibana/issues/144615 // Also TODO: Replace all references to this component with the one from alerts-ui-shared export function AlertsSearchBar({ appName, disableQueryLanguageSwitcher = false, - featureIds = EMPTY_FEATURE_IDS, - ruleTypeId, + ruleTypeIds, query, filters, quickFilters = [], @@ -58,33 +54,25 @@ export function AlertsSearchBar({ const [queryLanguage, setQueryLanguage] = useState('kuery'); const { dataView } = useAlertsDataView({ - featureIds, + ruleTypeIds: ruleTypeIds ?? [], http, dataViewsService, toasts, }); - const { aadFields, loading: fieldsLoading } = useRuleAADFields(ruleTypeId); const indexPatterns = useMemo(() => { - if (ruleTypeId && aadFields?.length) { - return [{ title: ruleTypeId, fields: aadFields }]; + if (ruleTypeIds && dataView?.fields?.length) { + return [{ title: ruleTypeIds.join(','), fields: dataView.fields }]; } + if (dataView) { return [dataView]; } - return null; - }, [aadFields, dataView, ruleTypeId]); - const ruleType = useLoadRuleTypesQuery({ - filteredRuleTypes: ruleTypeId !== undefined ? [ruleTypeId] : [], - enabled: ruleTypeId !== undefined, - }); + return null; + }, [dataView, ruleTypeIds]); - const isSecurity = - (featureIds && featureIds.length === 1 && featureIds.includes(AlertConsumers.SIEM)) || - (ruleType && - ruleTypeId && - ruleType.ruleTypesState.data.get(ruleTypeId)?.producer === AlertConsumers.SIEM); + const isSecurity = ruleTypeIds?.some(isSiemRuleType) ?? false; const onSearchQuerySubmit = useCallback( ( @@ -174,7 +162,7 @@ export function AlertsSearchBar({ appName={appName} disableQueryLanguageSwitcher={disableQueryLanguageSwitcher} // @ts-expect-error - DataView fields prop and SearchBar indexPatterns props are overly broad - indexPatterns={!indexPatterns || fieldsLoading ? NO_INDEX_PATTERNS : indexPatterns} + indexPatterns={!indexPatterns ? NO_INDEX_PATTERNS : indexPatterns} placeholder={placeholder} query={{ query: query ?? '', language: queryLanguage }} filters={filters} diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/constants.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/constants.ts index 408d4d171474..353996640005 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/constants.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/constants.ts @@ -10,5 +10,6 @@ import { AlertConsumers } from '@kbn/rule-data-utils'; export const NO_INDEX_PATTERNS: DataView[] = []; export const ALERTS_SEARCH_BAR_PARAMS_URL_STORAGE_KEY = 'searchBarParams'; -export const ALL_FEATURE_IDS = Object.values(AlertConsumers); -export const NON_SIEM_FEATURE_IDS = ALL_FEATURE_IDS.filter((fid) => fid !== AlertConsumers.SIEM); +export const NON_SIEM_CONSUMERS = Object.values(AlertConsumers).filter( + (fid) => fid !== AlertConsumers.SIEM +); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts index b1af2746d6ca..a9538bd4888b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/types.ts @@ -6,7 +6,6 @@ */ import { Filter } from '@kbn/es-query'; -import { ValidFeatureId } from '@kbn/rule-data-utils'; import { SearchBarProps } from '@kbn/unified-search-plugin/public/search_bar/search_bar'; import { QuickFiltersMenuItem } from './quick_filters'; @@ -16,7 +15,6 @@ export interface AlertsSearchBarProps extends Omit, 'query' | 'onQueryChange' | 'onQuerySubmit'> { appName: string; disableQueryLanguageSwitcher?: boolean; - featureIds: ValidFeatureId[]; rangeFrom?: string; rangeTo?: string; query?: string; @@ -27,7 +25,7 @@ export interface AlertsSearchBarProps showSubmitButton?: boolean; placeholder?: string; submitOnBlur?: boolean; - ruleTypeId?: string; + ruleTypeIds?: string[]; onQueryChange?: (query: { dateRange: { from: string; to: string; mode?: 'absolute' | 'relative' }; query?: string; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx index de89eb971573..175d9538918e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_search_bar/url_synced_alerts_search_bar.tsx @@ -5,20 +5,17 @@ * 2.0. */ -import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { BoolQuery } from '@kbn/es-query'; -import { AlertConsumers } from '@kbn/rule-data-utils'; +import React, { useCallback, useEffect, useState, useMemo } from 'react'; +import { BoolQuery, Filter } from '@kbn/es-query'; import { i18n } from '@kbn/i18n'; import { AlertFilterControls } from '@kbn/alerts-ui-shared/src/alert_filter_controls'; import { ControlGroupRenderer } from '@kbn/controls-plugin/public'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { AlertsFeatureIdsFilter } from '../../lib/search_filters'; import { useKibana } from '../../..'; import { useAlertSearchBarStateContainer } from './use_alert_search_bar_state_container'; import { ALERTS_SEARCH_BAR_PARAMS_URL_STORAGE_KEY } from './constants'; import { AlertsSearchBarProps } from './types'; import AlertsSearchBar from './alerts_search_bar'; -import { nonNullable } from '../../../../common/utils'; import { buildEsQuery } from './build_es_query'; const INVALID_QUERY_STRING_TOAST_TITLE = i18n.translate( @@ -35,16 +32,17 @@ export interface UrlSyncedAlertsSearchBarProps > { showFilterControls?: boolean; onEsQueryChange: (esQuery: { bool: BoolQuery }) => void; - onActiveFeatureFiltersChange?: (value: AlertConsumers[]) => void; + onFilterSelected?: (filters: Filter[]) => void; } /** * An abstraction over AlertsSearchBar that syncs the query state with the url */ export const UrlSyncedAlertsSearchBar = ({ + ruleTypeIds, showFilterControls = false, onEsQueryChange, - onActiveFeatureFiltersChange, + onFilterSelected, ...rest }: UrlSyncedAlertsSearchBarProps) => { const { @@ -91,13 +89,6 @@ export const UrlSyncedAlertsSearchBar = ({ useEffect(() => { try { - onActiveFeatureFiltersChange?.([ - ...new Set( - filters - .flatMap((f) => (f as AlertsFeatureIdsFilter).meta.alertsFeatureIds) - .filter(nonNullable) - ), - ]); onEsQueryChange( buildEsQuery({ timeRange: { @@ -108,6 +99,8 @@ export const UrlSyncedAlertsSearchBar = ({ filters: [...filters, ...controlFilters], }) ); + + onFilterSelected?.(filters); } catch (error) { toasts.addError(error, { title: INVALID_QUERY_STRING_TOAST_TITLE, @@ -118,8 +111,8 @@ export const UrlSyncedAlertsSearchBar = ({ controlFilters, filters, kuery, - onActiveFeatureFiltersChange, onEsQueryChange, + onFilterSelected, onKueryChange, rangeFrom, rangeTo, @@ -154,6 +147,7 @@ export const UrlSyncedAlertsSearchBar = ({ savedQuery={savedQuery} onSavedQueryUpdated={setSavedQuery} onClearSavedQuery={clearSavedQuery} + ruleTypeIds={ruleTypeIds} {...rest} /> {showFilterControls && ( diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx index 61c65eded27b..cf7e184c50f3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table.tsx @@ -309,7 +309,7 @@ const AlertsTable: React.FunctionComponent = memo((props: Aler dynamicRowHeight, query, querySnapshot, - featureIds, + ruleTypeIds, cases: { data: cases, isLoading: isLoadingCases }, maintenanceWindows: { data: maintenanceWindows, isLoading: isLoadingMaintenanceWindows }, controls, @@ -345,7 +345,7 @@ const AlertsTable: React.FunctionComponent = memo((props: Aler query, useBulkActionsConfig: alertsTableConfiguration.useBulkActions, refresh: refetchAlerts, - featureIds, + ruleTypeIds, hideBulkActions: Boolean(alertsTableConfiguration.hideBulkActions), }; }, [ @@ -355,7 +355,7 @@ const AlertsTable: React.FunctionComponent = memo((props: Aler alertsTableConfiguration.hideBulkActions, query, refetchAlerts, - featureIds, + ruleTypeIds, ]); const { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.test.tsx index 13b9433ce4b9..9db58d26d925 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.test.tsx @@ -9,12 +9,7 @@ import { BehaviorSubject } from 'rxjs'; import userEvent from '@testing-library/user-event'; import { get } from 'lodash'; import { fireEvent, render, waitFor, screen, act } from '@testing-library/react'; -import { - AlertConsumers, - ALERT_CASE_IDS, - ALERT_MAINTENANCE_WINDOW_IDS, - ALERT_UUID, -} from '@kbn/rule-data-utils'; +import { ALERT_CASE_IDS, ALERT_MAINTENANCE_WINDOW_IDS, ALERT_UUID } from '@kbn/rule-data-utils'; import { Storage } from '@kbn/kibana-utils-plugin/public'; import { @@ -344,7 +339,7 @@ const browserFields: BrowserFields = { }, }; -jest.mocked(fetchAlertsFields).mockResolvedValue({ browserFields, fields: [] }); +const fetchAlertsFieldsMock = fetchAlertsFields as jest.Mock; const queryClient = new QueryClient({ defaultOptions: { @@ -367,7 +362,7 @@ describe('AlertsTableState', () => { alertsTableConfigurationRegistry: alertsTableConfigurationRegistryMock, configurationId: PLUGIN_ID, id: PLUGIN_ID, - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['logs'], query: {}, columns, pagination: { @@ -419,6 +414,8 @@ describe('AlertsTableState', () => { data: maintenanceWindowsMap, isFetching: false, }); + + fetchAlertsFieldsMock.mockResolvedValue({ browserFields, fields: [] }); }); describe('Cases', () => { @@ -837,6 +834,8 @@ describe('AlertsTableState', () => { data: new Map(), isFetching: false, }); + + fetchAlertsFieldsMock.mockResolvedValue({ browserFields, fields: [] }); }); it('should show field browser', async () => { @@ -845,13 +844,13 @@ describe('AlertsTableState', () => { }); it('should remove an already existing element when selected', async () => { - const { getByTestId, queryByTestId } = render(); + const { findByTestId, queryByTestId } = render(); expect(queryByTestId(`dataGridHeaderCell-${AlertsField.name}`)).not.toBe(null); - fireEvent.click(getByTestId('show-field-browser')); - const fieldCheckbox = getByTestId(`field-${AlertsField.name}-checkbox`); + fireEvent.click(await findByTestId('show-field-browser')); + const fieldCheckbox = await findByTestId(`field-${AlertsField.name}-checkbox`); fireEvent.click(fieldCheckbox); - fireEvent.click(getByTestId('close')); + fireEvent.click(await findByTestId('close')); await waitFor(() => { expect(queryByTestId(`dataGridHeaderCell-${AlertsField.name}`)).toBe(null); @@ -877,13 +876,15 @@ describe('AlertsTableState', () => { set: jest.fn(), })); - const { getByTestId, queryByTestId } = render(); + const { getByTestId, findByTestId, queryByTestId } = render( + + ); expect(queryByTestId(`dataGridHeaderCell-${AlertsField.name}`)).toBe(null); - fireEvent.click(getByTestId('show-field-browser')); - const fieldCheckbox = getByTestId(`field-${AlertsField.name}-checkbox`); + fireEvent.click(await findByTestId('show-field-browser')); + const fieldCheckbox = await findByTestId(`field-${AlertsField.name}-checkbox`); fireEvent.click(fieldCheckbox); - fireEvent.click(getByTestId('close')); + fireEvent.click(await findByTestId('close')); await waitFor(() => { expect(queryByTestId(`dataGridHeaderCell-${AlertsField.name}`)).not.toBe(null); @@ -896,13 +897,13 @@ describe('AlertsTableState', () => { }); it('should insert a new field as column when its not a default one', async () => { - const { getByTestId, queryByTestId } = render(); + const { findByTestId, queryByTestId } = render(); expect(queryByTestId(`dataGridHeaderCell-${AlertsField.uuid}`)).toBe(null); - fireEvent.click(getByTestId('show-field-browser')); - const fieldCheckbox = getByTestId(`field-${AlertsField.uuid}-checkbox`); + fireEvent.click(await findByTestId('show-field-browser')); + const fieldCheckbox = await findByTestId(`field-${AlertsField.uuid}-checkbox`); fireEvent.click(fieldCheckbox); - fireEvent.click(getByTestId('close')); + fireEvent.click(await findByTestId('close')); await waitFor(() => { expect(queryByTestId(`dataGridHeaderCell-${AlertsField.uuid}`)).not.toBe(null); @@ -958,6 +959,16 @@ describe('AlertsTableState', () => { expect(result.getByTestId('alertsStateTableEmptyState')).toBeTruthy(); }); + it('should render an empty screen when the data are undefined', async () => { + mockUseSearchAlertsQuery.mockReturnValue({ + data: undefined, + refetch: refetchMock, + }); + + const result = render(); + expect(result.getByTestId('alertsStateTableEmptyState')).toBeTruthy(); + }); + describe('inspect button', () => { it('should hide the inspect button by default', () => { render(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx index 62c78a3ad589..93bb4f18dfe9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/alerts_table_state.tsx @@ -21,7 +21,6 @@ import { } from '@elastic/eui'; import type { MappingRuntimeFields } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { ALERT_CASE_IDS, ALERT_MAINTENANCE_WINDOW_IDS } from '@kbn/rule-data-utils'; -import type { ValidFeatureId } from '@kbn/rule-data-utils'; import type { RuleRegistrySearchRequestPagination } from '@kbn/rule-registry-plugin/common'; import type { BrowserFields } from '@kbn/alerting-types'; import { Storage } from '@kbn/kibana-utils-plugin/public'; @@ -68,7 +67,8 @@ export type AlertsTableStateProps = { alertsTableConfigurationRegistry: AlertsTableConfigurationRegistryContract; configurationId: string; id: string; - featureIds: ValidFeatureId[]; + ruleTypeIds: string[]; + consumers?: string[]; query: Pick; initialPageSize?: number; browserFields?: BrowserFields; @@ -192,7 +192,8 @@ const AlertsTableStateWithQueryProvider = memo( alertsTableConfigurationRegistry, configurationId, id, - featureIds, + ruleTypeIds, + consumers, query, initialPageSize = DEFAULT_ALERTS_PAGE_SIZE, leadingControlColumns = DEFAULT_LEADING_CONTROL_COLUMNS, @@ -292,7 +293,7 @@ const AlertsTableStateWithQueryProvider = memo( onColumnResize, fields, } = useColumns({ - featureIds, + ruleTypeIds, storageAlertsTable, storage, id, @@ -301,7 +302,8 @@ const AlertsTableStateWithQueryProvider = memo( }); const [queryParams, setQueryParams] = useState({ - featureIds, + ruleTypeIds, + consumers, fields, query, sort, @@ -312,14 +314,16 @@ const AlertsTableStateWithQueryProvider = memo( useEffect(() => { setQueryParams(({ pageIndex: oldPageIndex, pageSize: oldPageSize, ...prevQueryParams }) => ({ - featureIds, + ruleTypeIds, + consumers, fields, query, sort, runtimeMappings, // Go back to the first page if the query changes pageIndex: !deepEqual(prevQueryParams, { - featureIds, + ruleTypeIds, + consumers, fields, query, sort, @@ -329,7 +333,7 @@ const AlertsTableStateWithQueryProvider = memo( : oldPageIndex, pageSize: oldPageSize, })); - }, [featureIds, fields, query, runtimeMappings, sort]); + }, [ruleTypeIds, fields, query, runtimeMappings, sort, consumers]); const { data: alertsData, @@ -363,11 +367,11 @@ const AlertsTableStateWithQueryProvider = memo( } }, [alerts, isLoading, isSuccess, onLoaded]); - const mutedAlertIds = useMemo(() => { + const mutedRuleIds = useMemo(() => { return [...new Set(alerts.map((a) => a['kibana.alert.rule.uuid']![0]))]; }, [alerts]); - const { data: mutedAlerts } = useGetMutedAlerts(mutedAlertIds); + const { data: mutedAlerts } = useGetMutedAlerts(mutedRuleIds); const overriddenActions = useMemo(() => { return { toggleColumn: onToggleColumn }; }, [onToggleColumn]); @@ -501,7 +505,7 @@ const AlertsTableStateWithQueryProvider = memo( toolbarVisibility, shouldHighlightRow, dynamicRowHeight, - featureIds, + ruleTypeIds, querySnapshot, pageIndex: queryParams.pageIndex, pageSize: queryParams.pageSize, @@ -541,7 +545,7 @@ const AlertsTableStateWithQueryProvider = memo( toolbarVisibility, shouldHighlightRow, dynamicRowHeight, - featureIds, + ruleTypeIds, querySnapshot, queryParams.pageIndex, queryParams.pageSize, @@ -579,7 +583,7 @@ const AlertsTableStateWithQueryProvider = memo( return ( - {!isLoading && alertsCount === 0 && ( + {!isLoading && alertsCount <= 0 && ( { useKibanaMock().services.application.navigateToApp = navigateToApp; }); - it('calls navigateToApp with correct arguments', () => { - const { result, waitFor } = renderHook(() => useCaseViewNavigation(), { + it('calls navigateToApp with correct arguments', async () => { + const { result } = renderHook(() => useCaseViewNavigation(), { wrapper: appMockRender.AppWrapper, }); @@ -34,7 +34,7 @@ describe('useCaseViewNavigation', () => { result.current.navigateToCaseView({ caseId: 'test-id' }); }); - waitFor(() => { + await waitFor(() => { expect(navigateToApp).toHaveBeenCalledWith('testAppId', { deepLinkId: 'cases', path: '/test-id', @@ -42,8 +42,8 @@ describe('useCaseViewNavigation', () => { }); }); - it('calls navigateToApp with correct arguments and bypass current app id', () => { - const { result, waitFor } = renderHook(() => useCaseViewNavigation('superAppId'), { + it('calls navigateToApp with correct arguments and bypass current app id', async () => { + const { result } = renderHook(() => useCaseViewNavigation('superAppId'), { wrapper: appMockRender.AppWrapper, }); @@ -51,7 +51,7 @@ describe('useCaseViewNavigation', () => { result.current.navigateToCaseView({ caseId: 'test-id' }); }); - waitFor(() => { + await waitFor(() => { expect(navigateToApp).toHaveBeenCalledWith('superAppId', { deepLinkId: 'cases', path: '/test-id', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx index ad82a9d3ee97..6a25115ed7e2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/cells/render_cell_value.tsx @@ -9,7 +9,6 @@ import { isEmpty } from 'lodash'; import React from 'react'; import { ALERT_DURATION, - AlertConsumers, ALERT_RULE_NAME, ALERT_RULE_UUID, ALERT_START, @@ -25,6 +24,7 @@ import { import { EuiBadge, EuiLink, RenderCellValue } from '@elastic/eui'; import { alertProducersData, observabilityFeatureIds } from '../constants'; import { useKibana } from '../../../../common/lib/kibana'; +import { AlertsTableSupportedConsumers } from '../types'; export const getMappedNonEcsValue = ({ data, @@ -136,7 +136,7 @@ export function getAlertFormatters(fieldFormats: FieldFormatsRegistry) { ); case ALERT_RULE_CONSUMER: const producer = rowData?.find(({ field }) => field === ALERT_RULE_PRODUCER)?.value?.[0]; - const consumer: AlertConsumers = observabilityFeatureIds.includes(producer) + const consumer: AlertsTableSupportedConsumers = observabilityFeatureIds.includes(producer) ? 'observability' : producer && (value === 'alerts' || value === 'stackAlerts' || value === 'discover') ? producer diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/constants.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/constants.ts index 9605abb08523..54846574c1a1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/constants.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/constants.ts @@ -19,6 +19,7 @@ import { STACK_MONITORING_DISPLAY_NAME, UPTIME_DISPLAY_NAME, } from '../translations'; +import { AlertsTableSupportedConsumers } from './types'; interface AlertProducerData { displayName: string; @@ -33,13 +34,18 @@ export const observabilityFeatureIds: AlertConsumers[] = [ AlertConsumers.LOGS, AlertConsumers.SLO, AlertConsumers.UPTIME, + AlertConsumers.ALERTS, ]; -export const stackFeatureIds: AlertConsumers[] = [AlertConsumers.STACK_ALERTS, AlertConsumers.ML]; +export const stackFeatureIds: AlertConsumers[] = [ + AlertConsumers.STACK_ALERTS, + AlertConsumers.ML, + AlertConsumers.DISCOVER, +]; export const [_, ...observabilityApps] = observabilityFeatureIds; -export const alertProducersData: Record = { +export const alertProducersData: Record = { [AlertConsumers.OBSERVABILITY]: { displayName: OBSERVABILITY_DISPLAY_NAME, icon: 'logoObservability', @@ -86,4 +92,9 @@ export const alertProducersData: Record = { displayName: 'Example', icon: 'beaker', }, + [AlertConsumers.DISCOVER]: { + displayName: STACK_DISPLAY_NAME, + icon: 'managementApp', + subFeatureIds: stackFeatureIds, + }, }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.test.tsx index 8d65532c5f10..ae75e5472f22 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.test.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; import * as api from '../apis/get_rules_muted_alerts'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../../../../common/lib/kibana'; import { AppMockRenderer, createAppMockRenderer } from '../../../test_utils'; import { useGetMutedAlerts } from './use_get_muted_alerts'; @@ -31,16 +30,14 @@ describe('useGetMutedAlerts', () => { it('calls the api when invoked with the correct parameters', async () => { const muteAlertInstanceSpy = jest.spyOn(api, 'getMutedAlerts'); - const { waitForNextUpdate } = renderHook(() => useGetMutedAlerts(ruleIds), { + renderHook(() => useGetMutedAlerts(ruleIds), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - await waitFor(() => { expect(muteAlertInstanceSpy).toHaveBeenCalledWith( expect.anything(), - { ids: ruleIds }, + { ruleIds }, expect.any(AbortSignal) ); }); @@ -53,18 +50,16 @@ describe('useGetMutedAlerts', () => { wrapper: appMockRender.AppWrapper, }); - expect(spy).not.toHaveBeenCalled(); + await waitFor(() => expect(spy).not.toHaveBeenCalled()); }); it('shows a toast error when the api returns an error', async () => { const spy = jest.spyOn(api, 'getMutedAlerts').mockRejectedValue(new Error('An error')); - const { waitForNextUpdate } = renderHook(() => useGetMutedAlerts(ruleIds), { + renderHook(() => useGetMutedAlerts(ruleIds), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - await waitFor(() => { expect(spy).toHaveBeenCalled(); expect(addErrorMock).toHaveBeenCalled(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.tsx index 08f172451ca2..1ca6cbb22ea9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_get_muted_alerts.tsx @@ -25,7 +25,7 @@ export const useGetMutedAlerts = (ruleIds: string[], enabled = true) => { return useQuery( triggersActionsUiQueriesKeys.mutedAlerts(), ({ signal }) => - getMutedAlerts(http, { ids: ruleIds }, signal).then(({ data: rules }) => + getMutedAlerts(http, { ruleIds }, signal).then(({ data: rules }) => rules?.reduce((mutedAlerts, rule) => { mutedAlerts[rule.id] = rule.muted_alert_ids; return mutedAlerts; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_mute_alert.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_mute_alert.test.tsx index f7e8b94aa2e6..74d93a0504ca 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_mute_alert.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_mute_alert.test.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks/dom'; import * as api from '../../../../lib/rule_api/mute_alert'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../../../../common/lib/kibana'; import { AppMockRenderer, createAppMockRenderer } from '../../../test_utils'; import { useMuteAlert } from './use_mute_alert'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_unmute_alert.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_unmute_alert.test.tsx index d24a481ba30b..178dc5bb6ed9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_unmute_alert.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/alert_mute/use_unmute_alert.test.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks/dom'; import * as api from '../../../../lib/rule_api/unmute_alert'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../../../../common/lib/kibana'; import { AppMockRenderer, createAppMockRenderer } from '../../../test_utils'; import { useUnmuteAlert } from './use_unmute_alert'; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.test.ts new file mode 100644 index 000000000000..d0f1a39f7ced --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.test.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { httpServiceMock } from '@kbn/core/public/mocks'; +import { getMutedAlerts } from './get_rules_muted_alerts'; + +const http = httpServiceMock.createStartContract(); + +describe('getMutedAlerts', () => { + const apiRes = { + page: 1, + per_page: 10, + total: 0, + data: [], + }; + + beforeEach(() => { + jest.clearAllMocks(); + + http.post.mockResolvedValueOnce(apiRes); + }); + + test('should call find API with correct params', async () => { + const result = await getMutedAlerts(http, { ruleIds: ['foo'] }); + + expect(result).toEqual({ + page: 1, + per_page: 10, + total: 0, + data: [], + }); + + expect(http.post.mock.calls[0]).toMatchInlineSnapshot(` + Array [ + "/internal/alerting/rules/_find", + Object { + "body": "{\\"rule_type_ids\\":[\\"foo\\"],\\"fields\\":[\\"id\\",\\"mutedInstanceIds\\"],\\"page\\":1,\\"per_page\\":1}", + "signal": undefined, + }, + ] + `); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.ts index 5a2f2fcc21c6..d9baef548daf 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/apis/get_rules_muted_alerts.ts @@ -6,7 +6,6 @@ */ import { HttpStart } from '@kbn/core-http-browser'; -import { nodeBuilder } from '@kbn/es-query'; const INTERNAL_FIND_RULES_URL = '/internal/alerting/rules/_find'; @@ -21,18 +20,15 @@ export interface FindRulesResponse { export const getMutedAlerts = async ( http: HttpStart, - params: { ids: string[] }, + params: { ruleIds: string[] }, signal?: AbortSignal ) => { - const filterNode = nodeBuilder.or( - params.ids.map((id) => nodeBuilder.is('alert.id', `alert:${id}`)) - ); return http.post(INTERNAL_FIND_RULES_URL, { body: JSON.stringify({ - filter: JSON.stringify(filterNode), + rule_type_ids: params.ruleIds, fields: ['id', 'mutedInstanceIds'], page: 1, - per_page: params.ids.length, + per_page: params.ruleIds.length, }), signal, }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.test.tsx index d84909e746f2..554febab2021 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.test.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; +import { renderHook } from '@testing-library/react'; import { useBulkActions, useBulkAddToCaseActions, useBulkUntrackActions } from './use_bulk_actions'; import { AppMockRenderer, createAppMockRenderer } from '../../test_utils'; import { createCasesServiceMock } from '../index.mock'; @@ -392,7 +392,13 @@ describe('bulk action hooks', () => { it('appends only the case bulk actions for SIEM', async () => { const { result } = renderHook( () => - useBulkActions({ alertsCount: 0, query: {}, casesConfig, refresh, featureIds: ['siem'] }), + useBulkActions({ + alertsCount: 0, + query: {}, + casesConfig, + refresh, + ruleTypeIds: ['siem.esqlRule'], + }), { wrapper: appMockRender.AppWrapper, } @@ -476,7 +482,7 @@ describe('bulk action hooks', () => { query: {}, casesConfig, refresh, - featureIds: ['observability'], + ruleTypeIds: ['observability'], }), { wrapper: appMockRender.AppWrapper, @@ -492,7 +498,7 @@ describe('bulk action hooks', () => { query: {}, casesConfig, refresh, - featureIds: ['observability'], + ruleTypeIds: ['observability'], hideBulkActions: true, }), { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.ts index 727ff4f93ebd..1f35d02f8d72 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_actions.ts @@ -7,7 +7,7 @@ import { useCallback, useContext, useEffect, useMemo } from 'react'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { useKibana } from '@kbn/kibana-react-plugin/public'; -import { ALERT_CASE_IDS, ValidFeatureId } from '@kbn/rule-data-utils'; +import { ALERT_CASE_IDS, isSiemRuleType } from '@kbn/rule-data-utils'; import { AlertsTableContext } from '../contexts/alerts_table_context'; import { AlertsTableConfigurationRegistry, @@ -40,7 +40,7 @@ interface BulkActionsProps { casesConfig?: AlertsTableConfigurationRegistry['cases']; useBulkActionsConfig?: UseBulkActionsRegistry; refresh: () => void; - featureIds?: ValidFeatureId[]; + ruleTypeIds?: string[]; hideBulkActions?: boolean; } @@ -57,7 +57,7 @@ export interface UseBulkActions { type UseBulkAddToCaseActionsProps = Pick & Pick; -type UseBulkUntrackActionsProps = Pick & +type UseBulkUntrackActionsProps = Pick & Pick & { isAllSelected: boolean; }; @@ -191,7 +191,7 @@ export const useBulkUntrackActions = ({ refresh, clearSelection, query, - featureIds = [], + ruleTypeIds = [], isAllSelected, }: UseBulkUntrackActionsProps) => { const onSuccess = useCallback(() => { @@ -217,7 +217,7 @@ export const useBulkUntrackActions = ({ try { setIsBulkActionsLoading(true); if (isAllSelected) { - await untrackAlertsByQuery({ query, featureIds }); + await untrackAlertsByQuery({ query, ruleTypeIds }); } else { await untrackAlerts({ indices, alertUuids }); } @@ -228,7 +228,7 @@ export const useBulkUntrackActions = ({ }, [ query, - featureIds, + ruleTypeIds, isAllSelected, onSuccess, setIsBulkActionsLoading, @@ -277,7 +277,7 @@ export function useBulkActions({ query, refresh, useBulkActionsConfig = () => [], - featureIds, + ruleTypeIds, hideBulkActions, }: BulkActionsProps): UseBulkActions { const { @@ -300,13 +300,14 @@ export function useBulkActions({ refresh, clearSelection, query, - featureIds, + ruleTypeIds, isAllSelected: bulkActionsState.isAllSelected, }); const initialItems = useMemo(() => { - return [...caseBulkActions, ...(featureIds?.includes('siem') ? [] : untrackBulkActions)]; - }, [caseBulkActions, featureIds, untrackBulkActions]); + return [...caseBulkActions, ...(ruleTypeIds?.some(isSiemRuleType) ? [] : untrackBulkActions)]; + }, [caseBulkActions, ruleTypeIds, untrackBulkActions]); + const bulkActions = useMemo(() => { if (hideBulkActions) { return []; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx index b4598f56c02f..e79955715d4e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_cases.test.tsx @@ -5,9 +5,8 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; import * as api from './apis/bulk_get_cases'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { useKibana } from '../../../../common/lib/kibana'; import { useBulkGetCases } from './use_bulk_get_cases'; import { AppMockRenderer, createAppMockRenderer } from '../../test_utils'; @@ -35,18 +34,18 @@ describe('useBulkGetCases', () => { const spy = jest.spyOn(api, 'bulkGetCases'); spy.mockResolvedValue(response); - const { waitForNextUpdate } = renderHook(() => useBulkGetCases(['case-1'], true), { + renderHook(() => useBulkGetCases(['case-1'], true), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - - expect(spy).toHaveBeenCalledWith( - expect.anything(), - { - ids: ['case-1'], - }, - expect.any(AbortSignal) + await waitFor(() => + expect(spy).toHaveBeenCalledWith( + expect.anything(), + { + ids: ['case-1'], + }, + expect.any(AbortSignal) + ) ); }); @@ -58,18 +57,16 @@ describe('useBulkGetCases', () => { wrapper: appMockRender.AppWrapper, }); - expect(spy).not.toHaveBeenCalled(); + await waitFor(() => expect(spy).not.toHaveBeenCalled()); }); it('shows a toast error when the api return an error', async () => { const spy = jest.spyOn(api, 'bulkGetCases').mockRejectedValue(new Error('An error')); - const { waitForNextUpdate } = renderHook(() => useBulkGetCases(['case-1'], true), { + renderHook(() => useBulkGetCases(['case-1'], true), { wrapper: appMockRender.AppWrapper, }); - await waitForNextUpdate(); - await waitFor(() => { expect(spy).toHaveBeenCalledWith( expect.anything(), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts index b1f8a65e1603..7a2ffd32ad2c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_get_maintenance_windows.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { renderHook } from '@testing-library/react-hooks'; -import { waitFor } from '@testing-library/react'; +import { waitFor, renderHook } from '@testing-library/react'; import { MaintenanceWindowStatus } from '@kbn/alerting-plugin/common'; import * as api from './apis/bulk_get_maintenance_windows'; import { coreMock } from '@kbn/core/public/mocks'; @@ -96,7 +95,7 @@ describe('useBulkGetMaintenanceWindows', () => { const spy = jest.spyOn(api, 'bulkGetMaintenanceWindows'); spy.mockResolvedValue(response); - const { waitForNextUpdate, result } = renderHook( + const { result } = renderHook( () => useBulkGetMaintenanceWindows({ ids: ['test-id'], @@ -107,9 +106,7 @@ describe('useBulkGetMaintenanceWindows', () => { } ); - await waitForNextUpdate(); - - expect(result.current.data?.get('test-id')).toEqual(mockMaintenanceWindow); + await waitFor(() => expect(result.current.data?.get('test-id')).toEqual(mockMaintenanceWindow)); expect(spy).toHaveBeenCalledWith({ http: expect.anything(), @@ -132,7 +129,7 @@ describe('useBulkGetMaintenanceWindows', () => { } ); - expect(spy).not.toHaveBeenCalled(); + await waitFor(() => expect(spy).not.toHaveBeenCalled()); }); it('does not call the api if license is not platinum', async () => { @@ -152,7 +149,7 @@ describe('useBulkGetMaintenanceWindows', () => { } ); - expect(spy).not.toHaveBeenCalled(); + await waitFor(() => expect(spy).not.toHaveBeenCalled()); }); it('does not call the api if capabilities are not adequate', async () => { @@ -177,7 +174,7 @@ describe('useBulkGetMaintenanceWindows', () => { } ); - expect(spy).not.toHaveBeenCalled(); + await waitFor(() => expect(spy).not.toHaveBeenCalled()); }); it('shows a toast error when the api return an error', async () => { @@ -185,7 +182,7 @@ describe('useBulkGetMaintenanceWindows', () => { .spyOn(api, 'bulkGetMaintenanceWindows') .mockRejectedValue(new Error('An error')); - const { waitForNextUpdate } = renderHook( + renderHook( () => useBulkGetMaintenanceWindows({ ids: ['test-id'], @@ -196,8 +193,6 @@ describe('useBulkGetMaintenanceWindows', () => { } ); - await waitForNextUpdate(); - await waitFor(() => { expect(spy).toHaveBeenCalledWith({ http: expect.anything(), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.test.ts new file mode 100644 index 000000000000..5de16dd70ce5 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.test.ts @@ -0,0 +1,53 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { act, renderHook } from '@testing-library/react-hooks'; +import { AppMockRenderer, createAppMockRenderer } from '../../test_utils'; +import { AlertsQueryContext } from '@kbn/alerts-ui-shared/src/common/contexts/alerts_query_context'; +import { useBulkUntrackAlertsByQuery } from './use_bulk_untrack_alerts_by_query'; +import { createStartServicesMock } from '../../../../common/lib/kibana/kibana_react.mock'; +import { TriggersAndActionsUiServices } from '../../../..'; + +const mockUseKibanaReturnValue: TriggersAndActionsUiServices = createStartServicesMock(); + +jest.mock('../../../../common/lib/kibana', () => ({ + useKibana: jest.fn(() => ({ + services: mockUseKibanaReturnValue, + })), +})); + +const response = {}; + +describe('useBulkUntrackAlertsByQuery', () => { + const httpMock = mockUseKibanaReturnValue.http.post as jest.Mock; + + let appMockRender: AppMockRenderer; + + beforeEach(() => { + jest.clearAllMocks(); + appMockRender = createAppMockRenderer(AlertsQueryContext); + }); + + it('calls the api when invoked with the correct parameters', async () => { + httpMock.mockResolvedValue(response); + + const { result, waitFor } = renderHook(() => useBulkUntrackAlertsByQuery(), { + wrapper: appMockRender.AppWrapper, + }); + + await act(async () => { + // @ts-expect-error: no need to specify a query + await result.current.mutateAsync({ ruleTypeIds: ['foo'], query: [] }); + }); + + await waitFor(() => { + expect(httpMock).toHaveBeenCalledWith('/internal/alerting/alerts/_bulk_untrack_by_query', { + body: '{"query":[],"rule_type_ids":["foo"]}', + }); + }); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.tsx index 321d861e0361..88c878aa47a6 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_bulk_untrack_alerts_by_query.tsx @@ -9,7 +9,6 @@ import { i18n } from '@kbn/i18n'; import { useMutation } from '@tanstack/react-query'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { INTERNAL_BASE_ALERTING_API_PATH } from '@kbn/alerting-plugin/common'; -import { ValidFeatureId } from '@kbn/rule-data-utils'; import { AlertsQueryContext } from '@kbn/alerts-ui-shared/src/common/contexts/alerts_query_context'; import { useKibana } from '../../../../common'; @@ -22,14 +21,14 @@ export const useBulkUntrackAlertsByQuery = () => { const untrackAlertsByQuery = useMutation< string, string, - { query: Pick; featureIds: ValidFeatureId[] } + { query: Pick; ruleTypeIds: string[] } >( ['untrackAlerts'], - ({ query, featureIds }) => { + ({ query, ruleTypeIds }) => { try { const body = JSON.stringify({ query: Array.isArray(query) ? query : [query], - feature_ids: featureIds, + rule_type_ids: ruleTypeIds, }); return http.post(`${INTERNAL_BASE_ALERTING_API_PATH}/alerts/_bulk_untrack_by_query`, { body, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx index fb79f87162bc..3b742bbd6d62 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.test.tsx @@ -7,14 +7,13 @@ import React, { FunctionComponent } from 'react'; import { EuiDataGridColumn } from '@elastic/eui'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { Storage } from '@kbn/kibana-utils-plugin/public'; -import { act, renderHook } from '@testing-library/react-hooks'; +import { act, waitFor, renderHook } from '@testing-library/react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { BrowserFields } from '@kbn/alerting-types'; import { testQueryClientConfig } from '@kbn/alerts-ui-shared/src/common/test_utils/test_query_client_config'; import { fetchAlertsFields } from '@kbn/alerts-ui-shared/src/common/apis/fetch_alerts_fields'; -import { useColumns, UseColumnsArgs, UseColumnsResp } from './use_columns'; +import { useColumns } from './use_columns'; import { AlertsTableStorage } from '../../alerts_table_state'; import { createStartServicesMock } from '../../../../../common/lib/kibana/kibana_react.mock'; import { AlertsQueryContext } from '@kbn/alerts-ui-shared/src/common/contexts/alerts_query_context'; @@ -76,7 +75,7 @@ mockFetchAlertsFields.mockResolvedValue({ browserFields, fields: [] }); describe('useColumns', () => { const id = 'useColumnTest'; - const featureIds: AlertConsumers[] = [AlertConsumers.LOGS, AlertConsumers.APM]; + const ruleTypeIds: string[] = ['apm', 'logs']; let storage = { current: new Storage(mockStorage) }; const getStorageAlertsTableByDefaultColumns = (defaultColumns: EuiDataGridColumn[]) => { @@ -151,14 +150,11 @@ describe('useColumns', () => { test('onColumnResize', async () => { const localDefaultColumns = [...defaultColumns]; const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(localDefaultColumns); - const { result, rerender } = renderHook< - React.PropsWithChildren, - UseColumnsResp - >( + const { result, rerender } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -186,11 +182,11 @@ describe('useColumns', () => { test('check if initial width for the last column does not exist', async () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -211,12 +207,12 @@ describe('useColumns', () => { const alertsFields = { testField: { name: 'testField', type: 'string', searchable: true, aggregatable: true }, }; - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ alertsFields, defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -231,11 +227,11 @@ describe('useColumns', () => { describe('visibleColumns', () => { test('hide all columns with onChangeVisibleColumns', async () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -253,11 +249,11 @@ describe('useColumns', () => { test('show all columns with onChangeVisibleColumns', async () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -282,11 +278,11 @@ describe('useColumns', () => { test('should populate visibleColumns correctly', async () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -300,14 +296,11 @@ describe('useColumns', () => { test('should change visibleColumns if provided defaultColumns change', async () => { let localDefaultColumns = [...defaultColumns]; let localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(localDefaultColumns); - const { result, rerender } = renderHook< - React.PropsWithChildren, - UseColumnsResp - >( + const { result, rerender } = renderHook( () => useColumns({ defaultColumns: localDefaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -340,14 +333,11 @@ describe('useColumns', () => { describe('columns', () => { test('should changes the column list when defaultColumns has been updated', async () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result, waitFor } = renderHook< - React.PropsWithChildren, - UseColumnsResp - >( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -362,11 +352,11 @@ describe('useColumns', () => { describe('onToggleColumns', () => { test('should update the list of columns when on Toggle Columns is called', () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -383,11 +373,11 @@ describe('useColumns', () => { test('should update the list of visible columns when onToggleColumn is called', async () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -412,11 +402,11 @@ describe('useColumns', () => { test('should update the column details in the storage when onToggleColumn is called', () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, @@ -445,11 +435,11 @@ describe('useColumns', () => { describe('onResetColumns', () => { test('should restore visible columns defaults', () => { const localStorageAlertsTable = getStorageAlertsTableByDefaultColumns(defaultColumns); - const { result } = renderHook, UseColumnsResp>( + const { result } = renderHook( () => useColumns({ defaultColumns, - featureIds, + ruleTypeIds, id, storageAlertsTable: localStorageAlertsTable, storage, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts index 30c9ff0ea69e..3af1d37f10de 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_columns/use_columns.ts @@ -9,7 +9,6 @@ import { EuiDataGridColumn, EuiDataGridOnColumnResizeData } from '@elastic/eui'; import { IStorageWrapper } from '@kbn/kibana-utils-plugin/public'; import { BrowserField, BrowserFields } from '@kbn/alerting-types'; import { MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import { isEmpty } from 'lodash'; import { useFetchAlertsFieldsQuery } from '@kbn/alerts-ui-shared/src/common/hooks/use_fetch_alerts_fields_query'; import { AlertsQueryContext } from '@kbn/alerts-ui-shared/src/common/contexts/alerts_query_context'; @@ -18,7 +17,7 @@ import { toggleColumn } from './toggle_column'; import { useKibana } from '../../../../../common'; export interface UseColumnsArgs { - featureIds: AlertConsumers[]; + ruleTypeIds: string[]; storageAlertsTable: React.MutableRefObject; storage: React.MutableRefObject; id: string; @@ -155,7 +154,7 @@ const persist = ({ }; export const useColumns = ({ - featureIds, + ruleTypeIds, storageAlertsTable, storage, id, @@ -167,7 +166,7 @@ export const useColumns = ({ const fieldsQuery = useFetchAlertsFieldsQuery( { http, - featureIds, + ruleTypeIds, }, { enabled: !alertsFields, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_pagination.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_pagination.test.ts index 24bddbe90ec5..b53855f991c5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_pagination.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_pagination.test.ts @@ -5,7 +5,8 @@ * 2.0. */ import { usePagination } from './use_pagination'; -import { renderHook, act } from '@testing-library/react-hooks'; + +import { renderHook, act } from '@testing-library/react'; describe('usePagination', () => { const onPageChange = jest.fn(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_sorting.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_sorting.test.ts index 092ec0ed0eb4..95efe7c9c8c5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_sorting.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/hooks/use_sorting.test.ts @@ -5,7 +5,8 @@ * 2.0. */ import { useSorting } from './use_sorting'; -import { renderHook, act } from '@testing-library/react-hooks'; + +import { renderHook, act } from '@testing-library/react'; describe('useSorting', () => { const onSortChange = jest.fn(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/types.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/types.ts index 819cc42bd90e..46b349ae9bcc 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/alerts_table/types.ts @@ -20,6 +20,8 @@ export interface Consumer { name: string; } +export type AlertsTableSupportedConsumers = Exclude; + export type ServerError = IHttpFetchError; export interface CellComponentProps { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx index 23e6f978f4c0..d64c018a07f3 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.test.tsx @@ -602,6 +602,7 @@ function mockRuleType(overloads: Partial = {}): RuleType { producer: 'rules', minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx index 34f5a8e65436..593e0a989b5f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule.tsx @@ -8,8 +8,8 @@ import React, { lazy, useCallback, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiTabbedContent } from '@elastic/eui'; -import { AlertStatusValues, ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; -import { ALERT_RULE_UUID, AlertConsumers } from '@kbn/rule-data-utils'; +import { AlertStatusValues } from '@kbn/alerting-plugin/common'; +import { ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import { ALERT_TABLE_GENERIC_CONFIG_ID } from '../../../constants'; import { AlertTableConfigRegistry } from '../../../alert_table_config_registry'; import { useKibana } from '../../../../common/lib/kibana'; @@ -106,11 +106,7 @@ export function RuleComponent({ alertsTableConfigurationRegistry={ alertsTableConfigurationRegistry as AlertTableConfigRegistry } - featureIds={ - (rule.consumer === ALERTING_FEATURE_ID - ? [ruleType.producer] - : [rule.consumer]) as AlertConsumers[] - } + ruleTypeIds={[ruleType.id]} query={{ bool: { filter: { term: { [ALERT_RULE_UUID]: rule.id } } } }} showAlertStatusWithFlapping lastReloadRequestTime={lastReloadRequestTime} @@ -131,11 +127,10 @@ export function RuleComponent({ lastReloadRequestTime, onMuteAction, readOnly, - rule.consumer, rule.id, ruleType.hasAlertsMappings, ruleType.hasFieldsForAAD, - ruleType.producer, + ruleType.id, ]); const tabs = [ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx index ffde17111738..23c19642a870 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_details.test.tsx @@ -88,6 +88,7 @@ const ruleType: RuleType = { producer: ALERTING_FEATURE_ID, authorizedConsumers, enabledInLicense: true, + category: 'my-category', }; describe('rule_details', () => { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx index 7e660a30f7ec..b8357c68da20 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_route.test.tsx @@ -146,6 +146,7 @@ function mockRuleType(overloads: Partial = {}): RuleType { producer: 'rules', minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts index 01ea94fdea8d..3da317d4e2be 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/test_helpers.ts @@ -79,6 +79,7 @@ export function mockRuleType(overloads: Partial = {}): RuleType { producer: 'rules', minimumLicenseRequired: 'basic', enabledInLicense: true, + category: 'my-category', ...overloads, }; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx index c7b2876d83d8..0b9109c18831 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_add.test.tsx @@ -450,6 +450,7 @@ describe('rule_add', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx index 17bdcc92997c..a89f7fe76339 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form.test.tsx @@ -329,6 +329,7 @@ describe('rule_form', () => { state: [], }, enabledInLicense: true, + category: 'my-category', }, { id: 'disabled-by-license', @@ -352,6 +353,7 @@ describe('rule_form', () => { state: [], }, enabledInLicense: false, + category: 'my-category', }, ]; useLoadRuleTypesQuery.mockReturnValue({ @@ -579,6 +581,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, @@ -652,6 +655,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, @@ -730,6 +734,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, @@ -789,6 +794,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, @@ -848,6 +854,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, @@ -907,6 +914,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, @@ -966,6 +974,7 @@ describe('rule_form', () => { }, ], enabledInLicense: true, + category: 'my-category', defaultActionGroupId: 'threshold.fired', minimumLicenseRequired: 'basic', recoveryActionGroup: { id: 'recovered', name: 'Recovered' }, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.test.tsx index bec46c682919..c98733d377f0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.test.tsx @@ -9,14 +9,19 @@ import React from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import { RuleFormConsumerSelection } from './rule_form_consumer_selection'; import { RuleCreationValidConsumer } from '../../../types'; +import { useKibana } from '../../../common/lib/kibana'; const mockConsumers: RuleCreationValidConsumer[] = ['logs', 'infrastructure', 'stackAlerts']; const mockOnChange = jest.fn(); +jest.mock('../../../common/lib/kibana'); +const useKibanaMock = useKibana as jest.Mocked; + describe('RuleFormConsumerSelectionModal', () => { beforeEach(() => { jest.clearAllMocks(); + useKibanaMock().services.isServerless = false; }); it('renders correctly', async () => { @@ -162,41 +167,56 @@ describe('RuleFormConsumerSelectionModal', () => { expect(screen.queryByTestId('ruleFormConsumerSelect')).not.toBeInTheDocument(); }); - it('should display nothing if observability is one of the consumers', () => { + it('should display the initial selected consumer', () => { render( ); - expect(screen.queryByTestId('ruleFormConsumerSelect')).not.toBeInTheDocument(); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue('Logs'); }); - it('should display the initial selected consumer', () => { + it('should not display the initial selected consumer if it is not a selectable option', () => { render( ); + expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue(''); + }); - expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue('Logs'); + it('should not show the role visibility dropdown on serverless on an o11y project', () => { + useKibanaMock().services.isServerless = true; + + render( + + ); + expect(screen.queryByTestId('ruleFormConsumerSelect')).not.toBeInTheDocument(); }); - it('should not display the initial selected consumer if it is not a selectable option', () => { + it('should set the consumer correctly on an o11y project', () => { + useKibanaMock().services.isServerless = true; + render( ); - expect(screen.getByTestId('comboBoxSearchInput')).toHaveValue(''); + expect(mockOnChange).toHaveBeenLastCalledWith('observability'); }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx index 46ec61cca8a5..9fff99c1c999 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_form/rule_form_consumer_selection.tsx @@ -10,6 +10,7 @@ import { EuiComboBox, EuiFormRow, EuiComboBoxOptionOption } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { AlertConsumers, STACK_ALERTS_FEATURE_ID } from '@kbn/rule-data-utils'; import { IErrorObject, RuleCreationValidConsumer } from '../../../types'; +import { useKibana } from '../../../common/lib/kibana'; const SELECT_LABEL: string = i18n.translate( 'xpack.triggersActionsUI.sections.ruleFormConsumerSelectionModal.selectLabel', @@ -80,8 +81,11 @@ export interface RuleFormConsumerSelectionProps { const SINGLE_SELECTION = { asPlainText: true }; export const RuleFormConsumerSelection = (props: RuleFormConsumerSelectionProps) => { + const { isServerless } = useKibana().services; + const { consumers, errors, onChange, selectedConsumer, initialSelectedConsumer } = props; const isInvalid = (errors?.consumer as string[])?.length > 0; + const handleOnChange = useCallback( (selected: Array>) => { if (selected.length > 0) { @@ -93,6 +97,7 @@ export const RuleFormConsumerSelection = (props: RuleFormConsumerSelectionProps) }, [onChange] ); + const validatedSelectedConsumer = useMemo(() => { if ( selectedConsumer && @@ -103,6 +108,7 @@ export const RuleFormConsumerSelection = (props: RuleFormConsumerSelectionProps) } return null; }, [selectedConsumer, consumers]); + const selectedOptions = useMemo( () => validatedSelectedConsumer @@ -149,15 +155,16 @@ export const RuleFormConsumerSelection = (props: RuleFormConsumerSelectionProps) useEffect(() => { if (consumers.length === 1) { onChange(consumers[0] as RuleCreationValidConsumer); - } else if (consumers.includes(AlertConsumers.OBSERVABILITY)) { + } else if (isServerless && consumers.includes(AlertConsumers.OBSERVABILITY)) { onChange(AlertConsumers.OBSERVABILITY as RuleCreationValidConsumer); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [consumers]); - if (consumers.length <= 1 || consumers.includes(AlertConsumers.OBSERVABILITY)) { + if (consumers.length <= 1 || (isServerless && consumers.includes(AlertConsumers.OBSERVABILITY))) { return null; } + return ( { }); }); -// Failing: See https://github.com/elastic/kibana/issues/182435 -describe.skip('rules_list component empty', () => { +describe('rules_list component empty', () => { beforeEach(() => { fetchActiveMaintenanceWindowsMock.mockResolvedValue([]); loadRulesWithKueryFilter.mockResolvedValue({ @@ -282,28 +281,6 @@ describe.skip('rules_list component empty', () => { expect(await screen.findByTestId('createFirstRuleEmptyPrompt')).toBeInTheDocument(); }); - it('renders MaintenanceWindowCallout if one exists', async () => { - fetchActiveMaintenanceWindowsMock.mockResolvedValue([RUNNING_MAINTENANCE_WINDOW_1]); - renderWithProviders(); - expect( - await screen.findByText( - 'Rule notifications are stopped while maintenance windows are running.' - ) - ).toBeInTheDocument(); - expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1); - }); - - it("hides MaintenanceWindowCallout if filterConsumers does not match the running maintenance window's category", async () => { - fetchActiveMaintenanceWindowsMock.mockResolvedValue([ - { ...RUNNING_MAINTENANCE_WINDOW_1, categoryIds: ['securitySolution'] }, - ]); - renderWithProviders(); - await expect( - screen.findByText('Rule notifications are stopped while maintenance windows are running.') - ).rejects.toThrow(); - expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1); - }); - it('renders Create rule button', async () => { renderWithProviders(); @@ -319,6 +296,7 @@ describe.skip('rules_list component empty', () => { describe('rules_list ', () => { let ruleTypeRegistry: jest.Mocked; let actionTypeRegistry: jest.Mocked>; + beforeEach(() => { (getIsExperimentalFeatureEnabled as jest.Mock).mockImplementation(() => false); loadRulesWithKueryFilter.mockResolvedValue({ @@ -1403,3 +1381,99 @@ describe('rules_list with show only capability', () => { }); }); }); + +describe('MaintenanceWindowsMock', () => { + beforeEach(() => { + fetchActiveMaintenanceWindowsMock.mockResolvedValue([]); + + loadRulesWithKueryFilter.mockResolvedValue({ + page: 1, + perPage: 10000, + total: 0, + data: [], + }); + + loadActionTypes.mockResolvedValue([ + { + id: 'test', + name: 'Test', + }, + { + id: 'test2', + name: 'Test2', + }, + ]); + + loadRuleTypes.mockResolvedValue([ruleTypeFromApi]); + loadAllActions.mockResolvedValue([]); + loadRuleAggregationsWithKueryFilter.mockResolvedValue({}); + loadRuleTags.mockResolvedValue({ + data: ruleTags, + page: 1, + perPage: 50, + total: 4, + }); + + const actionTypeRegistry = actionTypeRegistryMock.create(); + const ruleTypeRegistry = ruleTypeRegistryMock.create(); + + ruleTypeRegistry.list.mockReturnValue([ruleType]); + actionTypeRegistry.list.mockReturnValue([]); + useKibanaMock().services.application.capabilities = { + ...useKibanaMock().services.application.capabilities, + [MAINTENANCE_WINDOW_FEATURE_ID]: { + save: true, + show: true, + }, + }; + useKibanaMock().services.ruleTypeRegistry = ruleTypeRegistry; + useKibanaMock().services.actionTypeRegistry = actionTypeRegistry; + }); + + afterEach(() => { + jest.clearAllMocks(); + queryClient.clear(); + cleanup(); + }); + + it('renders MaintenanceWindowCallout if one exists', async () => { + fetchActiveMaintenanceWindowsMock.mockResolvedValue([RUNNING_MAINTENANCE_WINDOW_1]); + renderWithProviders(); + + expect( + await screen.findByText('One or more maintenance windows are running') + ).toBeInTheDocument(); + + expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1); + }); + + it('hides MaintenanceWindowCallout if the category ID is not supported', async () => { + loadRuleTypes.mockResolvedValue([{ ...ruleTypeFromApi, category: 'observability' }]); + fetchActiveMaintenanceWindowsMock.mockResolvedValue([ + { ...RUNNING_MAINTENANCE_WINDOW_1, categoryIds: ['securitySolution'] }, + ]); + + renderWithProviders(); + + await expect( + screen.findByText('Rule notifications are stopped while maintenance windows are running.') + ).rejects.toThrow(); + + expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1); + }); + + it('shows MaintenanceWindowCallout for a specific category', async () => { + loadRuleTypes.mockResolvedValue([{ ...ruleTypeFromApi, category: 'observability' }]); + fetchActiveMaintenanceWindowsMock.mockResolvedValue([ + { ...RUNNING_MAINTENANCE_WINDOW_1, categoryIds: ['securitySolution', 'observability'] }, + ]); + + renderWithProviders(); + + expect( + await screen.findByText('A maintenance window is running for Observability rules') + ).toBeInTheDocument(); + + expect(fetchActiveMaintenanceWindowsMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx index d98aa2c5dec6..c0b56fa22451 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list.tsx @@ -117,7 +117,8 @@ const RuleAdd = lazy(() => import('../../rule_form/rule_add')); const RuleEdit = lazy(() => import('../../rule_form/rule_edit')); export interface RulesListProps { - filterConsumers?: string[]; + ruleTypeIds?: string[]; + consumers?: string[]; filteredRuleTypes?: string[]; lastResponseFilter?: string[]; lastRunOutcomeFilter?: string[]; @@ -159,7 +160,8 @@ const initialPercentileOptions = Object.values(Percentiles).map((percentile) => const EMPTY_ARRAY: string[] = []; export const RulesList = ({ - filterConsumers, + ruleTypeIds, + consumers, filteredRuleTypes = EMPTY_ARRAY, lastResponseFilter, lastRunOutcomeFilter, @@ -272,6 +274,7 @@ export const RulesList = ({ const rulesTypesFilter = isEmpty(filters.types) ? authorizedRuleTypes.map((art) => art.id) : filters.types; + const hasDefaultRuleTypesFiltersOn = isEmpty(filters.types); const computedFilter = useMemo(() => { @@ -285,7 +288,8 @@ export const RulesList = ({ // Fetch rules const { rulesState, loadRules, hasData, lastUpdate } = useLoadRulesQuery({ - filterConsumers, + ruleTypeIds, + consumers, filters: computedFilter, hasDefaultRuleTypesFiltersOn, page, @@ -298,7 +302,8 @@ export const RulesList = ({ // Fetch status aggregation const { loadRuleAggregations, rulesStatusesTotal, rulesLastRunOutcomesTotal } = useLoadRuleAggregationsQuery({ - filterConsumers, + ruleTypeIds, + consumers, filters: computedFilter, enabled: canLoadRules, refresh, @@ -766,12 +771,16 @@ export const RulesList = ({ const numberRulesToDelete = rulesToBulkEdit.length || numberOfSelectedItems; + const allRuleCategories = getAllUniqueRuleTypeCategories( + Array.from(ruleTypesState.data.values()) + ); + return ( <> {showSearchBar && !isEmpty(filters.ruleParams) ? ( ) : null} - + ids.includes(rule.id)); } + +const getAllUniqueRuleTypeCategories = (ruleTypes: RuleType[]) => { + const categories = new Set(ruleTypes.map((ruleType) => ruleType.category)); + + return Array.from(categories).filter(Boolean); +}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_column_selector.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_column_selector.test.tsx index ad623631fe85..c3afafd71605 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_column_selector.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_column_selector.test.tsx @@ -5,8 +5,7 @@ * 2.0. */ -import { render } from '@testing-library/react'; -import { renderHook } from '@testing-library/react-hooks'; +import { render, renderHook } from '@testing-library/react'; import React from 'react'; import { RulesListColumns, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_table.tsx index 88f22f9687ea..b325e7fd70a4 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rules_list/components/rules_list_table.tsx @@ -720,7 +720,7 @@ export const RulesListTable = (props: RulesListTableProps) => { ), sortable: true, truncateText: false, - width: '10%', + width: '100px', 'data-test-subj': 'rulesTableCell-status', render: (_enabled: boolean | undefined, rule: RuleTableItem) => { return renderRuleStatusDropdown(rule); diff --git a/x-pack/plugins/triggers_actions_ui/public/types.ts b/x-pack/plugins/triggers_actions_ui/public/types.ts index a592b19ae8a7..d6ea582058c1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/types.ts +++ b/x-pack/plugins/triggers_actions_ui/public/types.ts @@ -26,7 +26,7 @@ import type { RenderCellValue, EuiDataGridCellPopoverElementProps, } from '@elastic/eui'; -import type { RuleCreationValidConsumer, ValidFeatureId } from '@kbn/rule-data-utils'; +import type { RuleCreationValidConsumer } from '@kbn/rule-data-utils'; import { EuiDataGridColumn, EuiDataGridControlColumn, EuiDataGridSorting } from '@elastic/eui'; import { HttpSetup } from '@kbn/core/public'; import { KueryNode } from '@kbn/es-query'; @@ -490,7 +490,7 @@ export type AlertsTableProps = { * Enable when rows may have variable heights (disables virtualization) */ dynamicRowHeight?: boolean; - featureIds?: ValidFeatureId[]; + ruleTypeIds?: string[]; pageIndex: number; pageSize: number; sort: SortCombinations[]; diff --git a/x-pack/plugins/triggers_actions_ui/server/plugin.ts b/x-pack/plugins/triggers_actions_ui/server/plugin.ts index b5cafb057148..2263af73dbdc 100644 --- a/x-pack/plugins/triggers_actions_ui/server/plugin.ts +++ b/x-pack/plugins/triggers_actions_ui/server/plugin.ts @@ -6,10 +6,7 @@ */ import { Logger, Plugin, CoreSetup, PluginInitializerContext } from '@kbn/core/server'; -import { - PluginSetupContract as AlertingPluginSetup, - PluginStartContract as AlertingPluginStart, -} from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server'; import { EncryptedSavedObjectsPluginSetup } from '@kbn/encrypted-saved-objects-plugin/server'; import { getService, register as registerDataService } from './data'; import { createHealthRoute, createConfigRoute } from './routes'; @@ -21,11 +18,11 @@ export interface PluginStartContract { interface PluginsSetup { encryptedSavedObjects?: EncryptedSavedObjectsPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; } interface TriggersActionsPluginStart { - alerting: AlertingPluginStart; + alerting: AlertingServerStart; } export class TriggersActionsPlugin implements Plugin { diff --git a/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts b/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts index 010a01b46fbd..e96d5837b113 100644 --- a/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts +++ b/x-pack/plugins/triggers_actions_ui/server/routes/config.test.ts @@ -45,7 +45,7 @@ describe('createConfigRoute', () => { const logger = loggingSystemMock.create().get(); const mockRulesClient = rulesClientMock.create(); - mockRulesClient.listRuleTypes.mockResolvedValueOnce(new Set(ruleTypes)); + mockRulesClient.listRuleTypes.mockResolvedValueOnce(ruleTypes); createConfigRoute({ logger, router, @@ -80,7 +80,7 @@ describe('createConfigRoute', () => { const logger = loggingSystemMock.create().get(); const mockRulesClient = rulesClientMock.create(); - mockRulesClient.listRuleTypes.mockResolvedValueOnce(new Set()); + mockRulesClient.listRuleTypes.mockResolvedValueOnce([]); createConfigRoute({ logger, router, diff --git a/x-pack/plugins/upgrade_assistant/README.md b/x-pack/plugins/upgrade_assistant/README.md index 145f49baf032..39bebc15e44b 100644 --- a/x-pack/plugins/upgrade_assistant/README.md +++ b/x-pack/plugins/upgrade_assistant/README.md @@ -15,6 +15,7 @@ Some features of the UA are only needed when upgrading to a new major version. T * ML Snapshots (`featureSet.mlSnapshots`): Machine learning Upgrade mode can be toggled from outside Kibana, the purpose of this feature guard is to hide all ML related deprecations from the end user until the next major upgrade. When we want to enable ML model snapshot deprecation warnings again we need to change the constant `MachineLearningField.MIN_CHECKED_SUPPORTED_SNAPSHOT_VERSION` to something higher than 7.0.0 in the Elasticsearch code. * Migrating system indices (`featureSet.migrateSystemIndices`): Migrating system indices should only be enabled for major version upgrades. This config hides the second step from the UA UI for migrating system indices. +* Reindex Data Streams (`featureSet.migrateDataStreams`): Migrating deprecated Data streams should only be enabled for major version upgrades. The purpose of this feature guard is to hide all data streams related deprecations from the end user until the next major upgrade. * Reindex corrective actions (`featureSet.reindexCorrectiveActions`): Deprecations with reindexing corrective actions are only enabled for major version upgrades. Currently, the reindex actions include some logic that is specific to the [8.0 upgrade](https://github.com/elastic/kibana/blob/main/x-pack/plugins/upgrade_assistant/server/lib/reindexing/index_settings.ts). End users could get into a bad situation if this is enabled before this logic is fixed. ## Deprecations @@ -28,7 +29,7 @@ These surface runtime deprecations, e.g. a Painless script that uses a deprecate request to a deprecated API. These are also generally surfaced as deprecation headers within the response. Even if the cluster state is good, app maintainers need to watch the logs in case deprecations are discovered as data is migrated. Starting in 7.x, deprecation logs can be written to a file or a data stream ([#58924](https://github.com/elastic/elasticsearch/pull/58924)). When the data stream exists, the Upgrade Assistant provides a way to analyze the logs through Observability or Discover ([#106521](https://github.com/elastic/kibana/pull/106521)). -* [**Kibana deprecations API.**](https://github.com/elastic/kibana/blob/main/src/core/server/deprecations/README.mdx) This is information about deprecated features and configs in Kibana. These deprecations are only communicated to the user if the deployment is using these features. Kibana engineers are responsible for adding deprecations to the deprecations API for their respective team. +* [**Kibana deprecations API.**](https://github.com/elastic/kibana/blob/main/src/core/server/docs/kib_core_deprecations_service.mdx) This is information about deprecated features and configs in Kibana. These deprecations are only communicated to the user if the deployment is using these features. Kibana engineers are responsible for adding deprecations to the deprecations API for their respective team. ### Fixing problems diff --git a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts index 31fd69648418..010790e3c5e1 100644 --- a/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts +++ b/x-pack/plugins/upgrade_assistant/__jest__/client_integration/helpers/app_context.mock.ts @@ -80,6 +80,7 @@ export const getAppContextMock = (kibanaVersion: SemVer) => ({ featureSet: { mlSnapshots: true, migrateSystemIndices: true, + migrateDataStreams: true, reindexCorrectiveActions: true, }, kibanaVersionInfo: { diff --git a/x-pack/plugins/upgrade_assistant/common/types.ts b/x-pack/plugins/upgrade_assistant/common/types.ts index 6d7166569d8d..781e4865ee56 100644 --- a/x-pack/plugins/upgrade_assistant/common/types.ts +++ b/x-pack/plugins/upgrade_assistant/common/types.ts @@ -215,7 +215,7 @@ export interface HealthIndicatorAction { export interface EnrichedDeprecationInfo extends Omit { - type: keyof estypes.MigrationDeprecationsResponse | 'health_indicator'; + type: keyof estypes.MigrationDeprecationsResponse | 'health_indicator' | 'data_streams'; isCritical: boolean; status?: estypes.HealthReportIndicatorHealthStatus; index?: string; @@ -296,4 +296,5 @@ export interface FeatureSet { migrateSystemIndices: boolean; mlSnapshots: boolean; reindexCorrectiveActions: boolean; + migrateDataStreams: boolean; } diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx index 12babe0b9b46..d0743230f909 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/constants.tsx @@ -6,8 +6,9 @@ */ import { i18n } from '@kbn/i18n'; +import { EnrichedDeprecationInfo } from '../../../common/types'; -export const DEPRECATION_TYPE_MAP = { +export const DEPRECATION_TYPE_MAP: Record = { cluster_settings: i18n.translate( 'xpack.upgradeAssistant.esDeprecations.clusterDeprecationTypeLabel', { @@ -32,6 +33,9 @@ export const DEPRECATION_TYPE_MAP = { defaultMessage: 'Health Indicator', } ), + data_streams: i18n.translate('xpack.upgradeAssistant.esDeprecations.dataStreamsTypeLabel', { + defaultMessage: 'Data Stream', + }), }; export const PAGINATION_CONFIG = { diff --git a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx index cc28b2e152e2..b9579005ffe3 100644 --- a/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx +++ b/x-pack/plugins/upgrade_assistant/public/application/components/overview/overview.tsx @@ -9,13 +9,13 @@ import React, { useEffect, useState } from 'react'; import { EuiSteps, - EuiText, EuiPageHeader, EuiButtonEmpty, EuiSpacer, EuiLink, EuiPageBody, EuiPageSection, + EuiText, } from '@elastic/eui'; import type { EuiStepProps } from '@elastic/eui/src/components/steps/step'; @@ -94,18 +94,24 @@ export const Overview = withRouter(({ history }: RouteComponentProps) => { > + + + ), + }} /> - - - - - { + return { + cluster_settings: [], + node_settings: [], + ml_settings: [], + index_settings: {}, + data_streams: {}, + }; +}; + +export const getMockMlSettingsDeprecations = () => { + return { + ml_settings: [ + { + level: 'warning', + message: 'Datafeed [deprecation-datafeed] uses deprecated query options', + url: 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#breaking_70_search_changes', + details: + '[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]', + // @ts-ignore + resolve_during_rolling_upgrade: false, + }, + { + level: 'critical', + message: + 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', + url: '', + details: 'details', + // @ts-ignore + _meta: { snapshot_id: '1', job_id: 'deprecation_check_job' }, + // @ts-ignore + resolve_during_rolling_upgrade: false, + }, + ], + }; +}; + +export const getMockDataStreamDeprecations = () => { + return { + data_streams: { + 'my-v7-data-stream': [ + { + level: 'critical', + message: 'Old data stream with a compatibility version < 8.0', + url: 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-9.0.html', + details: + 'This data stream has backing indices that were created before Elasticsearch 8.0.0', + resolve_during_rolling_upgrade: false, + _meta: { + backing_indices: { + count: 52, + need_upgrading: { + count: 37, + searchable_snapshot: { + count: 23, + fully_mounted: { + count: 7, + }, + partially_mounted: { + count: 16, + }, + }, + }, + }, + }, + }, + ], + }, + }; +}; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json b/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json index a83d8d231d14..f53e4176096c 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json +++ b/x-pack/plugins/upgrade_assistant/server/lib/__fixtures__/fake_deprecations.json @@ -148,5 +148,31 @@ "resolve_during_rolling_upgrade": false } ] + }, + "data_streams": { + "my-v7-data-stream" : [{ + "level" : "critical", + "message" : "Old data stream with a compatibility version < 8.0", + "url" : "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-9.0.html", + "details" : "This data stream has backing indices that were created before Elasticsearch 8.0.0", + "resolve_during_rolling_upgrade" : false, + "_meta": { + "backing_indices": { + "count": 52, + "need_upgrading": { + "count": 37, + "searchable_snapshot": { + "count": 23, + "fully_mounted": { + "count": 7 + }, + "partially_mounted": { + "count": 16 + } + } + } + } + } + }] } } diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts deleted file mode 100644 index 05fc4f666f7b..000000000000 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.ts +++ /dev/null @@ -1,340 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { IScopedClusterClient } from '@kbn/core/server'; -import { i18n } from '@kbn/i18n'; -import { EnrichedDeprecationInfo, ESUpgradeStatus, FeatureSet } from '../../common/types'; -import { esIndicesStateCheck } from './es_indices_state_check'; -import { - getESSystemIndicesMigrationStatus, - convertFeaturesToIndicesArray, -} from './es_system_indices_migration'; - -export function getShardCapacityDeprecationInfo({ - symptom, - details, -}: { - details: any; - symptom: any; -}) { - // When we dont have a details field for our indicator, we can only report - // the symptom to the user given that's the only information about the deprecation - // we have. - if (!details) { - return { - details: symptom, - message: symptom, - url: null, - resolveDuringUpgrade: false, - }; - } - - const causes = []; - if (details.indices_with_readonly_block > 0) { - causes.push( - i18n.translate( - 'xpack.upgradeAssistant.esDeprecationsStatus.indicesWithReadonlyBlockCauseMessage', - { - defaultMessage: - 'The number of indices the system enforced a read-only index block (`index.blocks.read_only_allow_delete`) on because the cluster is running out of space.', - } - ) - ); - } - - if (details.nodes_over_high_watermark > 0) { - causes.push( - i18n.translate( - 'xpack.upgradeAssistant.esDeprecationsStatus.nodesOverHighWatermarkCauseMessage', - { - defaultMessage: - 'The number of nodes that are running low on disk and it is likely that they will run out of space. Their disk usage has tripped the <>.', - ignoreTag: true, - } - ) - ); - } - - if (details.nodes_over_flood_stage_watermark > 0) { - causes.push( - i18n.translate( - 'xpack.upgradeAssistant.esDeprecationsStatus.nodesOverFloodStageWatermarkCauseMessage', - { - defaultMessage: - 'The number of nodes that have run out of disk. Their disk usage has tripped the <>.', - ignoreTag: true, - } - ) - ); - } - - return { - details: symptom, - message: symptom, - url: null, - resolveDuringUpgrade: false, - correctiveAction: { - type: 'healthIndicator', - impacts: details, - cause: causes.join('\n'), - }, - }; -} - -export async function getHealthIndicators( - dataClient: IScopedClusterClient -): Promise { - const healthIndicators = await dataClient.asCurrentUser.healthReport(); - const isStatusNotGreen = (indicator?: estypes.HealthReportBaseIndicator): boolean => { - return !!(indicator?.status && indicator?.status !== 'green'); - }; - - // Temporarily ignoring due to untyped ES indicators - // types will be available during 8.9.0 - // @ts-ignore - return [ - ...[ - // @ts-ignore - healthIndicators.indicators.shards_capacity as estypes.HealthReportBaseIndicator, - ] - .filter(isStatusNotGreen) - .flatMap(({ status, symptom, impacts, diagnosis }) => { - // eslint-disable-next-line @typescript-eslint/naming-convention - return (diagnosis || []).map(({ cause, action, help_url }) => ({ - type: 'health_indicator', - details: symptom, - message: cause, - url: help_url, - isCritical: status === 'red', - resolveDuringUpgrade: false, - correctiveAction: { type: 'healthIndicator', cause, action, impacts }, - })); - }), - ...[healthIndicators.indicators.disk as estypes.HealthReportDiskIndicator] - .filter(isStatusNotGreen) - .flatMap(({ status, symptom, details }) => { - return { - type: 'health_indicator', - isCritical: status === 'red', - ...getShardCapacityDeprecationInfo({ symptom, details }), - }; - }), - ]; -} - -export async function getESUpgradeStatus( - dataClient: IScopedClusterClient, - featureSet: FeatureSet -): Promise { - const getCombinedDeprecations = async () => { - const healthIndicators = await getHealthIndicators(dataClient); - const deprecations = await dataClient.asCurrentUser.migration.deprecations(); - const indices = await getCombinedIndexInfos(deprecations, dataClient); - const systemIndices = await getESSystemIndicesMigrationStatus(dataClient.asCurrentUser); - const systemIndicesList = convertFeaturesToIndicesArray(systemIndices.features); - - const enrichedDeprecations = Object.keys(deprecations).reduce( - (combinedDeprecations, deprecationType) => { - if (deprecationType === 'index_settings') { - // We need to exclude all index related deprecations for system indices since - // they are resolved separately through the system indices upgrade section in - // the Overview page. - const withoutSystemIndices = indices.filter( - (index) => !systemIndicesList.includes(index.index!) - ); - - combinedDeprecations = combinedDeprecations.concat(withoutSystemIndices); - } else { - const deprecationsByType = deprecations[ - deprecationType as keyof estypes.MigrationDeprecationsResponse - ] as estypes.MigrationDeprecationsDeprecation[]; - - const enrichedDeprecationInfo = deprecationsByType - .map( - ({ - details, - level, - message, - url, - // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse - _meta: metadata, - // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse - resolve_during_rolling_upgrade: resolveDuringUpgrade, - }) => { - return { - details, - message, - url, - type: deprecationType as keyof estypes.MigrationDeprecationsResponse, - isCritical: level === 'critical', - resolveDuringUpgrade, - correctiveAction: getCorrectiveAction(message, metadata), - }; - } - ) - .filter(({ correctiveAction, type }) => { - /** - * This disables showing the ML deprecations in the UA if `featureSet.mlSnapshots` - * is set to `false`. - * - * This config should be set to true only on the `x.last` versions, or when - * the constant `MachineLearningField.MIN_CHECKED_SUPPORTED_SNAPSHOT_VERSION` - * is incremented to something higher than 7.0.0 in the Elasticsearch code. - */ - if (!featureSet.mlSnapshots) { - if (type === 'ml_settings' || correctiveAction?.type === 'mlSnapshot') { - return false; - } - } - - /** - * This disables showing the reindexing deprecations in the UA if - * `featureSet.reindexCorrectiveActions` is set to `false`. - */ - if (!featureSet.reindexCorrectiveActions && correctiveAction?.type === 'reindex') { - return false; - } - - return true; - }); - - combinedDeprecations = combinedDeprecations.concat(enrichedDeprecationInfo); - } - - return combinedDeprecations; - }, - [] as EnrichedDeprecationInfo[] - ); - - const enrichedHealthIndicators = healthIndicators.filter(({ status }) => { - return status !== 'green'; - }) as EnrichedDeprecationInfo[]; - - return [...enrichedHealthIndicators, ...enrichedDeprecations]; - }; - - const combinedDeprecations = await getCombinedDeprecations(); - const criticalWarnings = combinedDeprecations.filter(({ isCritical }) => isCritical === true); - - return { - totalCriticalDeprecations: criticalWarnings.length, - deprecations: combinedDeprecations, - }; -} - -// Reformats the index deprecations to an array of deprecation warnings extended with an index field. -const getCombinedIndexInfos = async ( - deprecations: estypes.MigrationDeprecationsResponse, - dataClient: IScopedClusterClient -) => { - const indices = Object.keys(deprecations.index_settings).reduce( - (indexDeprecations, indexName) => { - return indexDeprecations.concat( - deprecations.index_settings[indexName].map( - ({ - details, - message, - url, - level, - // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse - _meta: metadata, - // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse - resolve_during_rolling_upgrade: resolveDuringUpgrade, - }) => - ({ - details, - message, - url, - index: indexName, - type: 'index_settings', - isCritical: level === 'critical', - correctiveAction: getCorrectiveAction(message, metadata, indexName), - resolveDuringUpgrade, - } as EnrichedDeprecationInfo) - ) - ); - }, - [] as EnrichedDeprecationInfo[] - ); - - const indexNames = indices.map(({ index }) => index!); - - // If we have found deprecation information for index/indices - // check whether the index is open or closed. - if (indexNames.length) { - const indexStates = await esIndicesStateCheck(dataClient.asCurrentUser, indexNames); - - indices.forEach((indexData) => { - if (indexData.correctiveAction?.type === 'reindex') { - indexData.correctiveAction.blockerForReindexing = - indexStates[indexData.index!] === 'closed' ? 'index-closed' : undefined; - } - }); - } - return indices as EnrichedDeprecationInfo[]; -}; - -interface Action { - action_type: 'remove_settings'; - objects: string[]; -} - -interface Actions { - actions: Action[]; -} - -type EsMetadata = Actions & { - [key: string]: string; -}; - -const getCorrectiveAction = ( - message: string, - metadata: EsMetadata, - indexName?: string -): EnrichedDeprecationInfo['correctiveAction'] => { - const indexSettingDeprecation = metadata?.actions?.find( - (action) => action.action_type === 'remove_settings' && indexName - ); - const clusterSettingDeprecation = metadata?.actions?.find( - (action) => action.action_type === 'remove_settings' && typeof indexName === 'undefined' - ); - const requiresReindexAction = /Index created before/.test(message); - const requiresIndexSettingsAction = Boolean(indexSettingDeprecation); - const requiresClusterSettingsAction = Boolean(clusterSettingDeprecation); - const requiresMlAction = /[Mm]odel snapshot/.test(message); - - if (requiresReindexAction) { - return { - type: 'reindex', - }; - } - - if (requiresIndexSettingsAction) { - return { - type: 'indexSetting', - deprecatedSettings: indexSettingDeprecation!.objects, - }; - } - - if (requiresClusterSettingsAction) { - return { - type: 'clusterSetting', - deprecatedSettings: clusterSettingDeprecation!.objects, - }; - } - - if (requiresMlAction) { - const { snapshot_id: snapshotId, job_id: jobId } = metadata!; - - return { - type: 'mlSnapshot', - snapshotId, - jobId, - }; - } -}; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/__snapshots__/index.test.ts.snap similarity index 92% rename from x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap rename to x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/__snapshots__/index.test.ts.snap index de0154037f9b..b0d5d99a3749 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/__snapshots__/es_deprecations_status.test.ts.snap +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/__snapshots__/index.test.ts.snap @@ -6,6 +6,7 @@ Object { Object { "correctiveAction": undefined, "details": "templates using \`template\` field: security_audit_log,watches,.monitoring-alerts,triggered_watches,.ml-anomalies-,.ml-notifications,.ml-meta,.monitoring-kibana,.monitoring-es,.monitoring-logstash,.watch-history-6,.ml-state,security-index-template", + "index": undefined, "isCritical": false, "message": "Template patterns are no longer using \`template\` field, but \`index_patterns\` instead", "resolveDuringUpgrade": false, @@ -15,6 +16,7 @@ Object { Object { "correctiveAction": undefined, "details": "{.monitoring-logstash=[Coercion of boolean fields], .monitoring-es=[Coercion of boolean fields], .ml-anomalies-=[Coercion of boolean fields], .watch-history-6=[Coercion of boolean fields], .monitoring-kibana=[Coercion of boolean fields], security-index-template=[Coercion of boolean fields]}", + "index": undefined, "isCritical": false, "message": "one or more templates use deprecated mapping settings", "resolveDuringUpgrade": false, @@ -24,6 +26,7 @@ Object { Object { "correctiveAction": undefined, "details": "[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]", + "index": undefined, "isCritical": false, "message": "Datafeed [deprecation-datafeed] uses deprecated query options", "resolveDuringUpgrade": false, @@ -37,6 +40,7 @@ Object { "type": "mlSnapshot", }, "details": "details", + "index": undefined, "isCritical": true, "message": "model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded", "resolveDuringUpgrade": false, @@ -46,6 +50,7 @@ Object { Object { "correctiveAction": undefined, "details": "This node thing is wrong", + "index": undefined, "isCritical": true, "message": "A node-level issue", "resolveDuringUpgrade": true, @@ -153,7 +158,17 @@ Object { "type": "index_settings", "url": "https://www.elastic.co/guide/en/elasticsearch/reference/6.0/breaking_60_mappings_changes.html#_coercion_of_boolean_fields", }, + Object { + "correctiveAction": undefined, + "details": "This data stream has backing indices that were created before Elasticsearch 8.0.0", + "index": "my-v7-data-stream", + "isCritical": true, + "message": "Old data stream with a compatibility version < 8.0", + "resolveDuringUpgrade": false, + "type": "data_streams", + "url": "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-9.0.html", + }, ], - "totalCriticalDeprecations": 4, + "totalCriticalDeprecations": 5, } `; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/get_corrective_actions.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/get_corrective_actions.ts new file mode 100644 index 000000000000..be696acb1809 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/get_corrective_actions.ts @@ -0,0 +1,68 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EnrichedDeprecationInfo } from '../../../common/types'; + +interface Action { + action_type: 'remove_settings'; + objects: string[]; +} + +interface Actions { + actions: Action[]; +} + +type EsMetadata = Actions & { + [key: string]: string; +}; + +export const getCorrectiveAction = ( + message: string, + metadata: EsMetadata, + indexName?: string +): EnrichedDeprecationInfo['correctiveAction'] => { + const indexSettingDeprecation = metadata?.actions?.find( + (action) => action.action_type === 'remove_settings' && indexName + ); + const clusterSettingDeprecation = metadata?.actions?.find( + (action) => action.action_type === 'remove_settings' && typeof indexName === 'undefined' + ); + const requiresReindexAction = /Index created before/.test(message); + const requiresIndexSettingsAction = Boolean(indexSettingDeprecation); + const requiresClusterSettingsAction = Boolean(clusterSettingDeprecation); + const requiresMlAction = /[Mm]odel snapshot/.test(message); + + if (requiresReindexAction) { + return { + type: 'reindex', + }; + } + + if (requiresIndexSettingsAction) { + return { + type: 'indexSetting', + deprecatedSettings: indexSettingDeprecation!.objects, + }; + } + + if (requiresClusterSettingsAction) { + return { + type: 'clusterSetting', + deprecatedSettings: clusterSettingDeprecation!.objects, + }; + } + + if (requiresMlAction) { + const { snapshot_id: snapshotId, job_id: jobId } = metadata!; + + return { + type: 'mlSnapshot', + snapshotId, + jobId, + }; + } +}; diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/health_indicators.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/health_indicators.test.ts new file mode 100644 index 000000000000..3f16d0f9e94c --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/health_indicators.test.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { elasticsearchServiceMock, ScopedClusterClientMock } from '@kbn/core/server/mocks'; +import { getHealthIndicators } from './health_indicators'; +import * as healthIndicatorsMock from '../__fixtures__/health_indicators'; + +describe('getHealthIndicators', () => { + let esClient: ScopedClusterClientMock; + beforeEach(() => { + esClient = elasticsearchServiceMock.createScopedClusterClient(); + }); + + it('returns empty array on green indicators', async () => { + esClient.asCurrentUser.healthReport.mockResponse({ + cluster_name: 'mock', + indicators: { + disk: healthIndicatorsMock.diskIndicatorGreen, + // @ts-ignore + shards_capacity: healthIndicatorsMock.shardCapacityIndicatorGreen, + }, + }); + + const result = await getHealthIndicators(esClient); + expect(result).toEqual([]); + }); + + it('returns unknown indicators', async () => { + esClient.asCurrentUser.healthReport.mockResponse({ + cluster_name: 'mock', + indicators: { + disk: healthIndicatorsMock.diskIndicatorUnknown, + // @ts-ignore + shards_capacity: healthIndicatorsMock.shardCapacityIndicatorGreen, + }, + }); + + const result = await getHealthIndicators(esClient); + expect(result[0]).toEqual( + expect.objectContaining({ + details: 'No disk usage data.', + }) + ); + }); + + it('returns unhealthy shards_capacity indicator', async () => { + esClient.asCurrentUser.healthReport.mockResponse({ + cluster_name: 'mock', + indicators: { + disk: healthIndicatorsMock.diskIndicatorGreen, + // @ts-ignore + shards_capacity: healthIndicatorsMock.shardCapacityIndicatorRed, + }, + }); + + const result = await getHealthIndicators(esClient); + expect(result).toMatchInlineSnapshot(` + Array [ + Object { + "correctiveAction": Object { + "action": "Increase the value of [cluster.max_shards_per_node] cluster setting or remove data indices to clear up resources.", + "cause": "Elasticsearch is about to reach the maximum number of shards it can host, based on your current settings.", + "impacts": Array [ + Object { + "description": "The cluster has too many used shards to be able to upgrade.", + "id": "elasticsearch:health:shards_capacity:impact:upgrade_blocked", + "impact_areas": "[Array]", + "severity": 1, + }, + Object { + "description": "The cluster is running low on room to add new shards. Adding data to new indices is at risk", + "id": "elasticsearch:health:shards_capacity:impact:creation_of_new_indices_blocked", + "impact_areas": "[Array]", + "severity": 1, + }, + ], + "type": "healthIndicator", + }, + "details": "Cluster is close to reaching the configured maximum number of shards for data nodes.", + "isCritical": true, + "message": "Elasticsearch is about to reach the maximum number of shards it can host, based on your current settings.", + "resolveDuringUpgrade": false, + "type": "health_indicator", + "url": "https://ela.st/fix-shards-capacity", + }, + ] + `); + }); + + it('returns unhealthy disk indicator', async () => { + esClient.asCurrentUser.healthReport.mockResponse({ + cluster_name: 'mock', + indicators: { + disk: healthIndicatorsMock.diskIndicatorRed, + // @ts-ignore + shards_capacity: healthIndicatorsMock.shardCapacityIndicatorGreen, + }, + }); + + const result = await getHealthIndicators(esClient); + expect(result).toMatchInlineSnapshot(` + Array [ + Object { + "correctiveAction": Object { + "cause": "The number of indices the system enforced a read-only index block (\`index.blocks.read_only_allow_delete\`) on because the cluster is running out of space. + The number of nodes that are running low on disk and it is likely that they will run out of space. Their disk usage has tripped the <>. + The number of nodes that have run out of disk. Their disk usage has tripped the <>.", + "impacts": Object { + "indices_with_readonly_block": 1, + "nodes_over_flood_stage_watermark": 1, + "nodes_over_high_watermark": 1, + "nodes_with_enough_disk_space": 1, + "nodes_with_unknown_disk_status": 1, + }, + "type": "healthIndicator", + }, + "details": "The cluster does not have enough available disk space.", + "isCritical": true, + "message": "The cluster does not have enough available disk space.", + "resolveDuringUpgrade": false, + "type": "health_indicator", + "url": null, + }, + ] + `); + }); +}); diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/health_indicators.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/health_indicators.ts new file mode 100644 index 000000000000..372582220659 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/health_indicators.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { i18n } from '@kbn/i18n'; +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IScopedClusterClient } from '@kbn/core/server'; +import { EnrichedDeprecationInfo } from '../../../common/types'; + +export async function getHealthIndicators( + dataClient: IScopedClusterClient +): Promise { + const healthIndicators = await dataClient.asCurrentUser.healthReport(); + const isStatusNotGreen = (indicator?: estypes.HealthReportBaseIndicator): boolean => { + return !!(indicator?.status && indicator?.status !== 'green'); + }; + + // Temporarily ignoring due to untyped ES indicators + // types will be available during 8.9.0 + // @ts-ignore + return [ + ...[ + // @ts-ignore + healthIndicators.indicators.shards_capacity as estypes.HealthReportBaseIndicator, + ] + .filter(isStatusNotGreen) + .flatMap(({ status, symptom, impacts, diagnosis }) => { + // eslint-disable-next-line @typescript-eslint/naming-convention + return (diagnosis || []).map(({ cause, action, help_url }) => ({ + type: 'health_indicator', + details: symptom, + message: cause, + url: help_url, + isCritical: status === 'red', + resolveDuringUpgrade: false, + correctiveAction: { type: 'healthIndicator', cause, action, impacts }, + })); + }), + ...[healthIndicators.indicators.disk as estypes.HealthReportDiskIndicator] + .filter(isStatusNotGreen) + .flatMap(({ status, symptom, details }) => { + return { + type: 'health_indicator', + isCritical: status === 'red', + ...getShardCapacityDeprecationInfo({ symptom, details }), + }; + }), + ]; +} + +export function getShardCapacityDeprecationInfo({ + symptom, + details, +}: { + details: any; + symptom: any; +}) { + // When we dont have a details field for our indicator, we can only report + // the symptom to the user given that's the only information about the deprecation + // we have. + if (!details) { + return { + details: symptom, + message: symptom, + url: null, + resolveDuringUpgrade: false, + }; + } + + const causes = []; + if (details.indices_with_readonly_block > 0) { + causes.push( + i18n.translate( + 'xpack.upgradeAssistant.esDeprecationsStatus.indicesWithReadonlyBlockCauseMessage', + { + defaultMessage: + 'The number of indices the system enforced a read-only index block (`index.blocks.read_only_allow_delete`) on because the cluster is running out of space.', + } + ) + ); + } + + if (details.nodes_over_high_watermark > 0) { + causes.push( + i18n.translate( + 'xpack.upgradeAssistant.esDeprecationsStatus.nodesOverHighWatermarkCauseMessage', + { + defaultMessage: + 'The number of nodes that are running low on disk and it is likely that they will run out of space. Their disk usage has tripped the <>.', + ignoreTag: true, + } + ) + ); + } + + if (details.nodes_over_flood_stage_watermark > 0) { + causes.push( + i18n.translate( + 'xpack.upgradeAssistant.esDeprecationsStatus.nodesOverFloodStageWatermarkCauseMessage', + { + defaultMessage: + 'The number of nodes that have run out of disk. Their disk usage has tripped the <>.', + ignoreTag: true, + } + ) + ); + } + + return { + details: symptom, + message: symptom, + url: null, + resolveDuringUpgrade: false, + correctiveAction: { + type: 'healthIndicator', + impacts: details, + cause: causes.join('\n'), + }, + }; +} diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/index.test.ts similarity index 56% rename from x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts rename to x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/index.test.ts index 3a373cbffbfe..c7a8c1399309 100644 --- a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status.test.ts +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/index.test.ts @@ -6,142 +6,22 @@ */ import _ from 'lodash'; -import { elasticsearchServiceMock, ScopedClusterClientMock } from '@kbn/core/server/mocks'; +import { elasticsearchServiceMock } from '@kbn/core/server/mocks'; import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; -import { getESUpgradeStatus, getHealthIndicators } from './es_deprecations_status'; -import fakeDeprecations from './__fixtures__/fake_deprecations.json'; -import * as healthIndicatorsMock from './__fixtures__/health_indicators'; - -import type { FeatureSet } from '../../common/types'; +import fakeDeprecations from '../__fixtures__/fake_deprecations.json'; +import * as healthIndicatorsMock from '../__fixtures__/health_indicators'; +import * as esMigrationsMock from '../__fixtures__/es_deprecations'; +import type { FeatureSet } from '../../../common/types'; +import { getESUpgradeStatus } from '.'; const fakeIndexNames = Object.keys(fakeDeprecations.index_settings); -describe('getHealthIndicators', () => { - let esClient: ScopedClusterClientMock; - beforeEach(() => { - esClient = elasticsearchServiceMock.createScopedClusterClient(); - }); - - it('returns empty array on green indicators', async () => { - esClient.asCurrentUser.healthReport.mockResponse({ - cluster_name: 'mock', - indicators: { - disk: healthIndicatorsMock.diskIndicatorGreen, - // @ts-ignore - shards_capacity: healthIndicatorsMock.shardCapacityIndicatorGreen, - }, - }); - - const result = await getHealthIndicators(esClient); - expect(result).toEqual([]); - }); - - it('returns unknown indicators', async () => { - esClient.asCurrentUser.healthReport.mockResponse({ - cluster_name: 'mock', - indicators: { - disk: healthIndicatorsMock.diskIndicatorUnknown, - // @ts-ignore - shards_capacity: healthIndicatorsMock.shardCapacityIndicatorGreen, - }, - }); - - const result = await getHealthIndicators(esClient); - expect(result[0]).toEqual( - expect.objectContaining({ - details: 'No disk usage data.', - }) - ); - }); - - it('returns unhealthy shards_capacity indicator', async () => { - esClient.asCurrentUser.healthReport.mockResponse({ - cluster_name: 'mock', - indicators: { - disk: healthIndicatorsMock.diskIndicatorGreen, - // @ts-ignore - shards_capacity: healthIndicatorsMock.shardCapacityIndicatorRed, - }, - }); - - const result = await getHealthIndicators(esClient); - expect(result).toMatchInlineSnapshot(` - Array [ - Object { - "correctiveAction": Object { - "action": "Increase the value of [cluster.max_shards_per_node] cluster setting or remove data indices to clear up resources.", - "cause": "Elasticsearch is about to reach the maximum number of shards it can host, based on your current settings.", - "impacts": Array [ - Object { - "description": "The cluster has too many used shards to be able to upgrade.", - "id": "elasticsearch:health:shards_capacity:impact:upgrade_blocked", - "impact_areas": "[Array]", - "severity": 1, - }, - Object { - "description": "The cluster is running low on room to add new shards. Adding data to new indices is at risk", - "id": "elasticsearch:health:shards_capacity:impact:creation_of_new_indices_blocked", - "impact_areas": "[Array]", - "severity": 1, - }, - ], - "type": "healthIndicator", - }, - "details": "Cluster is close to reaching the configured maximum number of shards for data nodes.", - "isCritical": true, - "message": "Elasticsearch is about to reach the maximum number of shards it can host, based on your current settings.", - "resolveDuringUpgrade": false, - "type": "health_indicator", - "url": "https://ela.st/fix-shards-capacity", - }, - ] - `); - }); - - it('returns unhealthy disk indicator', async () => { - esClient.asCurrentUser.healthReport.mockResponse({ - cluster_name: 'mock', - indicators: { - disk: healthIndicatorsMock.diskIndicatorRed, - // @ts-ignore - shards_capacity: healthIndicatorsMock.shardCapacityIndicatorGreen, - }, - }); - - const result = await getHealthIndicators(esClient); - expect(result).toMatchInlineSnapshot(` - Array [ - Object { - "correctiveAction": Object { - "cause": "The number of indices the system enforced a read-only index block (\`index.blocks.read_only_allow_delete\`) on because the cluster is running out of space. - The number of nodes that are running low on disk and it is likely that they will run out of space. Their disk usage has tripped the <>. - The number of nodes that have run out of disk. Their disk usage has tripped the <>.", - "impacts": Object { - "indices_with_readonly_block": 1, - "nodes_over_flood_stage_watermark": 1, - "nodes_over_high_watermark": 1, - "nodes_with_enough_disk_space": 1, - "nodes_with_unknown_disk_status": 1, - }, - "type": "healthIndicator", - }, - "details": "The cluster does not have enough available disk space.", - "isCritical": true, - "message": "The cluster does not have enough available disk space.", - "resolveDuringUpgrade": false, - "type": "health_indicator", - "url": null, - }, - ] - `); - }); -}); - describe('getESUpgradeStatus', () => { const featureSet: FeatureSet = { reindexCorrectiveActions: true, migrateSystemIndices: true, mlSnapshots: true, + migrateDataStreams: true, }; const resolvedIndices = { @@ -200,6 +80,7 @@ describe('getESUpgradeStatus', () => { node_settings: [], ml_settings: [], index_settings: {}, + data_streams: {}, }); await expect(getESUpgradeStatus(esClient, featureSet)).resolves.toHaveProperty( @@ -215,6 +96,7 @@ describe('getESUpgradeStatus', () => { node_settings: [], ml_settings: [], index_settings: {}, + data_streams: {}, }); await expect(getESUpgradeStatus(esClient, featureSet)).resolves.toHaveProperty( @@ -240,6 +122,7 @@ describe('getESUpgradeStatus', () => { }, ], }, + data_streams: {}, }); const upgradeStatus = await getESUpgradeStatus(esClient, featureSet); @@ -249,38 +132,44 @@ describe('getESUpgradeStatus', () => { }); it('filters out ml_settings if featureSet.mlSnapshots is set to false', async () => { - esClient.asCurrentUser.migration.deprecations.mockResponse({ - cluster_settings: [], - node_settings: [], - ml_settings: [ - { - level: 'warning', - message: 'Datafeed [deprecation-datafeed] uses deprecated query options', - url: 'https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-7.0.html#breaking_70_search_changes', - details: - '[Deprecated field [use_dis_max] used, replaced by [Set [tie_breaker] to 1 instead]]', - // @ts-ignore - resolve_during_rolling_upgrade: false, - }, - { - level: 'critical', - message: - 'model snapshot [1] for job [deprecation_check_job] needs to be deleted or upgraded', - url: '', - details: 'details', - // @ts-ignore - _meta: { snapshot_id: '1', job_id: 'deprecation_check_job' }, - // @ts-ignore - resolve_during_rolling_upgrade: false, - }, - ], - index_settings: {}, + const mockResponse = { + ...esMigrationsMock.getMockEsDeprecations(), + ...esMigrationsMock.getMockMlSettingsDeprecations(), + }; + // @ts-ignore missing property definitions in ES resolve_during_rolling_upgrade and _meta + esClient.asCurrentUser.migration.deprecations.mockResponse(mockResponse); + + const enabledUpgradeStatus = await getESUpgradeStatus(esClient, { ...featureSet }); + expect(enabledUpgradeStatus.deprecations).toHaveLength(2); + expect(enabledUpgradeStatus.totalCriticalDeprecations).toBe(1); + + const disabledUpgradeStatus = await getESUpgradeStatus(esClient, { + ...featureSet, + mlSnapshots: false, }); - const upgradeStatus = await getESUpgradeStatus(esClient, { ...featureSet, mlSnapshots: false }); + expect(disabledUpgradeStatus.deprecations).toHaveLength(0); + expect(disabledUpgradeStatus.totalCriticalDeprecations).toBe(0); + }); - expect(upgradeStatus.deprecations).toHaveLength(0); - expect(upgradeStatus.totalCriticalDeprecations).toBe(0); + it('filters out data_streams if featureSet.migrateDataStreams is set to false', async () => { + const mockResponse = { + ...esMigrationsMock.getMockEsDeprecations(), + ...esMigrationsMock.getMockDataStreamDeprecations(), + }; + esClient.asCurrentUser.migration.deprecations.mockResponse(mockResponse); + + const enabledUpgradeStatus = await getESUpgradeStatus(esClient, { ...featureSet }); + expect(enabledUpgradeStatus.deprecations).toHaveLength(1); + expect(enabledUpgradeStatus.totalCriticalDeprecations).toBe(1); + + const disabledUpgradeStatus = await getESUpgradeStatus(esClient, { + ...featureSet, + migrateDataStreams: false, + }); + + expect(disabledUpgradeStatus.deprecations).toHaveLength(0); + expect(disabledUpgradeStatus.totalCriticalDeprecations).toBe(0); }); it('filters out reindex corrective actions if featureSet.reindexCorrectiveActions is set to false', async () => { @@ -306,6 +195,7 @@ describe('getESUpgradeStatus', () => { ], ml_settings: [], index_settings: {}, + data_streams: {}, }); const upgradeStatus = await getESUpgradeStatus(esClient, { @@ -332,6 +222,7 @@ describe('getESUpgradeStatus', () => { ], ml_settings: [], index_settings: {}, + data_streams: {}, }); esClient.asCurrentUser.healthReport.mockResponse({ @@ -380,6 +271,7 @@ describe('getESUpgradeStatus', () => { "type": "reindex", }, "details": "This index was created using version: 6.8.13", + "index": undefined, "isCritical": true, "message": "Index created before 7.0", "resolveDuringUpgrade": false, diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/index.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/index.ts new file mode 100644 index 000000000000..062c62660a53 --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/index.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { IScopedClusterClient } from '@kbn/core/server'; +import { EnrichedDeprecationInfo, ESUpgradeStatus, FeatureSet } from '../../../common/types'; +import { getEnrichedDeprecations } from './migrations'; +import { getHealthIndicators } from './health_indicators'; + +export async function getESUpgradeStatus( + dataClient: IScopedClusterClient, + featureSet: FeatureSet +): Promise { + const getCombinedDeprecations = async () => { + const healthIndicators = await getHealthIndicators(dataClient); + const enrichedDeprecations = await getEnrichedDeprecations(dataClient); + + const toggledMigrationsDeprecations = enrichedDeprecations.filter( + ({ type, correctiveAction }) => { + /** + * This disables showing the ML deprecations in the UA if `featureSet.mlSnapshots` + * is set to `false`. + * + * This config should be set to true only on the `x.last` versions, or when + * the constant `MachineLearningField.MIN_CHECKED_SUPPORTED_SNAPSHOT_VERSION` + * is incremented to something higher than 7.0.0 in the Elasticsearch code. + */ + if (type === 'ml_settings' || correctiveAction?.type === 'mlSnapshot') { + return featureSet.mlSnapshots; + } + + /** + * This disables showing the Data streams deprecations in the UA if + * `featureSet.migrateDataStreams` is set to `false`. + */ + if (type === 'data_streams') { + return !!featureSet.migrateDataStreams; + } + + /** + * This disables showing the reindexing deprecations in the UA if + * `featureSet.reindexCorrectiveActions` is set to `false`. + */ + if (correctiveAction?.type === 'reindex') { + return !!featureSet.reindexCorrectiveActions; + } + + return true; + } + ); + + const enrichedHealthIndicators = healthIndicators.filter(({ status }) => { + return status !== 'green'; + }) as EnrichedDeprecationInfo[]; + + return [...enrichedHealthIndicators, ...toggledMigrationsDeprecations]; + }; + + const combinedDeprecations = await getCombinedDeprecations(); + const criticalWarnings = combinedDeprecations.filter(({ isCritical }) => isCritical === true); + + return { + totalCriticalDeprecations: criticalWarnings.length, + deprecations: combinedDeprecations, + }; +} diff --git a/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/migrations.ts b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/migrations.ts new file mode 100644 index 000000000000..39d9984a64aa --- /dev/null +++ b/x-pack/plugins/upgrade_assistant/server/lib/es_deprecations_status/migrations.ts @@ -0,0 +1,157 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { + MigrationDeprecationsResponse, + MigrationDeprecationsDeprecation, +} from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { IScopedClusterClient } from '@kbn/core-elasticsearch-server'; +import _ from 'lodash'; +import { EnrichedDeprecationInfo } from '../../../common/types'; +import { + convertFeaturesToIndicesArray, + getESSystemIndicesMigrationStatus, +} from '../es_system_indices_migration'; +import { getCorrectiveAction } from './get_corrective_actions'; +import { esIndicesStateCheck } from '../es_indices_state_check'; + +/** + * Remove once the data_streams type is added to the `MigrationDeprecationsResponse` type + */ +interface EsDeprecations extends MigrationDeprecationsResponse { + data_streams: Record; +} + +const createBaseMigrationDeprecation = ( + migrationDeprecation: MigrationDeprecationsDeprecation, + { deprecationType, indexName }: { deprecationType: keyof EsDeprecations; indexName?: string } +) => { + const { + details, + message, + url, + level, + // @ts-expect-error @elastic/elasticsearch _meta not available yet in MigrationDeprecationInfoResponse + _meta: metadata, + // @ts-expect-error @elastic/elasticsearch resolve_during_rolling_upgrade not available yet in MigrationDeprecationInfoResponse + resolve_during_rolling_upgrade: resolveDuringUpgrade, + } = migrationDeprecation; + + return { + index: indexName, + type: deprecationType, + details, + message, + url, + isCritical: level === 'critical', + metadata, + resolveDuringUpgrade, + }; +}; + +const normalizeEsResponse = (migrationsResponse: EsDeprecations) => { + const indexSettingsMigrations = Object.entries(migrationsResponse.index_settings).flatMap( + ([indexName, migrationDeprecations]) => { + return migrationDeprecations.flatMap((migrationDeprecation) => + createBaseMigrationDeprecation(migrationDeprecation, { + indexName, + deprecationType: 'index_settings', + }) + ); + } + ); + + const dataStreamsMigrations = Object.entries(migrationsResponse.data_streams).flatMap( + ([indexName, dataStreamDeprecations]) => { + return dataStreamDeprecations.flatMap((depractionData) => + createBaseMigrationDeprecation(depractionData, { + indexName, + deprecationType: 'data_streams', + }) + ); + } + ); + + const mlSettingsMigrations = migrationsResponse.ml_settings.map((depractionData) => + createBaseMigrationDeprecation(depractionData, { deprecationType: 'ml_settings' }) + ); + const nodeSettingsMigrations = migrationsResponse.node_settings.map((depractionData) => + createBaseMigrationDeprecation(depractionData, { deprecationType: 'node_settings' }) + ); + + const clusterSettingsMigrations = migrationsResponse.cluster_settings.map((depractionData) => + createBaseMigrationDeprecation(depractionData, { deprecationType: 'cluster_settings' }) + ); + + return [ + ...clusterSettingsMigrations, + ...mlSettingsMigrations, + ...nodeSettingsMigrations, + ...indexSettingsMigrations, + ...dataStreamsMigrations, + ].flat(); +}; + +export const getEnrichedDeprecations = async ( + dataClient: IScopedClusterClient +): Promise => { + const deprecations = (await dataClient.asCurrentUser.migration.deprecations()) as EsDeprecations; + const systemIndices = await getESSystemIndicesMigrationStatus(dataClient.asCurrentUser); + + const systemIndicesList = convertFeaturesToIndicesArray(systemIndices.features); + + const indexSettingsIndexNames = Object.keys(deprecations.index_settings).map( + (indexName) => indexName! + ); + const indexSettingsIndexStates = indexSettingsIndexNames.length + ? await esIndicesStateCheck(dataClient.asCurrentUser, indexSettingsIndexNames) + : {}; + + return normalizeEsResponse(deprecations) + .filter((deprecation) => { + switch (deprecation.type) { + case 'index_settings': { + if (!deprecation.index) { + return false; + } + // filter out system indices + return !systemIndicesList.includes(deprecation.index); + } + case 'cluster_settings': + case 'ml_settings': + case 'node_settings': + case 'data_streams': { + return true; + } + default: { + // Throwing here to avoid allowing upgrades while we have unhandled deprecation types from ES + // That might cause the stack to fail to start after upgrade. + throw new Error(`Unknown ES deprecation type "${deprecation.type}"`); + } + } + }) + .map((deprecation) => { + const correctiveAction = getCorrectiveAction( + deprecation.message, + deprecation.metadata, + deprecation.index! + ); + + // If we have found deprecation information for index/indices + // check whether the index is open or closed. + if (deprecation.type === 'index_settings' && correctiveAction?.type === 'reindex') { + correctiveAction.blockerForReindexing = + indexSettingsIndexStates[deprecation.index!] === 'closed' ? 'index-closed' : undefined; + } + + const enrichedDeprecation = _.omit(deprecation, 'metadata'); + return { + ...enrichedDeprecation, + correctiveAction, + }; + }); +}; diff --git a/x-pack/plugins/upgrade_assistant/tsconfig.json b/x-pack/plugins/upgrade_assistant/tsconfig.json index 85fb886ca2af..d78cafa21551 100644 --- a/x-pack/plugins/upgrade_assistant/tsconfig.json +++ b/x-pack/plugins/upgrade_assistant/tsconfig.json @@ -42,7 +42,8 @@ "@kbn/deeplinks-observability", "@kbn/core-logging-server-mocks", "@kbn/core-http-server-mocks", - "@kbn/core-http-server-utils" + "@kbn/core-http-server-utils", + "@kbn/core-elasticsearch-server" ], "exclude": [ "target/**/*", diff --git a/x-pack/test/alerting_api_integration/common/config.ts b/x-pack/test/alerting_api_integration/common/config.ts index b8a576f99b8d..04d6a1c48b98 100644 --- a/x-pack/test/alerting_api_integration/common/config.ts +++ b/x-pack/test/alerting_api_integration/common/config.ts @@ -217,7 +217,6 @@ export function createTestConfig(name: string, options: CreateTestConfigOptions) ...emailSettings, ...maxScheduledPerMinuteSettings, '--xpack.eventLog.logEntries=true', - '--xpack.task_manager.ephemeral_tasks.enabled=false', `--xpack.task_manager.unsafe.exclude_task_types=${JSON.stringify([ 'actions:test.excluded', ])}`, diff --git a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts index 9210e9f71ed9..62b6d6594b06 100644 --- a/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts +++ b/x-pack/test/alerting_api_integration/common/plugins/alerts/server/plugin.ts @@ -8,10 +8,7 @@ import { Plugin, CoreSetup, CoreStart, Logger, PluginInitializerContext } from '@kbn/core/server'; import { firstValueFrom, Subject } from 'rxjs'; import { PluginSetupContract as ActionsPluginSetup } from '@kbn/actions-plugin/server/plugin'; -import { - PluginStartContract as AlertingPluginsStart, - PluginSetupContract as AlertingPluginSetup, -} from '@kbn/alerting-plugin/server/plugin'; +import { AlertingServerSetup, AlertingServerStart } from '@kbn/alerting-plugin/server/plugin'; import { TaskManagerSetupContract, TaskManagerStartContract, @@ -25,6 +22,7 @@ import { RuleRegistryPluginSetupContract } from '@kbn/rule-registry-plugin/serve import { IEventLogClientService } from '@kbn/event-log-plugin/server'; import { NotificationsPluginStart } from '@kbn/notifications-plugin/server'; import { RULE_SAVED_OBJECT_TYPE } from '@kbn/alerting-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; import { defineRoutes } from './routes'; import { defineActionTypes } from './action_types'; @@ -34,13 +32,13 @@ import { defineConnectorAdapters } from './connector_adapters'; export interface FixtureSetupDeps { features: FeaturesPluginSetup; actions: ActionsPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; taskManager: TaskManagerSetupContract; ruleRegistry: RuleRegistryPluginSetupContract; } export interface FixtureStartDeps { - alerting: AlertingPluginsStart; + alerting: AlertingServerStart; encryptedSavedObjects: EncryptedSavedObjectsPluginStart; security?: SecurityPluginStart; spaces?: SpacesPluginStart; @@ -50,6 +48,35 @@ export interface FixtureStartDeps { notifications: NotificationsPluginStart; } +const testRuleTypes = [ + 'test.always-firing', + 'test.cumulative-firing', + 'test.never-firing', + 'test.failing', + 'test.authorization', + 'test.delayed', + 'test.validation', + 'test.onlyContextVariables', + 'test.onlyStateVariables', + 'test.noop', + 'test.unrestricted-noop', + 'test.patternFiring', + 'test.patternSuccessOrFailure', + 'test.throw', + 'test.longRunning', + 'test.exceedsAlertLimit', + 'test.always-firing-alert-as-data', + 'test.patternFiringAad', + 'test.waitingRule', + 'test.patternFiringAutoRecoverFalse', + 'test.severity', +]; + +const testAlertingFeatures = testRuleTypes.map((ruleTypeId) => ({ + ruleTypeId, + consumers: ['alertsFixture', ALERTING_FEATURE_ID], +})); + export class FixturePlugin implements Plugin { private readonly logger: Logger; @@ -72,30 +99,8 @@ export class FixturePlugin implements Plugin { const defaultStart = moment().utc().startOf('day').subtract(7, 'days').toISOString(); const defaultEnd = moment().utc().startOf('day').subtract(1, 'day').toISOString(); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_untrack_by_query.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_untrack_by_query.ts index 794cb7367773..66d04b723ca0 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_untrack_by_query.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/bulk_untrack_by_query.ts @@ -130,7 +130,7 @@ export default function bulkUntrackByQueryTests({ getService }: FtrProviderConte }, }, ], - feature_ids: ['alertsFixture'], + rule_type_ids: ['test.always-firing-alert-as-data'], }); switch (scenario.id) { diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts index 95e6f7043c90..d0716df4e2db 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/create.ts @@ -261,18 +261,11 @@ export default function createAlertTests({ getService }: FtrProviderContext) { switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('create', 'test.noop', 'alerts'), - statusCode: 403, - }); - break; case 'global_read at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('create', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('create', 'test.noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/delete.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/delete.ts index d6cb57261a55..6814ed46c42b 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/delete.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/delete.ts @@ -219,7 +219,7 @@ export default function createDeleteTests({ getService }: FtrProviderContext) { expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('delete', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('delete', 'test.noop', 'alerts'), statusCode: 403, }); objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts index 264df417440f..aa43d52d60ad 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/disable.ts @@ -255,18 +255,11 @@ export default function createDisableAlertTests({ getService }: FtrProviderConte switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('disable', 'test.noop', 'alerts'), - statusCode: 403, - }); - break; case 'global_read at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('disable', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('disable', 'test.noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/enable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/enable.ts index 581f6f13a63b..eef6ff320a82 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/enable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/enable.ts @@ -246,18 +246,11 @@ export default function createEnableAlertTests({ getService }: FtrProviderContex switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('enable', 'test.noop', 'alerts'), - statusCode: 403, - }); - break; case 'global_read at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('enable', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('enable', 'test.noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts index bf5595e5756c..da74893f8171 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find.ts @@ -8,12 +8,7 @@ import expect from '@kbn/expect'; import { chunk, omit } from 'lodash'; import { v4 as uuidv4 } from 'uuid'; -import { - ES_QUERY_ID, - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, -} from '@kbn/rule-data-utils'; -import { SuperuserAtSpace1, UserAtSpaceScenarios, StackAlertsOnly } from '../../../scenarios'; +import { SuperuserAtSpace1, UserAtSpaceScenarios } from '../../../scenarios'; import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -614,120 +609,5 @@ export default function createFindTests({ getService }: FtrProviderContext) { ]); }); }); - - describe('stack alerts', () => { - const ruleTypes = [ - [ - ES_QUERY_ID, - { - searchType: 'esQuery', - timeWindowSize: 5, - timeWindowUnit: 'm', - threshold: [1000], - thresholdComparator: '>', - size: 100, - esQuery: '{\n "query":{\n "match_all" : {}\n }\n }', - aggType: 'count', - groupBy: 'all', - termSize: 5, - excludeHitsFromPreviousRun: false, - sourceFields: [], - index: ['.kibana'], - timeField: 'created_at', - }, - ], - [ - OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, - { - criteria: [ - { - comparator: '>', - metrics: [ - { - name: 'A', - aggType: 'count', - }, - ], - threshold: [100], - timeSize: 1, - timeUnit: 'm', - }, - ], - alertOnNoData: false, - alertOnGroupDisappear: false, - searchConfiguration: { - query: { - query: '', - language: 'kuery', - }, - index: 'kibana-event-log-data-view', - }, - }, - ], - [ - ML_ANOMALY_DETECTION_RULE_TYPE_ID, - { - severity: 75, - resultType: 'bucket', - includeInterim: false, - jobSelection: { - jobIds: ['low_request_rate'], - }, - }, - ], - ]; - - const createRule = async (rule = {}) => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix('space1')}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(getTestRuleData({ ...rule })) - .expect(200); - - objectRemover.add('space1', createdAlert.id, 'rule', 'alerting'); - }; - - for (const [ruleTypeId, params] of ruleTypes) { - it(`should get rules of ${ruleTypeId} rule type ID and stackAlerts consumer`, async () => { - /** - * We create two rules. The first one is a test.noop - * rule with stackAlerts as consumer. The second rule - * is has different rule type ID but with the same consumer as the first rule (stackAlerts). - * This way we can verify that the find API call returns only the rules the user is authorized to. - * Specifically only the second rule because the StackAlertsOnly user does not have - * access to the test.noop rule type. - */ - await createRule({ consumer: 'stackAlerts' }); - await createRule({ rule_type_id: ruleTypeId, params, consumer: 'stackAlerts' }); - - const response = await supertestWithoutAuth - .get(`${getUrlPrefix('space1')}/api/alerting/rules/_find`) - .auth(StackAlertsOnly.username, StackAlertsOnly.password); - - expect(response.statusCode).to.eql(200); - expect(response.body.total).to.equal(1); - expect(response.body.data[0].rule_type_id).to.equal(ruleTypeId); - expect(response.body.data[0].consumer).to.equal('stackAlerts'); - }); - } - - for (const [ruleTypeId, params] of ruleTypes) { - it(`should NOT get rules of ${ruleTypeId} rule type ID and NOT stackAlerts consumer`, async () => { - /** - * We create two rules with logs as consumer. The user is authorized to - * access rules only with the stackAlerts consumers. - */ - await createRule({ consumer: 'logs' }); - await createRule({ rule_type_id: ruleTypeId, params, consumer: 'logs' }); - - const response = await supertestWithoutAuth - .get(`${getUrlPrefix('space1')}/api/alerting/rules/_find`) - .auth(StackAlertsOnly.username, StackAlertsOnly.password); - - expect(response.statusCode).to.eql(200); - expect(response.body.total).to.equal(0); - }); - } - }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_internal.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_internal.ts index ee8d49c662ad..751d5cf16983 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_internal.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_internal.ts @@ -13,7 +13,13 @@ import { ML_ANOMALY_DETECTION_RULE_TYPE_ID, OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, } from '@kbn/rule-data-utils'; -import { SuperuserAtSpace1, UserAtSpaceScenarios, StackAlertsOnly } from '../../../scenarios'; +import { Space } from '../../../../common/types'; +import { + Space1AllAtSpace1, + StackAlertsOnly, + SuperuserAtSpace1, + UserAtSpaceScenarios, +} from '../../../scenarios'; import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; import { FtrProviderContext } from '../../../../common/ftr_provider_context'; @@ -31,40 +37,13 @@ export default function createFindTests({ getService }: FtrProviderContext) { for (const scenario of UserAtSpaceScenarios) { const { user, space } = scenario; + describe(scenario.id, () => { it('should handle find alert request appropriately', async () => { - const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/connector`) - .set('kbn-xsrf', 'foo') - .send({ - name: 'MY action', - connector_type_id: 'test.noop', - config: {}, - secrets: {}, - }) - .expect(200); - const { body: createdAlert } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - actions: [ - { - group: 'default', - id: createdAction.id, - params: {}, - frequency: { - summary: false, - notify_when: 'onThrottleInterval', - throttle: '1m', - }, - }, - ], - notify_when: undefined, - throttle: undefined, - }) - ) + .send(getTestRuleData()) .expect(200); objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); @@ -108,37 +87,23 @@ export default function createFindTests({ getService }: FtrProviderContext) { consumer: 'alertsFixture', schedule: { interval: '1m' }, enabled: true, - actions: [ - { - group: 'default', - id: createdAction.id, - connector_type_id: 'test.noop', - params: {}, - uuid: match.actions[0].uuid, - frequency: { - summary: false, - notify_when: 'onThrottleInterval', - throttle: '1m', - }, - }, - ], + actions: [], params: {}, created_by: 'elastic', + api_key_created_by_user: false, + revision: 0, scheduled_task_id: match.scheduled_task_id, created_at: match.created_at, updated_at: match.updated_at, - throttle: null, - notify_when: null, + throttle: '1m', + notify_when: 'onThrottleInterval', updated_by: 'elastic', api_key_owner: 'elastic', - api_key_created_by_user: false, mute_all: false, muted_alert_ids: [], - revision: 0, execution_status: match.execution_status, ...(match.next_run ? { next_run: match.next_run } : {}), ...(match.last_run ? { last_run: match.last_run } : {}), - monitoring: match.monitoring, snooze_schedule: match.snooze_schedule, ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), @@ -153,40 +118,15 @@ export default function createFindTests({ getService }: FtrProviderContext) { }); it('should filter out types that the user is not authorized to `get` retaining pagination', async () => { - async function createNoOpAlert(overrides = {}) { - const alert = getTestRuleData(overrides); - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(alert) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - return { - id: createdAlert.id, - rule_type_id: alert.rule_type_id, - }; - } - function createRestrictedNoOpAlert() { - return createNoOpAlert({ - rule_type_id: 'test.restricted-noop', - consumer: 'alertsRestrictedFixture', - }); - } - function createUnrestrictedNoOpAlert() { - return createNoOpAlert({ - rule_type_id: 'test.unrestricted-noop', - consumer: 'alertsFixture', - }); - } const allAlerts = []; - allAlerts.push(await createNoOpAlert()); - allAlerts.push(await createNoOpAlert()); - allAlerts.push(await createRestrictedNoOpAlert()); - allAlerts.push(await createUnrestrictedNoOpAlert()); - allAlerts.push(await createUnrestrictedNoOpAlert()); - allAlerts.push(await createRestrictedNoOpAlert()); - allAlerts.push(await createNoOpAlert()); - allAlerts.push(await createNoOpAlert()); + allAlerts.push(await createNoOpAlert(space)); + allAlerts.push(await createNoOpAlert(space)); + allAlerts.push(await createRestrictedNoOpAlert(space)); + allAlerts.push(await createUnrestrictedNoOpAlert(space)); + allAlerts.push(await createUnrestrictedNoOpAlert(space)); + allAlerts.push(await createRestrictedNoOpAlert(space)); + allAlerts.push(await createNoOpAlert(space)); + allAlerts.push(await createNoOpAlert(space)); const perPage = 4; @@ -233,25 +173,24 @@ export default function createFindTests({ getService }: FtrProviderContext) { expect(response.body.per_page).to.be.equal(perPage); expect(response.body.total).to.be.equal(8); - { - const [firstPage, secondPage] = chunk( - allAlerts.map((alert) => alert.id), - perPage - ); - expect(response.body.data.map((alert: any) => alert.id)).to.eql(firstPage); - - const secondResponse = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_find`) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - per_page: perPage, - sort_field: 'createdAt', - page: 2, - }); - - expect(secondResponse.body.data.map((alert: any) => alert.id)).to.eql(secondPage); - } + const [firstPage, secondPage] = chunk( + allAlerts.map((alert) => alert.id), + perPage + ); + expect(response.body.data.map((alert: any) => alert.id)).to.eql(firstPage); + + const secondResponse = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_find`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send({ + per_page: perPage, + sort_field: 'createdAt', + page: '2', + }); + + expect(secondResponse.statusCode).to.eql(200); + expect(secondResponse.body.data.map((alert: any) => alert.id)).to.eql(secondPage); break; default: @@ -294,7 +233,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'foo') .auth(user.username, user.password) .send({ - filter: 'alert.attributes.actions:{ actionTypeId: test.noop }', + filter: 'alert.attributes.actions:{ actionTypeId: "test.noop" }', }); switch (scenario.id) { @@ -334,13 +273,14 @@ export default function createFindTests({ getService }: FtrProviderContext) { group: 'default', connector_type_id: 'test.noop', params: {}, - uuid: createdAlert.actions[0].uuid, + uuid: match.actions[0].uuid, }, ], params: {}, created_by: 'elastic', - throttle: '1m', api_key_created_by_user: null, + revision: 0, + throttle: '1m', updated_by: 'elastic', api_key_owner: null, mute_all: false, @@ -349,7 +289,6 @@ export default function createFindTests({ getService }: FtrProviderContext) { created_at: match.created_at, updated_at: match.updated_at, execution_status: match.execution_status, - revision: 0, ...(match.next_run ? { next_run: match.next_run } : {}), ...(match.last_run ? { last_run: match.last_run } : {}), monitoring: match.monitoring, @@ -577,73 +516,153 @@ export default function createFindTests({ getService }: FtrProviderContext) { throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); } }); + + it('should filter by rule type IDs correctly', async () => { + await createNoOpAlert(space); + await createRestrictedNoOpAlert(space); + await createUnrestrictedNoOpAlert(space); + + const perPage = 10; + const ruleTypeIds = ['test.restricted-noop', 'test.noop']; + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_find`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send({ + per_page: perPage, + sort_field: 'createdAt', + rule_type_ids: ruleTypeIds, + }); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + expect(response.statusCode).to.eql(403); + expect(response.body).to.eql({ + error: 'Forbidden', + message: `Unauthorized to find rules for any rule types`, + statusCode: 403, + }); + break; + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + expect(response.statusCode).to.eql(200); + expect(response.body.total).to.be.equal(1); + + expect( + response.body.data.every( + (rule: { rule_type_id: string }) => rule.rule_type_id === 'test.noop' + ) + ).to.be.eql(true); + break; + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all_with_restricted_fixture at space1': + expect(response.statusCode).to.eql(200); + expect(response.body.total).to.be.equal(2); + + expect( + response.body.data.every((rule: { rule_type_id: string }) => + ruleTypeIds.includes(rule.rule_type_id) + ) + ).to.be.eql(true); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); }); } - describe('Actions', () => { - const { user, space } = SuperuserAtSpace1; + describe('filtering', () => { + it('should return the correct rules when trying to exploit RBAC through the ruleTypeIds parameter', async () => { + const { user, space } = Space1AllAtSpace1; - it('should return the actions correctly', async () => { - const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/connector`) + const { body: createdAlert1 } = await supertest + .post(`${getUrlPrefix(SuperuserAtSpace1.space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') - .send({ - name: 'MY action', - connector_type_id: 'test.noop', - config: {}, - secrets: {}, - }) + .send( + getTestRuleData({ + rule_type_id: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }) + ) + .auth(SuperuserAtSpace1.user.username, SuperuserAtSpace1.user.password) .expect(200); - const { body: createdRule1 } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + const { body: createdAlert2 } = await supertest + .post(`${getUrlPrefix(SuperuserAtSpace1.space.id)}/api/alerting/rule`) .set('kbn-xsrf', 'foo') .send( getTestRuleData({ - enabled: true, - actions: [ - { - id: createdAction.id, - group: 'default', - params: {}, - }, - { - id: 'system-connector-test.system-action', - params: {}, - }, - ], + rule_type_id: 'test.noop', + consumer: 'alertsFixture', }) ) + .auth(SuperuserAtSpace1.user.username, SuperuserAtSpace1.user.password) .expect(200); - objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); + objectRemover.add(SuperuserAtSpace1.space.id, createdAlert1.id, 'rule', 'alerting'); + objectRemover.add(SuperuserAtSpace1.space.id, createdAlert2.id, 'rule', 'alerting'); const response = await supertestWithoutAuth - .get(`${getUrlPrefix(space.id)}/api/alerting/rules/_find`) + .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_find`) .set('kbn-xsrf', 'foo') - .auth(user.username, user.password); + .auth(user.username, user.password) + .send({ + rule_type_ids: ['test.noop', 'test.restricted-noop'], + }); - const action = response.body.data[0].actions[0]; - const systemAction = response.body.data[0].actions[1]; - const { uuid, ...restAction } = action; - const { uuid: systemActionUuid, ...restSystemAction } = systemAction; + expect(response.status).to.eql(200); + expect(response.body.total).to.equal(1); + expect(response.body.data[0].rule_type_id).to.eql('test.noop'); + }); - expect([restAction, restSystemAction]).to.eql([ - { - id: createdAction.id, - connector_type_id: 'test.noop', - group: 'default', - params: {}, - }, - { - id: 'system-connector-test.system-action', - connector_type_id: 'test.system-action', - params: {}, - }, - , - ]); + it('should return the correct rules when trying to exploit RBAC through the consumers parameter', async () => { + const { user, space } = Space1AllAtSpace1; + + const { body: createdAlert1 } = await supertest + .post(`${getUrlPrefix(SuperuserAtSpace1.space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }) + ) + .auth(SuperuserAtSpace1.user.username, SuperuserAtSpace1.user.password) + .expect(200); + + const { body: createdAlert2 } = await supertest + .post(`${getUrlPrefix(SuperuserAtSpace1.space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send( + getTestRuleData({ + rule_type_id: 'test.noop', + consumer: 'alertsFixture', + }) + ) + .auth(SuperuserAtSpace1.user.username, SuperuserAtSpace1.user.password) + .expect(200); + + objectRemover.add(SuperuserAtSpace1.space.id, createdAlert1.id, 'rule', 'alerting'); + objectRemover.add(SuperuserAtSpace1.space.id, createdAlert2.id, 'rule', 'alerting'); + + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_find`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send({ + consumers: ['alertsFixture', 'alertsRestrictedFixture'], + }); + + expect(response.status).to.eql(200); + expect(response.body.total).to.equal(1); + expect(response.body.data[0].consumer).to.eql('alertsFixture'); }); }); + describe('stack alerts', () => { const ruleTypes = [ [ @@ -758,5 +777,35 @@ export default function createFindTests({ getService }: FtrProviderContext) { }); } }); + + async function createNoOpAlert(space: Space, overrides = {}) { + const alert = getTestRuleData(overrides); + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(alert) + .expect(200); + + objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); + + return { + id: createdAlert.id, + rule_type_id: alert.rule_type_id, + }; + } + + function createRestrictedNoOpAlert(space: Space) { + return createNoOpAlert(space, { + rule_type_id: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }); + } + + function createUnrestrictedNoOpAlert(space: Space) { + return createNoOpAlert(space, { + rule_type_id: 'test.unrestricted-noop', + consumer: 'alertsFixture', + }); + } }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts deleted file mode 100644 index c8afff8fcc47..000000000000 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/find_with_post.ts +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { Agent as SuperTestAgent } from 'supertest'; -import { chunk, omit } from 'lodash'; -import { v4 as uuidv4 } from 'uuid'; -import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services'; -import { UserAtSpaceScenarios } from '../../../scenarios'; -import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib'; -import { FtrProviderContext } from '../../../../common/ftr_provider_context'; - -const findTestUtils = ( - describeType: 'internal' | 'public', - objectRemover: ObjectRemover, - supertest: SuperTestAgent, - supertestWithoutAuth: SupertestWithoutAuthProviderType -) => { - describe(describeType, () => { - afterEach(async () => { - await objectRemover.removeAll(); - }); - - for (const scenario of UserAtSpaceScenarios) { - const { user, space } = scenario; - describe(scenario.id, () => { - it('should handle find alert request appropriately', async () => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(getTestRuleData()) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - - const response = await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/${ - describeType === 'public' ? 'api' : 'internal' - }/alerting/rules/_find` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - search: 'test.noop', - search_fields: 'alertTypeId', - }); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: `Unauthorized to find rules for any rule types`, - statusCode: 403, - }); - break; - case 'global_read at space1': - case 'superuser at space1': - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - case 'space_1_all_with_restricted_fixture at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.page).to.equal(1); - expect(response.body.per_page).to.be.greaterThan(0); - expect(response.body.total).to.be.greaterThan(0); - const match = response.body.data.find((obj: any) => obj.id === createdAlert.id); - const activeSnoozes = match.active_snoozes; - const hasActiveSnoozes = !!(activeSnoozes || []).filter((obj: any) => obj).length; - expect(match).to.eql({ - id: createdAlert.id, - name: 'abc', - tags: ['foo'], - rule_type_id: 'test.noop', - running: match.running ?? false, - consumer: 'alertsFixture', - schedule: { interval: '1m' }, - enabled: true, - actions: [], - params: {}, - created_by: 'elastic', - api_key_created_by_user: false, - revision: 0, - scheduled_task_id: match.scheduled_task_id, - created_at: match.created_at, - updated_at: match.updated_at, - throttle: '1m', - notify_when: 'onThrottleInterval', - updated_by: 'elastic', - api_key_owner: 'elastic', - mute_all: false, - muted_alert_ids: [], - execution_status: match.execution_status, - ...(match.next_run ? { next_run: match.next_run } : {}), - ...(match.last_run ? { last_run: match.last_run } : {}), - ...(describeType === 'internal' - ? { - monitoring: match.monitoring, - snooze_schedule: match.snooze_schedule, - ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), - is_snoozed_until: null, - } - : {}), - }); - expect(Date.parse(match.created_at)).to.be.greaterThan(0); - expect(Date.parse(match.updated_at)).to.be.greaterThan(0); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - - it('should filter out types that the user is not authorized to `get` retaining pagination', async () => { - async function createNoOpAlert(overrides = {}) { - const alert = getTestRuleData(overrides); - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(alert) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - return { - id: createdAlert.id, - rule_type_id: alert.rule_type_id, - }; - } - function createRestrictedNoOpAlert() { - return createNoOpAlert({ - rule_type_id: 'test.restricted-noop', - consumer: 'alertsRestrictedFixture', - }); - } - function createUnrestrictedNoOpAlert() { - return createNoOpAlert({ - rule_type_id: 'test.unrestricted-noop', - consumer: 'alertsFixture', - }); - } - const allAlerts = []; - allAlerts.push(await createNoOpAlert()); - allAlerts.push(await createNoOpAlert()); - allAlerts.push(await createRestrictedNoOpAlert()); - allAlerts.push(await createUnrestrictedNoOpAlert()); - allAlerts.push(await createUnrestrictedNoOpAlert()); - allAlerts.push(await createRestrictedNoOpAlert()); - allAlerts.push(await createNoOpAlert()); - allAlerts.push(await createNoOpAlert()); - - const perPage = 4; - - const response = await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/${ - describeType === 'public' ? 'api' : 'internal' - }/alerting/rules/_find` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - per_page: perPage, - sort_field: 'createdAt', - }); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: `Unauthorized to find rules for any rule types`, - statusCode: 403, - }); - break; - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.page).to.equal(1); - expect(response.body.per_page).to.be.equal(perPage); - expect(response.body.total).to.be.equal(6); - { - const [firstPage] = chunk( - allAlerts - .filter((alert) => alert.rule_type_id !== 'test.restricted-noop') - .map((alert) => alert.id), - perPage - ); - expect(response.body.data.map((alert: any) => alert.id)).to.eql(firstPage); - } - break; - case 'global_read at space1': - case 'superuser at space1': - case 'space_1_all_with_restricted_fixture at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.page).to.equal(1); - expect(response.body.per_page).to.be.equal(perPage); - expect(response.body.total).to.be.equal(8); - - { - const [firstPage, secondPage] = chunk( - allAlerts.map((alert) => alert.id), - perPage - ); - expect(response.body.data.map((alert: any) => alert.id)).to.eql(firstPage); - - const secondResponse = await supertestWithoutAuth - .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_find`) - .set('kbn-xsrf', 'kibana') - .auth(user.username, user.password) - .send({ - per_page: perPage, - sort_field: 'createdAt', - page: 2, - }); - - expect(secondResponse.body.data.map((alert: any) => alert.id)).to.eql(secondPage); - } - - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - - it('should handle find alert request with filter appropriately', async () => { - const { body: createdAction } = await supertest - .post(`${getUrlPrefix(space.id)}/api/actions/connector`) - .set('kbn-xsrf', 'foo') - .send({ - name: 'My action', - connector_type_id: 'test.noop', - config: {}, - secrets: {}, - }) - .expect(200); - - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - enabled: false, - actions: [ - { - id: createdAction.id, - group: 'default', - params: {}, - }, - ], - }) - ) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - - const response = await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/${ - describeType === 'public' ? 'api' : 'internal' - }/alerting/rules/_find` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - filter: 'alert.attributes.actions:{ actionTypeId: "test.noop" }', - }); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: `Unauthorized to find rules for any rule types`, - statusCode: 403, - }); - break; - case 'global_read at space1': - case 'superuser at space1': - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - case 'space_1_all_with_restricted_fixture at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.page).to.equal(1); - expect(response.body.per_page).to.be.greaterThan(0); - expect(response.body.total).to.be.greaterThan(0); - const match = response.body.data.find((obj: any) => obj.id === createdAlert.id); - const activeSnoozes = match.active_snoozes; - const hasActiveSnoozes = !!(activeSnoozes || []).filter((obj: any) => obj).length; - expect(match).to.eql({ - id: createdAlert.id, - name: 'abc', - tags: ['foo'], - rule_type_id: 'test.noop', - running: match.running ?? false, - consumer: 'alertsFixture', - schedule: { interval: '1m' }, - enabled: false, - actions: [ - { - id: createdAction.id, - group: 'default', - connector_type_id: 'test.noop', - params: {}, - uuid: match.actions[0].uuid, - }, - ], - params: {}, - created_by: 'elastic', - api_key_created_by_user: null, - revision: 0, - throttle: '1m', - updated_by: 'elastic', - api_key_owner: null, - mute_all: false, - muted_alert_ids: [], - notify_when: 'onThrottleInterval', - created_at: match.created_at, - updated_at: match.updated_at, - execution_status: match.execution_status, - ...(match.next_run ? { next_run: match.next_run } : {}), - ...(match.last_run ? { last_run: match.last_run } : {}), - ...(describeType === 'internal' - ? { - monitoring: match.monitoring, - snooze_schedule: match.snooze_schedule, - ...(hasActiveSnoozes && { active_snoozes: activeSnoozes }), - is_snoozed_until: null, - } - : {}), - }); - expect(Date.parse(match.created_at)).to.be.greaterThan(0); - expect(Date.parse(match.updated_at)).to.be.greaterThan(0); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - - it('should handle find alert request with fields appropriately', async () => { - const myTag = uuidv4(); - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - enabled: false, - tags: [myTag], - rule_type_id: 'test.restricted-noop', - consumer: 'alertsRestrictedFixture', - }) - ) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - - // create another type with same tag - const { body: createdSecondAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - tags: [myTag], - rule_type_id: 'test.restricted-noop', - consumer: 'alertsRestrictedFixture', - }) - ) - .expect(200); - objectRemover.add(space.id, createdSecondAlert.id, 'rule', 'alerting'); - - const response = await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/${ - describeType === 'public' ? 'api' : 'internal' - }/alerting/rules/_find` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - filter: 'alert.attributes.alertTypeId:test.restricted-noop', - fields: ['tags'], - sort_field: 'createdAt', - }); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: `Unauthorized to find rules for any rule types`, - statusCode: 403, - }); - break; - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.data).to.eql([]); - break; - case 'global_read at space1': - case 'superuser at space1': - case 'space_1_all_with_restricted_fixture at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.page).to.equal(1); - expect(response.body.per_page).to.be.greaterThan(0); - expect(response.body.total).to.be.greaterThan(0); - const [matchFirst, matchSecond] = response.body.data; - expect(omit(matchFirst, 'updatedAt')).to.eql({ - id: createdAlert.id, - actions: [], - tags: [myTag], - ...(describeType === 'internal' && { - snooze_schedule: [], - is_snoozed_until: null, - }), - }); - expect(omit(matchSecond, 'updatedAt')).to.eql({ - id: createdSecondAlert.id, - actions: [], - tags: [myTag], - ...(describeType === 'internal' && { - snooze_schedule: [], - is_snoozed_until: null, - }), - }); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - - it('should handle find alert request with executionStatus field appropriately', async () => { - const myTag = uuidv4(); - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - enabled: false, - tags: [myTag], - rule_type_id: 'test.restricted-noop', - consumer: 'alertsRestrictedFixture', - }) - ) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - - // create another type with same tag - const { body: createdSecondAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - tags: [myTag], - rule_type_id: 'test.restricted-noop', - consumer: 'alertsRestrictedFixture', - }) - ) - .expect(200); - objectRemover.add(space.id, createdSecondAlert.id, 'rule', 'alerting'); - - const response = await supertestWithoutAuth - .post( - `${getUrlPrefix(space.id)}/${ - describeType === 'public' ? 'api' : 'internal' - }/alerting/rules/_find` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - filter: 'alert.attributes.alertTypeId:test.restricted-noop', - fields: ['tags', 'executionStatus'], - sort_field: 'createdAt', - }); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: `Unauthorized to find rules for any rule types`, - statusCode: 403, - }); - break; - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.data).to.eql([]); - break; - case 'global_read at space1': - case 'superuser at space1': - case 'space_1_all_with_restricted_fixture at space1': - expect(response.statusCode).to.eql(200); - expect(response.body.page).to.equal(1); - expect(response.body.per_page).to.be.greaterThan(0); - expect(response.body.total).to.be.greaterThan(0); - const [matchFirst, matchSecond] = response.body.data; - expect(omit(matchFirst, 'updatedAt')).to.eql({ - id: createdAlert.id, - actions: [], - tags: [myTag], - execution_status: matchFirst.execution_status, - ...(describeType === 'internal' && { - snooze_schedule: [], - is_snoozed_until: null, - }), - }); - expect(omit(matchSecond, 'updatedAt')).to.eql({ - id: createdSecondAlert.id, - actions: [], - tags: [myTag], - execution_status: matchSecond.execution_status, - ...(describeType === 'internal' && { - snooze_schedule: [], - is_snoozed_until: null, - }), - }); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - - it(`shouldn't find alert from another space`, async () => { - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(getTestRuleData()) - .expect(200); - objectRemover.add(space.id, createdAlert.id, 'rule', 'alerting'); - - const response = await supertestWithoutAuth - .post( - `${getUrlPrefix('other')}/${ - describeType === 'public' ? 'api' : 'internal' - }/alerting/rules/_find` - ) - .set('kbn-xsrf', 'foo') - .auth(user.username, user.password) - .send({ - search: 'test.noop', - search_fields: 'alertTypeId', - }); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - case 'space_1_all_with_restricted_fixture at space1': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: `Unauthorized to find rules for any rule types`, - statusCode: 403, - }); - break; - case 'global_read at space1': - case 'superuser at space1': - expect(response.statusCode).to.eql(200); - expect(response.body).to.eql({ - page: 1, - per_page: 10, - total: 0, - data: [], - }); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - }); - } - }); -}; - -// eslint-disable-next-line import/no-default-export -export default function createFindTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - const supertestWithoutAuth = getService('supertestWithoutAuth'); - - describe('find with post', () => { - const objectRemover = new ObjectRemover(supertest); - - afterEach(async () => { - await objectRemover.removeAll(); - }); - - findTestUtils('internal', objectRemover, supertest, supertestWithoutAuth); - }); -} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts index 78c662d98a54..c1872d1e4021 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/get.ts @@ -223,23 +223,12 @@ const getTestUtils = ( switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('get', 'test.restricted-noop', 'alerts'), - statusCode: 403, - }); - break; case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'get', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('get', 'test.restricted-noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts index 262fe8af301c..dc85feb741eb 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group1/tests/alerting/index.ts @@ -23,7 +23,6 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./backfill')); loadTestFile(require.resolve('./find')); loadTestFile(require.resolve('./find_internal')); - loadTestFile(require.resolve('./find_with_post')); loadTestFile(require.resolve('./create')); loadTestFile(require.resolve('./delete')); loadTestFile(require.resolve('./disable')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/aggregate.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/aggregate.ts new file mode 100644 index 000000000000..dde153aca402 --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/aggregate.ts @@ -0,0 +1,377 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { Space, User } from '../../../../common/types'; +import { Space1AllAtSpace1, SuperuserAtSpace1, UserAtSpaceScenarios } from '../../../scenarios'; +import { getUrlPrefix, getTestRuleData, ObjectRemover, getEventLog } from '../../../../common/lib'; +import { FtrProviderContext } from '../../../../common/ftr_provider_context'; + +// eslint-disable-next-line import/no-default-export +export default function createAggregateTests({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); + const retry = getService('retry'); + + const getEventLogWithRetry = async (id: string, space: Space) => { + await retry.try(async () => { + return await getEventLog({ + getService, + spaceId: space.id, + type: 'alert', + id, + provider: 'alerting', + actions: new Map([['execute', { equal: 1 }]]), + }); + }); + }; + + describe('aggregate', () => { + const objectRemover = new ObjectRemover(supertest); + + afterEach(async () => { + await objectRemover.removeAll(); + }); + + for (const scenario of UserAtSpaceScenarios) { + const { user, space } = scenario; + + describe(scenario.id, () => { + it('should aggregate alert status totals', async () => { + const NumOkAlerts = 4; + const NumActiveAlerts = 1; + const NumErrorAlerts = 2; + + const okAlertIds: string[] = []; + const activeAlertIds: string[] = []; + const errorAlertIds: string[] = []; + + await Promise.all( + [...Array(NumOkAlerts)].map(async () => { + const okAlertId = await createTestAlert( + { + /** + * The _aggregate calls is made + * to get all stats across all rule types + * that the user has access to. Only a subset + * of users have access to the test.restricted-noop/alertsRestrictedFixture + * pair. The differences in the stats ensure that even though we request + * the stats for all rule types only for the ones that the user has access to + * are returned. + * */ + rule_type_id: 'test.restricted-noop', + schedule: { interval: '24h' }, + consumer: 'alertsRestrictedFixture', + }, + space, + user + ); + + okAlertIds.push(okAlertId); + + objectRemover.add(space.id, okAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(okAlertIds.map((id) => getEventLogWithRetry(id, space))); + + await Promise.all( + [...Array(NumActiveAlerts)].map(async () => { + const activeAlertId = await createTestAlert( + { + rule_type_id: 'test.patternFiring', + schedule: { interval: '24h' }, + params: { + pattern: { instance: new Array(100).fill(true) }, + }, + }, + space, + user + ); + + activeAlertIds.push(activeAlertId); + objectRemover.add(space.id, activeAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(activeAlertIds.map((id) => getEventLogWithRetry(id, space))); + + await Promise.all( + [...Array(NumErrorAlerts)].map(async () => { + const errorAlertId = await createTestAlert( + { + rule_type_id: 'test.throw', + schedule: { interval: '24h' }, + }, + space, + user + ); + + errorAlertIds.push(errorAlertId); + objectRemover.add(space.id, errorAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(errorAlertIds.map((id) => getEventLogWithRetry(id, space))); + + switch (scenario.id) { + case 'no_kibana_privileges at space1': + case 'space_1_all at space2': + await aggregate({ + space, + user, + expectedStatusCode: 403, + expectedResponse: { + error: 'Forbidden', + message: 'Unauthorized to find rules for any rule types', + statusCode: 403, + }, + }); + break; + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': + await aggregate({ + space, + user, + expectedStatusCode: 200, + expectedResponse: { + rule_enabled_status: { + disabled: 0, + enabled: 3, + }, + rule_execution_status: { + ok: 0, + active: NumActiveAlerts, + error: NumErrorAlerts, + pending: 0, + unknown: 0, + warning: 0, + }, + rule_last_run_outcome: { + succeeded: 1, + warning: 0, + failed: 2, + }, + rule_muted_status: { + muted: 0, + unmuted: 3, + }, + rule_snoozed_status: { + snoozed: 0, + }, + rule_tags: ['foo'], + }, + }); + break; + case 'global_read at space1': + case 'superuser at space1': + case 'space_1_all_with_restricted_fixture at space1': + await aggregate({ + space, + user, + expectedStatusCode: 200, + expectedResponse: { + rule_enabled_status: { + disabled: 0, + enabled: 7, + }, + rule_execution_status: { + ok: NumOkAlerts, + active: NumActiveAlerts, + error: NumErrorAlerts, + pending: 0, + unknown: 0, + warning: 0, + }, + rule_last_run_outcome: { + succeeded: 5, + warning: 0, + failed: 2, + }, + rule_muted_status: { + muted: 0, + unmuted: 7, + }, + rule_snoozed_status: { + snoozed: 0, + }, + rule_tags: ['foo'], + }, + }); + break; + default: + throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); + } + }); + }); + } + + describe('filtering', () => { + it('should return the correct rule stats when trying to exploit RBAC through the ruleTypeIds parameter', async () => { + const { user, space } = Space1AllAtSpace1; + + const okAlertId = await createTestAlert( + { + rule_type_id: 'test.restricted-noop', + schedule: { interval: '24h' }, + consumer: 'alertsRestrictedFixture', + }, + SuperuserAtSpace1.space, + SuperuserAtSpace1.user + ); + + const activeAlertId = await createTestAlert( + { + rule_type_id: 'test.patternFiring', + schedule: { interval: '24h' }, + params: { + pattern: { instance: new Array(100).fill(true) }, + }, + }, + SuperuserAtSpace1.space, + SuperuserAtSpace1.user + ); + + objectRemover.add(SuperuserAtSpace1.space.id, okAlertId, 'rule', 'alerting'); + objectRemover.add(SuperuserAtSpace1.space.id, activeAlertId, 'rule', 'alerting'); + + await aggregate({ + space, + user, + params: { rule_type_ids: ['test.restricted-noop', 'test.patternFiring'] }, + expectedStatusCode: 200, + expectedResponse: { + rule_enabled_status: { + disabled: 0, + enabled: 1, + }, + rule_execution_status: { + ok: 0, + active: 1, + error: 0, + pending: 0, + unknown: 0, + warning: 0, + }, + rule_last_run_outcome: { + succeeded: 1, + warning: 0, + failed: 0, + }, + rule_muted_status: { + muted: 0, + unmuted: 1, + }, + rule_snoozed_status: { + snoozed: 0, + }, + rule_tags: ['foo'], + }, + }); + }); + + it('should return the correct rule stats when trying to exploit RBAC through the consumer parameter', async () => { + const { user, space } = Space1AllAtSpace1; + + const okAlertId = await createTestAlert( + { + rule_type_id: 'test.restricted-noop', + schedule: { interval: '24h' }, + consumer: 'alertsRestrictedFixture', + }, + SuperuserAtSpace1.space, + SuperuserAtSpace1.user + ); + + const activeAlertId = await createTestAlert( + { + rule_type_id: 'test.patternFiring', + schedule: { interval: '24h' }, + params: { + pattern: { instance: new Array(100).fill(true) }, + }, + }, + SuperuserAtSpace1.space, + SuperuserAtSpace1.user + ); + + objectRemover.add(SuperuserAtSpace1.space.id, okAlertId, 'rule', 'alerting'); + objectRemover.add(SuperuserAtSpace1.space.id, activeAlertId, 'rule', 'alerting'); + + await aggregate({ + space, + user, + params: { consumers: ['alertsRestrictedFixture', 'alertsFixture'] }, + expectedStatusCode: 200, + expectedResponse: { + rule_enabled_status: { + disabled: 0, + enabled: 1, + }, + rule_execution_status: { + ok: 0, + active: 1, + error: 0, + pending: 0, + unknown: 0, + warning: 0, + }, + rule_last_run_outcome: { + succeeded: 1, + warning: 0, + failed: 0, + }, + rule_muted_status: { + muted: 0, + unmuted: 1, + }, + rule_snoozed_status: { + snoozed: 0, + }, + rule_tags: ['foo'], + }, + }); + }); + }); + }); + + async function createTestAlert(testAlertOverrides = {}, space: Space, user: User) { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData(testAlertOverrides)) + .auth(user.username, user.password) + .expect(200); + + return createdAlert.id; + } + + const aggregate = async ({ + space, + user, + expectedStatusCode, + expectedResponse, + params = {}, + }: { + space: Space; + user: User; + expectedStatusCode: number; + expectedResponse: Record; + params?: Record; + }) => { + await retry.try(async () => { + const response = await supertestWithoutAuth + .post(`${getUrlPrefix(space.id)}/internal/alerting/rules/_aggregate`) + .set('kbn-xsrf', 'foo') + .auth(user.username, user.password) + .send(params); + + expect(response.status).to.eql(expectedStatusCode); + expect(response.body).to.eql(expectedResponse); + }); + }; +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts index a6f090030a6d..ea834cbdb502 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/index.ts @@ -19,6 +19,7 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC await tearDown(getService); }); + loadTestFile(require.resolve('./aggregate')); loadTestFile(require.resolve('./mute_all')); loadTestFile(require.resolve('./mute_instance')); loadTestFile(require.resolve('./unmute_all')); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_all.ts index c5be0877c89f..a9b6bf42e55a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_all.ts @@ -252,11 +252,7 @@ export default function createMuteAlertTests({ getService }: FtrProviderContext) expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'muteAll', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('muteAll', 'test.restricted-noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_instance.ts index b7cdf762836f..1e3d99f5dd6a 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/mute_instance.ts @@ -239,24 +239,13 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('muteAlert', 'test.restricted-noop', 'alerts'), - statusCode: 403, - }); - break; case 'global_read at space1': case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'muteAlert', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('muteAlert', 'test.restricted-noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_all.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_all.ts index d038108d29f6..6c7f56b75eec 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_all.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_all.ts @@ -259,6 +259,9 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': + case 'global_read at space1': + case 'space_1_all at space1': + case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', @@ -266,9 +269,6 @@ export default function createUnmuteAlertTests({ getService }: FtrProviderContex statusCode: 403, }); break; - case 'global_read at space1': - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_instance.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_instance.ts index 97add81c6d5b..a569b834fb82 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_instance.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/unmute_instance.ts @@ -259,17 +259,6 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'unmuteAlert', - 'test.restricted-noop', - 'alerts' - ), - statusCode: 403, - }); - break; case 'global_read at space1': case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': @@ -279,7 +268,7 @@ export default function createMuteAlertInstanceTests({ getService }: FtrProvider message: getUnauthorizedErrorMessage( 'unmuteAlert', 'test.restricted-noop', - 'alertsRestrictedFixture' + 'alerts' ), statusCode: 403, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts index 198baf12e751..14f089b40759 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update.ts @@ -409,24 +409,13 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('update', 'test.restricted-noop', 'alerts'), - statusCode: 403, - }); - break; case 'global_read at space1': case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'update', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('update', 'test.restricted-noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts index 3df057065014..b92e423cd682 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group2/tests/alerting/update_api_key.ts @@ -238,17 +238,6 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'updateApiKey', - 'test.restricted-noop', - 'alerts' - ), - statusCode: 403, - }); - break; case 'global_read at space1': case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': @@ -258,7 +247,7 @@ export default function createUpdateApiKeyTests({ getService }: FtrProviderConte message: getUnauthorizedErrorMessage( 'updateApiKey', 'test.restricted-noop', - 'alertsRestrictedFixture' + 'alerts' ), statusCode: 403, }); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts index fc3526eebc6a..acc0321adfa5 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_delete.ts @@ -249,71 +249,6 @@ export default ({ getService }: FtrProviderContext) => { } }); - it('should handle delete alert request appropriately when consumer is not the producer', async () => { - const { body: createdRule1 } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - rule_type_id: 'test.restricted-noop', - consumer: 'alertsFixture', - }) - ) - .expect(200); - - const response = await supertestWithoutAuth - .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_delete`) - .set('kbn-xsrf', 'foo') - .send({ ids: [createdRule1.id] }) - .auth(user.username, user.password); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.body).to.eql({ - error: 'Forbidden', - message: 'Unauthorized to find rules for any rule types', - statusCode: 403, - }); - expect(response.statusCode).to.eql(403); - objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); - // Ensure task still exists - await getScheduledTask(createdRule1.scheduled_task_id); - break; - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - case 'space_1_all_with_restricted_fixture at space1': - case 'global_read at space1': - expect(response.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: 'No rules found for bulk delete', - }); - expect(response.statusCode).to.eql(400); - objectRemover.add(space.id, createdRule1.id, 'rule', 'alerting'); - // Ensure task still exists - await getScheduledTask(createdRule1.scheduled_task_id); - break; - case 'superuser at space1': - expect(response.body).to.eql({ - rules: [{ ...getDefaultRules(response), rule_type_id: 'test.restricted-noop' }], - errors: [], - total: 1, - taskIdsFailedToBeDeleted: [], - }); - expect(response.statusCode).to.eql(200); - try { - await getScheduledTask(createdRule1.scheduled_task_id); - throw new Error('Should have removed scheduled task'); - } catch (e) { - expect(e.meta.statusCode).to.eql(404); - } - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - it('should handle delete alert request appropriately when consumer is "alerts"', async () => { const { body: createdRule1 } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) @@ -348,7 +283,7 @@ export default ({ getService }: FtrProviderContext) => { case 'global_read at space1': expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('bulkDelete', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('bulkDelete', 'test.noop', 'alerts'), statusCode: 403, }); expect(response.statusCode).to.eql(403); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts index b8c2041cb27a..7bd3e42edeb7 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_disable.ts @@ -278,7 +278,7 @@ export default ({ getService }: FtrProviderContext) => { case 'global_read at space1': expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('bulkDisable', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('bulkDisable', 'test.noop', 'alerts'), statusCode: 403, }); expect(response.statusCode).to.eql(403); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts index 1082a6741ec0..c0835b91e209 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_edit.ts @@ -388,11 +388,7 @@ export default function createUpdateTests({ getService }: FtrProviderContext) { case 'global_read at space1': expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'bulkEdit', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('bulkEdit', 'test.restricted-noop', 'alerts'), statusCode: 403, }); expect(response.statusCode).to.eql(403); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts index e7cd7044717c..c829e130f246 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group3/tests/alerting/bulk_enable.ts @@ -228,54 +228,6 @@ export default ({ getService }: FtrProviderContext) => { } }); - it('should handle enable alert request appropriately when consumer is not the producer', async () => { - const { body: createdRule } = await supertest - .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send( - getTestRuleData({ - rule_type_id: 'test.restricted-noop', - consumer: 'alertsFixture', - }) - ) - .expect(200); - objectRemover.add(space.id, createdRule.id, 'rule', 'alerting'); - - const response = await supertestWithoutAuth - .patch(`${getUrlPrefix(space.id)}/internal/alerting/rules/_bulk_enable`) - .set('kbn-xsrf', 'foo') - .send({ ids: [createdRule.id] }) - .auth(user.username, user.password); - - switch (scenario.id) { - case 'no_kibana_privileges at space1': - case 'space_1_all at space2': - expect(response.body).to.eql({ - error: 'Forbidden', - message: 'Unauthorized to find rules for any rule types', - statusCode: 403, - }); - expect(response.statusCode).to.eql(403); - break; - case 'space_1_all at space1': - case 'space_1_all_alerts_none_actions at space1': - case 'space_1_all_with_restricted_fixture at space1': - case 'global_read at space1': - expect(response.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: 'No rules found for bulk enable', - }); - expect(response.statusCode).to.eql(400); - break; - case 'superuser at space1': - expect(response.statusCode).to.eql(200); - break; - default: - throw new Error(`Scenario untested: ${JSON.stringify(scenario)}`); - } - }); - it('should handle enable alert request appropriately when consumer is "alerts"', async () => { const { body: createdRule } = await supertest .post(`${getUrlPrefix(space.id)}/api/alerting/rule`) @@ -308,7 +260,7 @@ export default ({ getService }: FtrProviderContext) => { case 'global_read at space1': expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage('bulkEnable', 'test.noop', 'alertsFixture'), + message: getUnauthorizedErrorMessage('bulkEnable', 'test.noop', 'alerts'), statusCode: 403, }); expect(response.statusCode).to.eql(403); diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/snooze.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/snooze.ts index 8c1fed7978b5..c880b18dd4b4 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/snooze.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/snooze.ts @@ -269,24 +269,13 @@ export default function createSnoozeRuleTests({ getService }: FtrProviderContext switch (scenario.id) { case 'no_kibana_privileges at space1': case 'space_1_all at space2': - expect(response.statusCode).to.eql(403); - expect(response.body).to.eql({ - error: 'Forbidden', - message: getUnauthorizedErrorMessage('snooze', 'test.restricted-noop', 'alerts'), - statusCode: 403, - }); - break; case 'global_read at space1': case 'space_1_all at space1': case 'space_1_all_alerts_none_actions at space1': expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'snooze', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('snooze', 'test.restricted-noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/unsnooze.ts b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/unsnooze.ts index eae8814a514f..8f509e6104c3 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/unsnooze.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/group4/tests/alerting/unsnooze.ts @@ -254,11 +254,7 @@ export default function createUnsnoozeRuleTests({ getService }: FtrProviderConte expect(response.statusCode).to.eql(403); expect(response.body).to.eql({ error: 'Forbidden', - message: getUnauthorizedErrorMessage( - 'unsnooze', - 'test.restricted-noop', - 'alertsRestrictedFixture' - ), + message: getUnauthorizedErrorMessage('unsnooze', 'test.restricted-noop', 'alerts'), statusCode: 403, }); break; diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts b/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts index fdb56a4fb501..bf6b38b6befb 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/scenarios.ts @@ -282,6 +282,10 @@ const GlobalReadAtSpace1: GlobalReadAtSpace1 = { space: Space1, }; +interface Space1AllAtSpace1 extends Scenario { + id: 'space_1_all at space1'; +} + interface Space1AllWithRestrictedFixtureAtSpace1 extends Scenario { id: 'space_1_all_with_restricted_fixture at space1'; } @@ -322,7 +326,8 @@ export const systemActionScenario: SystemActionSpace1 = { interface Space1AllAtSpace1 extends Scenario { id: 'space_1_all at space1'; } -const Space1AllAtSpace1: Space1AllAtSpace1 = { + +export const Space1AllAtSpace1: Space1AllAtSpace1 = { id: 'space_1_all at space1', user: Space1All, space: Space1, diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/aggregate_post.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/aggregate.ts similarity index 51% rename from x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/aggregate_post.ts rename to x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/aggregate.ts index 6269e9bff6e2..c1553d1ef8d9 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/aggregate_post.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/aggregate.ts @@ -28,10 +28,12 @@ export default function createAggregateTests({ getService }: FtrProviderContext) }); }; - describe('aggregate post', () => { + describe('aggregate', () => { const objectRemover = new ObjectRemover(supertest); - afterEach(() => objectRemover.removeAll()); + afterEach(async () => { + await objectRemover.removeAll(); + }); it('should aggregate when there are no alerts', async () => { const response = await supertest @@ -157,6 +159,171 @@ export default function createAggregateTests({ getService }: FtrProviderContext) }); }); + it('should aggregate only filtered rules by rule type IDs', async () => { + const NumOkAlerts = 4; + const NumActiveAlerts = 1; + const NumErrorAlerts = 2; + + const okAlertIds: string[] = []; + const activeAlertIds: string[] = []; + const errorAlertIds: string[] = []; + + await Promise.all( + [...Array(NumOkAlerts)].map(async () => { + const okAlertId = await createTestAlert({ + rule_type_id: 'test.noop', + schedule: { interval: '24h' }, + }); + okAlertIds.push(okAlertId); + objectRemover.add(Spaces.space1.id, okAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(okAlertIds.map((id) => getEventLogWithRetry(id))); + + await Promise.all( + [...Array(NumActiveAlerts)].map(async () => { + const activeAlertId = await createTestAlert({ + rule_type_id: 'test.patternFiring', + schedule: { interval: '24h' }, + params: { + pattern: { instance: new Array(100).fill(true) }, + }, + }); + activeAlertIds.push(activeAlertId); + objectRemover.add(Spaces.space1.id, activeAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(activeAlertIds.map((id) => getEventLogWithRetry(id))); + + await Promise.all( + [...Array(NumErrorAlerts)].map(async () => { + const errorAlertId = await createTestAlert({ + rule_type_id: 'test.throw', + schedule: { interval: '24h' }, + }); + errorAlertIds.push(errorAlertId); + objectRemover.add(Spaces.space1.id, errorAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(errorAlertIds.map((id) => getEventLogWithRetry(id))); + + await retry.try(async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_aggregate`) + .set('kbn-xsrf', 'foo') + .send({ rule_type_ids: ['test.noop'] }); + + expect(response.status).to.eql(200); + expect(response.body).to.eql({ + rule_enabled_status: { + disabled: 0, + enabled: 4, + }, + rule_execution_status: { + ok: NumOkAlerts, + active: 0, + error: 0, + pending: 0, + unknown: 0, + warning: 0, + }, + rule_last_run_outcome: { + succeeded: 4, + warning: 0, + failed: 0, + }, + rule_muted_status: { + muted: 0, + unmuted: 4, + }, + rule_snoozed_status: { + snoozed: 0, + }, + rule_tags: ['foo'], + }); + }); + }); + + it('should aggregate only filtered rules by consumer', async () => { + const NumOkAlerts = 4; + const NumActiveAlerts = 1; + const NumErrorAlerts = 2; + + const okAlertIds: string[] = []; + const activeAlertIds: string[] = []; + const errorAlertIds: string[] = []; + + await Promise.all( + [...Array(NumOkAlerts)].map(async () => { + const okAlertId = await createTestAlert({ + rule_type_id: 'test.restricted-noop', + schedule: { interval: '24h' }, + consumer: 'alertsRestrictedFixture', + }); + okAlertIds.push(okAlertId); + objectRemover.add(Spaces.space1.id, okAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(okAlertIds.map((id) => getEventLogWithRetry(id))); + + await Promise.all( + [...Array(NumActiveAlerts)].map(async () => { + const activeAlertId = await createTestAlert({ + rule_type_id: 'test.patternFiring', + schedule: { interval: '24h' }, + params: { + pattern: { instance: new Array(100).fill(true) }, + }, + }); + activeAlertIds.push(activeAlertId); + objectRemover.add(Spaces.space1.id, activeAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(activeAlertIds.map((id) => getEventLogWithRetry(id))); + + await Promise.all( + [...Array(NumErrorAlerts)].map(async () => { + const errorAlertId = await createTestAlert({ + rule_type_id: 'test.throw', + schedule: { interval: '24h' }, + }); + errorAlertIds.push(errorAlertId); + objectRemover.add(Spaces.space1.id, errorAlertId, 'rule', 'alerting'); + }) + ); + + await Promise.all(errorAlertIds.map((id) => getEventLogWithRetry(id))); + + await retry.try(async () => { + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_aggregate`) + .set('kbn-xsrf', 'foo') + .send({ consumers: ['alertsFixture'] }); + + expect(response.status).to.eql(200); + expect(response.body).to.eql({ + rule_execution_status: { + error: NumErrorAlerts, + active: NumActiveAlerts, + ok: 0, + pending: 0, + unknown: 0, + warning: 0, + }, + rule_last_run_outcome: { failed: 2, succeeded: 1, warning: 0 }, + rule_enabled_status: { enabled: 3, disabled: 0 }, + rule_muted_status: { muted: 0, unmuted: 3 }, + rule_snoozed_status: { snoozed: 0 }, + rule_tags: ['foo'], + }); + }); + }); + describe('tags limit', () => { it('should be 50 be default', async () => { const numOfAlerts = 3; diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts index e730dd657d2f..f6b48df9b9f1 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find.ts @@ -33,10 +33,13 @@ export default function createFindTests({ getService }: FtrProviderContext) { describe('find public API', () => { const objectRemover = new ObjectRemover(supertest); - afterEach(() => objectRemover.removeAll()); + afterEach(async () => { + await objectRemover.removeAll(); + }); describe('handle find alert request', function () { this.tags('skipFIPS'); + it('should handle find alert request appropriately', async () => { const { body: createdAction } = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) @@ -290,6 +293,48 @@ export default function createFindTests({ getService }: FtrProviderContext) { 'Error find rules: Filter is not supported on this field alert.attributes.mapped_params.risk_score' ); }); + + it('should throw when using rule_type_ids', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()) + .expect(200); + + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rules/_find?rule_type_ids=foo` + ); + + expect(response.statusCode).to.eql(400); + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: '[request query.rule_type_ids]: definition for this key is missing', + }); + }); + + it('should throw when using consumers', async () => { + const { body: createdAlert } = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestRuleData()) + .expect(200); + + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); + + const response = await supertest.get( + `${getUrlPrefix(Spaces.space1.id)}/api/alerting/rules/_find?consumers=foo` + ); + + expect(response.statusCode).to.eql(400); + expect(response.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: '[request query.consumers]: definition for this key is missing', + }); + }); }); describe('legacy', function () { diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find_internal.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find_internal.ts index 25fc54a5229d..7c10b9be598b 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find_internal.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/find_internal.ts @@ -22,6 +22,7 @@ async function createAlert( .set('kbn-xsrf', 'foo') .send(getTestRuleData(overwrites)) .expect(200); + objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); return createdAlert; } @@ -33,10 +34,13 @@ export default function createFindTests({ getService }: FtrProviderContext) { describe('find internal API', () => { const objectRemover = new ObjectRemover(supertest); - afterEach(() => objectRemover.removeAll()); + afterEach(async () => { + await objectRemover.removeAll(); + }); describe('handle find alert request', function () { this.tags('skipFIPS'); + it('should handle find alert request appropriately', async () => { const { body: createdAction } = await supertest .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) @@ -276,7 +280,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { it('should filter on parameters', async () => { const response = await supertest - .get(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_find`) + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_find`) .set('kbn-xsrf', 'foo') .send({ filter: 'alert.attributes.params.risk_score:40', @@ -286,17 +290,52 @@ export default function createFindTests({ getService }: FtrProviderContext) { expect(response.body.total).to.equal(1); expect(response.body.data[0].params.risk_score).to.eql(40); }); + }); - it('should error if filtering on mapped parameters directly using the public API', async () => { - const response = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_find`) - .set('kbn-xsrf', 'foo') - .send({ - filter: 'alert.attributes.mapped_params.risk_score:40', - }); + it('should filter rules by rule type IDs', async () => { + await createAlert(objectRemover, supertest, { + rule_type_id: 'test.noop', + consumer: 'alertsFixture', + }); - expect(response.status).to.eql(200); + await createAlert(objectRemover, supertest, { + rule_type_id: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', }); + + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_find`) + .set('kbn-xsrf', 'foo') + .send({ + rule_type_ids: ['test.restricted-noop'], + }); + + expect(response.status).to.eql(200); + expect(response.body.total).to.equal(1); + expect(response.body.data[0].rule_type_id).to.eql('test.restricted-noop'); + }); + + it('should filter rules by consumers', async () => { + await createAlert(objectRemover, supertest, { + rule_type_id: 'test.noop', + consumer: 'alertsFixture', + }); + + await createAlert(objectRemover, supertest, { + rule_type_id: 'test.restricted-noop', + consumer: 'alertsRestrictedFixture', + }); + + const response = await supertest + .post(`${getUrlPrefix(Spaces.space1.id)}/internal/alerting/rules/_find`) + .set('kbn-xsrf', 'foo') + .send({ + consumers: ['alertsRestrictedFixture'], + }); + + expect(response.status).to.eql(200); + expect(response.body.total).to.equal(1); + expect(response.body.data[0].consumer).to.eql('alertsRestrictedFixture'); }); describe('legacy', function () { @@ -309,11 +348,7 @@ export default function createFindTests({ getService }: FtrProviderContext) { .expect(200); objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); - const response = await supertest.get( - `${getUrlPrefix( - Spaces.space1.id - )}/api/alerts/_find?search=test.noop&search_fields=alertTypeId` - ); + const response = await supertest.get(`${getUrlPrefix(Spaces.space1.id)}/api/alerts/_find`); expect(response.status).to.eql(200); expect(response.body.page).to.equal(1); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/index.ts index 7a0c24878d07..d750fd7bcfb4 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group1/index.ts @@ -14,12 +14,13 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC before(async () => await buildUp(getService)); after(async () => await tearDown(getService)); - loadTestFile(require.resolve('./aggregate_post')); + loadTestFile(require.resolve('./aggregate')); loadTestFile(require.resolve('./create')); loadTestFile(require.resolve('./delete')); loadTestFile(require.resolve('./disable')); loadTestFile(require.resolve('./enable')); loadTestFile(require.resolve('./find')); + loadTestFile(require.resolve('./find_internal')); loadTestFile(require.resolve('./get')); loadTestFile(require.resolve('./get_alert_state')); loadTestFile(require.resolve('./get_alert_summary')); diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/ephemeral.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/ephemeral.ts deleted file mode 100644 index 51149a3008ff..000000000000 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/ephemeral.ts +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { flatten } from 'lodash'; -import { IValidatedEvent } from '@kbn/event-log-plugin/server'; -import { DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT } from '@kbn/alerting-plugin/server/config'; -import { ESTestIndexTool, ES_TEST_INDEX_NAME } from '@kbn/alerting-api-integration-helpers'; -import { Spaces } from '../../../scenarios'; -import { getUrlPrefix, ObjectRemover, getTestRuleData, getEventLog } from '../../../../common/lib'; -import { FtrProviderContext } from '../../../../common/ftr_provider_context'; - -// eslint-disable-next-line import/no-default-export -export default function createNotifyWhenTests({ getService }: FtrProviderContext) { - const supertest = getService('supertest'); - const retry = getService('retry'); - const es = getService('es'); - - const esTestIndexTool = new ESTestIndexTool(es, retry); - - describe('ephemeral', () => { - const objectRemover = new ObjectRemover(supertest); - - beforeEach(async () => { - await esTestIndexTool.destroy(); - await esTestIndexTool.setup(); - }); - afterEach(async () => await esTestIndexTool.destroy()); - after(async () => { - await objectRemover.removeAll(); - }); - - it('should execute all requests, when some will be ephemeral and some not', async () => { - const nonEphemeralTasks = 3; - const actionPromises = []; - for (let i = 0; i < DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT + nonEphemeralTasks; i++) { - actionPromises.push( - supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector`) - .set('kbn-xsrf', 'foo') - .send({ - name: `My action${i}`, - connector_type_id: 'test.index-record', - config: { - unencrypted: `This value shouldn't get encrypted`, - }, - secrets: { - encrypted: 'This value should be encrypted', - }, - }) - .expect(200) - ); - } - const createdActions = await Promise.all(actionPromises); - createdActions.forEach((createdAction) => - objectRemover.add(Spaces.space1.id, createdAction.body.id, 'connector', 'actions') - ); - - const pattern = { - instance: [true, true, true, false, true, true], - }; - const alertData = getTestRuleData({ - rule_type_id: 'test.patternFiring', - params: { pattern }, - schedule: { interval: '1m' }, - throttle: null, - notify_when: 'onActiveAlert', - actions: createdActions.map((createdAction) => { - return { - id: createdAction.body.id, - group: 'default', - params: { - index: ES_TEST_INDEX_NAME, - reference: '', - message: 'test message', - }, - }; - }), - }); - const { body: createdAlert } = await supertest - .post(`${getUrlPrefix(Spaces.space1.id)}/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(alertData) - .expect(200); - objectRemover.add(Spaces.space1.id, createdAlert.id, 'rule', 'alerting'); - - const events = flatten( - await Promise.all( - createdActions.map(async (createdAction) => { - return await retry.try(async () => { - return await getEventLog({ - getService, - spaceId: Spaces.space1.id, - type: 'action', - id: createdAction.body.id, - provider: 'actions', - actions: new Map([['execute', { gte: 1 }]]), - }); - }); - }) - ) - ); - - const executeActionsEvents = getEventsByAction(events, 'execute'); - expect(executeActionsEvents.length).equal( - nonEphemeralTasks + DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT - ); - - const searchResult = await esTestIndexTool.search('action:test.index-record'); - // @ts-expect-error doesnt handle total: number - expect(searchResult.body.hits.total.value).equal( - nonEphemeralTasks + DEFAULT_MAX_EPHEMERAL_ACTIONS_PER_ALERT - ); - }); - }); -} - -function getEventsByAction(events: IValidatedEvent[], action: string) { - return events.filter((event) => event?.event?.action === action); -} diff --git a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/index.ts b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/index.ts index 79dae86b6a8d..1da03fbbcc54 100644 --- a/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/index.ts +++ b/x-pack/test/alerting_api_integration/spaces_only/tests/alerting/group4/index.ts @@ -18,7 +18,6 @@ export default function alertingTests({ loadTestFile, getService }: FtrProviderC loadTestFile(require.resolve('./builtin_alert_types')); loadTestFile(require.resolve('./mustache_templates.ts')); loadTestFile(require.resolve('./notify_when')); - loadTestFile(require.resolve('./ephemeral')); loadTestFile(require.resolve('./event_log_alerts')); loadTestFile(require.resolve('./snooze')); loadTestFile(require.resolve('./unsnooze')); diff --git a/x-pack/test/api_integration/apis/cases/common/roles.ts b/x-pack/test/api_integration/apis/cases/common/roles.ts index 21ad6943ba0d..c50076b301f7 100644 --- a/x-pack/test/api_integration/apis/cases/common/roles.ts +++ b/x-pack/test/api_integration/apis/cases/common/roles.ts @@ -136,6 +136,56 @@ export const secCasesV2All: Role = { }, }; +export const secCasesV2NoReopenWithCreateComment: Role = { + name: 'sec_cases_v2_no_reopen_role_api_int', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + siem: ['all'], + securitySolutionCasesV2: ['read', 'update', 'create', 'delete', 'create_comment'], + actions: ['all'], + actionsSimulators: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + +export const secCasesV2NoCreateCommentWithReopen: Role = { + name: 'sec_cases_v2_create_comment_no_reopen_role_api_int', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + siem: ['all'], + securitySolutionCasesV2: ['read', 'update', 'create', 'delete', 'case_reopen'], + actions: ['all'], + actionsSimulators: ['all'], + }, + spaces: ['*'], + }, + ], + }, +}; + export const secAllSpace1: Role = { name: 'sec_all_role_space1_api_int', privileges: { @@ -434,6 +484,56 @@ export const casesV2All: Role = { }, }; +export const casesV2NoReopenWithCreateComment: Role = { + name: 'cases_v2_no_reopen_role_api_int', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + spaces: ['*'], + base: [], + feature: { + generalCasesV2: ['read', 'update', 'create', 'delete', 'create_comment'], + actions: ['all'], + actionsSimulators: ['all'], + }, + }, + ], + }, +}; + +export const casesV2NoCreateCommentWithReopen: Role = { + name: 'cases_v2_no_create_comment_role_api_int', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + spaces: ['*'], + base: [], + feature: { + generalCasesV2: ['read', 'update', 'create', 'delete', 'case_reopen'], + actions: ['all'], + actionsSimulators: ['all'], + }, + }, + ], + }, +}; + export const casesRead: Role = { name: 'cases_read_role_api_int', privileges: { @@ -583,6 +683,56 @@ export const obsCasesV2All: Role = { }, }; +export const obsCasesV2NoReopenWithCreateComment: Role = { + name: 'obs_cases_v2_no_reopen_role_api_int', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + spaces: ['*'], + base: [], + feature: { + observabilityCasesV2: ['read', 'update', 'create', 'delete', 'create_comment'], + actions: ['all'], + actionsSimulators: ['all'], + }, + }, + ], + }, +}; + +export const obsCasesV2NoCreateCommentWithReopen: Role = { + name: 'obs_cases_v2_no_create_comment_role_api_int', + privileges: { + elasticsearch: { + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + spaces: ['*'], + base: [], + feature: { + observabilityCasesV2: ['read', 'update', 'create', 'delete', 'case_reopen'], + actions: ['all'], + actionsSimulators: ['all'], + }, + }, + ], + }, +}; + export const obsCasesRead: Role = { name: 'obs_cases_read_role_api_int', privileges: { @@ -613,6 +763,8 @@ export const roles = [ secAllCasesNoDelete, secAll, secCasesV2All, + secCasesV2NoReopenWithCreateComment, + secCasesV2NoCreateCommentWithReopen, secAllSpace1, secAllCasesRead, secAllCasesNone, @@ -625,11 +777,15 @@ export const roles = [ casesNoDelete, casesAll, casesV2All, + casesV2NoReopenWithCreateComment, + casesV2NoCreateCommentWithReopen, casesRead, obsCasesOnlyDelete, obsCasesOnlyReadDelete, obsCasesNoDelete, obsCasesAll, obsCasesV2All, + obsCasesV2NoReopenWithCreateComment, + obsCasesV2NoCreateCommentWithReopen, obsCasesRead, ]; diff --git a/x-pack/test/api_integration/apis/cases/common/users.ts b/x-pack/test/api_integration/apis/cases/common/users.ts index a64b9767498f..d3b05c5d3ddf 100644 --- a/x-pack/test/api_integration/apis/cases/common/users.ts +++ b/x-pack/test/api_integration/apis/cases/common/users.ts @@ -31,6 +31,12 @@ import { secReadCasesAll, secReadCasesNone, secReadCasesRead, + casesV2NoReopenWithCreateComment, + obsCasesV2NoReopenWithCreateComment, + secCasesV2NoReopenWithCreateComment, + secCasesV2NoCreateCommentWithReopen, + casesV2NoCreateCommentWithReopen, + obsCasesV2NoCreateCommentWithReopen, } from './roles'; /** @@ -67,6 +73,18 @@ export const secCasesV2AllUser: User = { roles: [secCasesV2All.name], }; +export const secCasesV2NoReopenWithCreateCommentUser: User = { + username: 'sec_cases_v2_no_reopen_with_create_comment_user_api_int', + password: 'password', + roles: [secCasesV2NoReopenWithCreateComment.name], +}; + +export const secCasesV2NoCreateCommentWithReopenUser: User = { + username: 'sec_cases_v2_no_create_comment_with_reopen_user_api_int', + password: 'password', + roles: [secCasesV2NoCreateCommentWithReopen.name], +}; + export const secAllSpace1User: User = { username: 'sec_all_space1_user_api_int', password: 'password', @@ -143,6 +161,18 @@ export const casesV2AllUser: User = { roles: [casesV2All.name], }; +export const casesV2NoReopenWithCreateCommentUser: User = { + username: 'cases_v2_no_reopen_with_create_comment_user_api_int', + password: 'password', + roles: [casesV2NoReopenWithCreateComment.name], +}; + +export const casesV2NoCreateCommentWithReopenUser: User = { + username: 'cases_v2_no_create_comment_with_reopen_user_api_int', + password: 'password', + roles: [casesV2NoCreateCommentWithReopen.name], +}; + export const casesReadUser: User = { username: 'cases_read_user_api_int', password: 'password', @@ -183,6 +213,18 @@ export const obsCasesV2AllUser: User = { roles: [obsCasesV2All.name], }; +export const obsCasesV2NoReopenWithCreateCommentUser: User = { + username: 'obs_cases_v2_no_reopen_with_create_comment_user_api_int', + password: 'password', + roles: [obsCasesV2NoReopenWithCreateComment.name], +}; + +export const obsCasesV2NoCreateCommentWithReopenUser: User = { + username: 'obs_cases_v2_no_create_comment_with_reopen_user_api_int', + password: 'password', + roles: [obsCasesV2NoCreateCommentWithReopen.name], +}; + export const obsCasesReadUser: User = { username: 'obs_cases_read_user_api_int', password: 'password', @@ -211,6 +253,8 @@ export const users = [ secAllCasesNoDeleteUser, secAllUser, secCasesV2AllUser, + secCasesV2NoReopenWithCreateCommentUser, + secCasesV2NoCreateCommentWithReopenUser, secAllSpace1User, secAllCasesReadUser, secAllCasesNoneUser, @@ -223,12 +267,16 @@ export const users = [ casesNoDeleteUser, casesAllUser, casesV2AllUser, + casesV2NoReopenWithCreateCommentUser, + casesV2NoCreateCommentWithReopenUser, casesReadUser, obsCasesOnlyDeleteUser, obsCasesOnlyReadDeleteUser, obsCasesNoDeleteUser, obsCasesAllUser, obsCasesV2AllUser, + obsCasesV2NoReopenWithCreateCommentUser, + obsCasesV2NoCreateCommentWithReopenUser, obsCasesReadUser, obsSecCasesAllUser, obsSecCasesReadUser, diff --git a/x-pack/test/api_integration/apis/cases/privileges.ts b/x-pack/test/api_integration/apis/cases/privileges.ts index 53a1767f5c1a..4e2baeeffa51 100644 --- a/x-pack/test/api_integration/apis/cases/privileges.ts +++ b/x-pack/test/api_integration/apis/cases/privileges.ts @@ -40,6 +40,12 @@ import { secReadCasesNoneUser, secReadCasesReadUser, secReadUser, + casesV2NoReopenWithCreateCommentUser, + casesV2NoCreateCommentWithReopenUser, + obsCasesV2NoReopenWithCreateCommentUser, + obsCasesV2NoCreateCommentWithReopenUser, + secCasesV2NoReopenWithCreateCommentUser, + secCasesV2NoCreateCommentWithReopenUser, } from './common/users'; import { getPostCaseRequest } from '../../../cases_api_integration/common/lib/mock'; @@ -183,6 +189,9 @@ export default ({ getService }: FtrProviderContext): void => { { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, { user: casesAllUser, owner: CASES_APP_ID }, { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesV2NoCreateCommentWithReopenUser, owner: CASES_APP_ID }, + { user: obsCasesV2NoCreateCommentWithReopenUser, owner: OBSERVABILITY_APP_ID }, + { user: secCasesV2NoCreateCommentWithReopenUser, owner: SECURITY_SOLUTION_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can reopen a case`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -206,6 +215,35 @@ export default ({ getService }: FtrProviderContext): void => { }); } + for (const { user, owner } of [ + { user: casesV2NoReopenWithCreateCommentUser, owner: CASES_APP_ID }, + { user: obsCasesV2NoReopenWithCreateCommentUser, owner: OBSERVABILITY_APP_ID }, + { user: secCasesV2NoReopenWithCreateCommentUser, owner: SECURITY_SOLUTION_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT reopen a case`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'closed' as CaseStatuses, + version: '2', + expectedHttpCode: 200, + auth: { user, space: null }, + }); + + await updateCaseStatus({ + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + status: 'open' as CaseStatuses, + version: '3', + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } + for (const { user, owner } of [ { user: secAllUser, owner: SECURITY_SOLUTION_APP_ID }, { user: secCasesV2AllUser, owner: SECURITY_SOLUTION_APP_ID }, @@ -213,6 +251,9 @@ export default ({ getService }: FtrProviderContext): void => { { user: obsCasesV2AllUser, owner: OBSERVABILITY_APP_ID }, { user: casesAllUser, owner: CASES_APP_ID }, { user: casesV2AllUser, owner: CASES_APP_ID }, + { user: casesV2NoReopenWithCreateCommentUser, owner: CASES_APP_ID }, + { user: obsCasesV2NoReopenWithCreateCommentUser, owner: OBSERVABILITY_APP_ID }, + { user: secCasesV2NoReopenWithCreateCommentUser, owner: SECURITY_SOLUTION_APP_ID }, ]) { it(`User ${user.username} with role(s) ${user.roles.join()} can add comments`, async () => { const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); @@ -230,5 +271,29 @@ export default ({ getService }: FtrProviderContext): void => { }); }); } + + for (const { user, owner } of [ + { user: casesV2NoCreateCommentWithReopenUser, owner: CASES_APP_ID }, + { user: obsCasesV2NoCreateCommentWithReopenUser, owner: OBSERVABILITY_APP_ID }, + { user: secCasesV2NoCreateCommentWithReopenUser, owner: SECURITY_SOLUTION_APP_ID }, + ]) { + it(`User ${ + user.username + } with role(s) ${user.roles.join()} CANNOT add comments`, async () => { + const caseInfo = await createCase(supertest, getPostCaseRequest({ owner })); + const comment: UserCommentAttachmentPayload = { + comment: 'test', + owner, + type: AttachmentType.user, + }; + await createComment({ + params: comment, + supertest: supertestWithoutAuth, + caseId: caseInfo.id, + expectedHttpCode: 403, + auth: { user, space: null }, + }); + }); + } }); }; diff --git a/x-pack/test/api_integration/apis/content_management/dashboard_search.ts b/x-pack/test/api_integration/apis/content_management/dashboard_search.ts new file mode 100644 index 000000000000..9a1739d508d1 --- /dev/null +++ b/x-pack/test/api_integration/apis/content_management/dashboard_search.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { sampleDashboard } from './helpers'; + +export default function ({ getService }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const supertest = getService('supertest'); + + describe('search dashboards', function () { + const createPayload = { + ...sampleDashboard, + options: { + ...sampleDashboard.options, + references: [ + { + type: 'tag', + id: 'tag1', + name: 'tag-ref-tag1', + }, + { + type: 'index-pattern', + id: 'index-pattern1', + name: 'index-pattern-ref-index-pattern1', + }, + ], + }, + }; + before(async () => { + await kibanaServer.savedObjects.clean({ + types: ['dashboard'], + }); + + await supertest + .post('/api/content_management/rpc/create') + .set('kbn-xsrf', 'true') + .send(createPayload) + .expect(200); + }); + + it('can specify references to return', async () => { + const searchPayload = { + contentTypeId: 'dashboard', + version: 3, + query: {}, + options: {}, + }; + + { + const { body } = await supertest + .post('/api/content_management/rpc/search') + .set('kbn-xsrf', 'true') + .send(searchPayload) + .expect(200); + + expect(body.result.result.hits[0].references).to.eql(createPayload.options.references); + } + + { + const { body } = await supertest + .post('/api/content_management/rpc/search') + .set('kbn-xsrf', 'true') + .send({ ...searchPayload, options: { includeReferences: ['tag'] } }) + .expect(200); + + expect(body.result.result.hits[0].references).to.eql([createPayload.options.references[0]]); + } + }); + }); +} diff --git a/x-pack/test/api_integration/apis/content_management/index.ts b/x-pack/test/api_integration/apis/content_management/index.ts index 992aafa74d27..26541d6e7e46 100644 --- a/x-pack/test/api_integration/apis/content_management/index.ts +++ b/x-pack/test/api_integration/apis/content_management/index.ts @@ -12,5 +12,6 @@ export default function ({ loadTestFile, getService }: FtrProviderContext) { loadTestFile(require.resolve('./created_by')); loadTestFile(require.resolve('./updated_by')); loadTestFile(require.resolve('./favorites')); + loadTestFile(require.resolve('./dashboard_search')); }); } diff --git a/x-pack/test/api_integration/apis/management/index_management/create_enrich_policy.ts b/x-pack/test/api_integration/apis/management/index_management/create_enrich_policy.ts index e2bfa9cdb35e..36f5e17e347d 100644 --- a/x-pack/test/api_integration/apis/management/index_management/create_enrich_policy.ts +++ b/x-pack/test/api_integration/apis/management/index_management/create_enrich_policy.ts @@ -19,6 +19,9 @@ export default function ({ getService }: FtrProviderContext) { const INDEX_A_NAME = `index-${Math.random()}`; const INDEX_B_NAME = `index-${Math.random()}`; const POLICY_NAME = `policy-${Math.random()}`; + const DATA_STREAM_TEMPLATE = `data-stream-template`; + const DATA_STREAM_A_NAME = `data-stream-${Math.random()}`; + const DATA_STREAM_B_NAME = `data-stream-${Math.random()}`; before(async () => { try { @@ -56,6 +59,24 @@ export default function ({ getService }: FtrProviderContext) { log.debug('[Setup error] Error creating test index'); throw err; } + try { + await es.indices.putIndexTemplate({ + name: DATA_STREAM_TEMPLATE, + body: { + index_patterns: ['data-stream-*'], + data_stream: {}, + }, + }); + await es.indices.createDataStream({ + name: DATA_STREAM_A_NAME, + }); + await es.indices.createDataStream({ + name: DATA_STREAM_B_NAME, + }); + } catch (err) { + log.debug('[Setup error] Error creating test data stream'); + throw err; + } }); after(async () => { @@ -66,6 +87,14 @@ export default function ({ getService }: FtrProviderContext) { log.debug('[Cleanup error] Error deleting test index'); throw err; } + try { + await es.indices.deleteDataStream({ name: DATA_STREAM_A_NAME }); + await es.indices.deleteDataStream({ name: DATA_STREAM_B_NAME }); + await es.indices.deleteIndexTemplate({ name: DATA_STREAM_TEMPLATE }); + } catch (err) { + log.debug('[Cleanup error] Error deleting test data stream'); + throw err; + } }); it('Allows to create an enrich policy', async () => { @@ -92,11 +121,14 @@ export default function ({ getService }: FtrProviderContext) { .post(`${INTERNAL_API_BASE_PATH}/enrich_policies/get_fields_from_indices`) .set('kbn-xsrf', 'xxx') .set('x-elastic-internal-origin', 'xxx') - .send({ indices: [INDEX_A_NAME, INDEX_B_NAME] }) + .send({ indices: [INDEX_A_NAME, INDEX_B_NAME, DATA_STREAM_A_NAME, DATA_STREAM_B_NAME] }) .expect(200); expect(body).toStrictEqual({ - commonFields: [{ name: 'email', type: 'text', normalizedType: 'text' }], + commonFields: [ + { name: 'email', type: 'text', normalizedType: 'text' }, + { name: '@timestamp', type: 'date', normalizedType: 'date' }, + ], indices: [ { index: INDEX_A_NAME, @@ -112,6 +144,14 @@ export default function ({ getService }: FtrProviderContext) { { name: 'email', type: 'text', normalizedType: 'text' }, ], }, + { + index: DATA_STREAM_A_NAME, + fields: [{ name: '@timestamp', type: 'date', normalizedType: 'date' }], + }, + { + index: DATA_STREAM_B_NAME, + fields: [{ name: '@timestamp', type: 'date', normalizedType: 'date' }], + }, ], }); }); @@ -128,5 +168,20 @@ export default function ({ getService }: FtrProviderContext) { body.indices.every((value: string) => [INDEX_A_NAME, INDEX_B_NAME].includes(value)) ).toBe(true); }); + + it('Can retrieve matching data streams', async () => { + const { body } = await supertest + .post(`${INTERNAL_API_BASE_PATH}/enrich_policies/get_matching_data_streams`) + .set('kbn-xsrf', 'xxx') + .set('x-elastic-internal-origin', 'xxx') + .send({ pattern: 'data-stream-' }) + .expect(200); + + expect( + body.dataStreams.every((value: string) => + [DATA_STREAM_A_NAME, DATA_STREAM_B_NAME].includes(value) + ) + ).toBe(true); + }); }); } diff --git a/x-pack/test/api_integration/apis/ml/modules/get_module.ts b/x-pack/test/api_integration/apis/ml/modules/get_module.ts index ee223eb0de3e..d8f3ce736526 100644 --- a/x-pack/test/api_integration/apis/ml/modules/get_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/get_module.ts @@ -28,6 +28,7 @@ const moduleIds = [ 'sample_data_weblogs', 'security_auth', 'security_cloudtrail', + 'security_host', 'security_linux_v3', 'security_network', 'security_packetbeat', @@ -41,6 +42,7 @@ const securityModuleIds = [ 'logs_ui_categories', 'security_auth', 'security_cloudtrail', + 'security_host', 'security_linux_v3', 'security_network', 'security_packetbeat', diff --git a/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts b/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts index 31dd5f335463..3daa5e73f308 100644 --- a/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts +++ b/x-pack/test/api_integration/apis/ml/modules/recognize_module.ts @@ -135,6 +135,7 @@ export default ({ getService }: FtrProviderContext) => { responseCode: 200, moduleIds: [ 'security_auth', + 'security_host', 'security_linux_v3', 'security_network', 'security_windows_v3', diff --git a/x-pack/test/api_integration/apis/ml/notifications/count_notifications.ts b/x-pack/test/api_integration/apis/ml/notifications/count_notifications.ts index a066999a08b5..e1ddf399d572 100644 --- a/x-pack/test/api_integration/apis/ml/notifications/count_notifications.ts +++ b/x-pack/test/api_integration/apis/ml/notifications/count_notifications.ts @@ -6,7 +6,6 @@ */ import expect from '@kbn/expect'; -import moment from 'moment'; import type { FtrProviderContext } from '../../../ftr_provider_context'; import { USER } from '../../../../functional/services/ml/security_common'; import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api'; @@ -14,20 +13,25 @@ import { getCommonRequestHeader } from '../../../../functional/services/ml/commo export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); const ml = getService('ml'); + let testStart: number; describe('GET notifications count', () => { + before(async () => { + testStart = Date.now(); + }); + describe('when no ML entities present', () => { it('return a default response', async () => { const { body, status } = await supertest .get(`/internal/ml/notifications/count`) - .query({ lastCheckedAt: moment().subtract(7, 'd').valueOf() }) + .query({ lastCheckedAt: testStart }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); - expect(body.info).to.eql(0); - expect(body.warning).to.eql(0); - expect(body.error).to.eql(0); + expect(body.info).to.eql(0, `Expecting info count to be 0, got ${body.info}`); + expect(body.warning).to.eql(0, `Expecting warning count to be 0, got ${body.warning}`); + expect(body.error).to.eql(0, `Expecting error count to be 0, got ${body.error}`); }); }); @@ -36,10 +40,11 @@ export default ({ getService }: FtrProviderContext) => { await ml.api.initSavedObjects(); await ml.testResources.setKibanaTimeZoneToUTC(); - const adJobConfig = ml.commonConfig.getADFqSingleMetricJobConfig('fq_job'); + const jobId = `fq_job_${Date.now()}`; + const adJobConfig = ml.commonConfig.getADFqSingleMetricJobConfig(jobId); await ml.api.createAnomalyDetectionJob(adJobConfig); - await ml.api.waitForJobNotificationsToIndex('fq_job'); + await ml.api.waitForJobNotificationsToIndex(jobId); }); after(async () => { @@ -50,14 +55,14 @@ export default ({ getService }: FtrProviderContext) => { it('return notifications count by level', async () => { const { body, status } = await supertest .get(`/internal/ml/notifications/count`) - .query({ lastCheckedAt: moment().subtract(7, 'd').valueOf() }) + .query({ lastCheckedAt: testStart }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); - expect(body.info).to.eql(1); - expect(body.warning).to.eql(0); - expect(body.error).to.eql(0); + expect(body.info).to.eql(1, `Expecting info count to be 1, got ${body.info}`); + expect(body.warning).to.eql(0, `Expecting warning count to be 0, got ${body.warning}`); + expect(body.error).to.eql(0, `Expecting error count to be 0, got ${body.error}`); }); it('returns an error for unauthorized user', async () => { diff --git a/x-pack/test/api_integration/apis/ml/notifications/get_notifications.ts b/x-pack/test/api_integration/apis/ml/notifications/get_notifications.ts index e13f1869e665..5e5f2c584c46 100644 --- a/x-pack/test/api_integration/apis/ml/notifications/get_notifications.ts +++ b/x-pack/test/api_integration/apis/ml/notifications/get_notifications.ts @@ -18,9 +18,11 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); const esArchiver = getService('esArchiver'); const ml = getService('ml'); + let testStart: number; describe('GET notifications', () => { before(async () => { + testStart = Date.now(); await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/bm_classification'); await ml.api.initSavedObjects(); await ml.testResources.setKibanaTimeZoneToUTC(); @@ -45,7 +47,7 @@ export default ({ getService }: FtrProviderContext) => { it('return all notifications ', async () => { const { body, status } = await supertest .get(`/internal/ml/notifications`) - .query({ earliest: 'now-1d', latest: 'now' }) + .query({ earliest: testStart, latest: 'now' }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); @@ -56,7 +58,7 @@ export default ({ getService }: FtrProviderContext) => { it('return notifications based on the query string', async () => { const { body, status } = await supertest .get(`/internal/ml/notifications`) - .query({ earliest: 'now-1d', latest: 'now', queryString: 'job_type:anomaly_detector' }) + .query({ earliest: testStart, latest: 'now', queryString: 'job_type:anomaly_detector' }) .auth(USER.ML_VIEWER, ml.securityCommon.getPasswordForUser(USER.ML_VIEWER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); @@ -72,7 +74,7 @@ export default ({ getService }: FtrProviderContext) => { it('supports sorting asc sorting by field', async () => { const { body, status } = await supertest .get(`/internal/ml/notifications`) - .query({ earliest: 'now-1d', latest: 'now', sortField: 'job_id', sortDirection: 'asc' }) + .query({ earliest: testStart, latest: 'now', sortField: 'job_id', sortDirection: 'asc' }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); @@ -83,7 +85,7 @@ export default ({ getService }: FtrProviderContext) => { it('supports sorting desc sorting by field', async () => { const { body, status } = await supertest .get(`/internal/ml/notifications`) - .query({ earliest: 'now-1h', latest: 'now', sortField: 'job_id', sortDirection: 'desc' }) + .query({ earliest: testStart, latest: 'now', sortField: 'job_id', sortDirection: 'desc' }) .auth(USER.ML_POWERUSER, ml.securityCommon.getPasswordForUser(USER.ML_POWERUSER)) .set(getCommonRequestHeader('1')); ml.api.assertResponseStatusCode(200, status, body); diff --git a/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts b/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts index 78f4347cd091..a3953a87b82b 100644 --- a/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts +++ b/x-pack/test/api_integration/apis/ml/trained_models/get_models.ts @@ -32,7 +32,6 @@ export default ({ getService }: FtrProviderContext) => { }); after(async () => { - await ml.api.cleanMlIndices(); await esDeleteAllIndices('user-index_dfa*'); // delete created ingest pipelines @@ -42,6 +41,7 @@ export default ({ getService }: FtrProviderContext) => { ) ); await ml.testResources.cleanMLSavedObjects(); + await ml.api.cleanMlIndices(); }); it('returns all trained models with associated pipelines including aliases', async () => { diff --git a/x-pack/test/api_integration/apis/security/privileges.ts b/x-pack/test/api_integration/apis/security/privileges.ts index b269aef6ae1c..dc84f6c33d20 100644 --- a/x-pack/test/api_integration/apis/security/privileges.ts +++ b/x-pack/test/api_integration/apis/security/privileges.ts @@ -91,7 +91,14 @@ export default function ({ getService }: FtrProviderContext) { 'execute_operations_all', 'scan_operations_all', ], - uptime: ['all', 'read', 'minimal_all', 'minimal_read', 'elastic_managed_locations_enabled'], + uptime: [ + 'all', + 'read', + 'minimal_all', + 'minimal_read', + 'elastic_managed_locations_enabled', + 'can_manage_private_locations', + ], securitySolutionAssistant: [ 'all', 'read', diff --git a/x-pack/test/api_integration/apis/security/privileges_basic.ts b/x-pack/test/api_integration/apis/security/privileges_basic.ts index a97ee360062c..2bbd70fcf730 100644 --- a/x-pack/test/api_integration/apis/security/privileges_basic.ts +++ b/x-pack/test/api_integration/apis/security/privileges_basic.ts @@ -178,6 +178,7 @@ export default function ({ getService }: FtrProviderContext) { ], uptime: [ 'all', + 'can_manage_private_locations', 'elastic_managed_locations_enabled', 'read', 'minimal_all', diff --git a/x-pack/test/api_integration/apis/spaces/set_solution_space.ts b/x-pack/test/api_integration/apis/spaces/set_solution_space.ts index 8019b59ca817..7f91c5fb606a 100644 --- a/x-pack/test/api_integration/apis/spaces/set_solution_space.ts +++ b/x-pack/test/api_integration/apis/spaces/set_solution_space.ts @@ -139,7 +139,7 @@ export default function ({ getService }: FtrProviderContext) { .expect(400); expect(body.message).to.eql( - '[request body]: types that failed validation:\n- [request body.0.solution]: expected at least one defined value but got [undefined]\n- [request body.1.solution_type]: types that failed validation:\n - [request body.solution_type.0]: expected value to equal [security]\n - [request body.solution_type.1]: expected value to equal [observability]\n - [request body.solution_type.2]: expected value to equal [elasticsearch]' + '[request body]: types that failed validation:\n- [request body.0.solution]: expected at least one defined value but got [undefined]\n- [request body.1.solution_type]: types that failed validation:\n - [request body.solution_type.0]: expected value to equal [security]\n - [request body.solution_type.1]: expected value to equal [observability]\n - [request body.solution_type.2]: expected value to equal [elasticsearch]\n - [request body.solution_type.3]: expected value to equal [search]' ); }); diff --git a/x-pack/test/api_integration/apis/streams/config.ts b/x-pack/test/api_integration/apis/streams/config.ts new file mode 100644 index 000000000000..c737db949983 --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/config.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../config.ts')); + return { + ...baseIntegrationTestsConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/api_integration/apis/streams/enrichment.ts b/x-pack/test/api_integration/apis/streams/enrichment.ts new file mode 100644 index 000000000000..22293b09fbbb --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/enrichment.ts @@ -0,0 +1,162 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { JsonObject } from '@kbn/utility-types'; +import { SearchTotalHits } from '@elastic/elasticsearch/lib/api/types'; +import { enableStreams, fetchDocument, indexDocument, putStream } from './helpers/requests'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { waitForDocumentInIndex } from '../../../alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; +import { cleanUpRootStream } from './helpers/cleanup'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esClient = getService('es'); + const retryService = getService('retry'); + const logger = getService('log'); + + describe('Enrichment', () => { + after(async () => { + await cleanUpRootStream(esClient); + }); + + before(async () => { + await enableStreams(supertest); + }); + + it('Place processing steps', async () => { + const body = { + fields: [ + { + name: '@timestamp', + type: 'date', + }, + { + name: 'message', + type: 'match_only_text', + }, + { + name: 'message2', + type: 'match_only_text', + }, + { + name: 'host.name', + type: 'keyword', + }, + { + name: 'log.level', + type: 'keyword', + }, + ], + processing: [ + { + config: { + type: 'grok', + field: 'message', + patterns: [ + '%{TIMESTAMP_ISO8601:inner_timestamp} %{LOGLEVEL:log.level} %{GREEDYDATA:message2}', + ], + }, + } as JsonObject, + { + config: { + type: 'dissect', + field: 'message2', + pattern: '%{log.logger} %{message3}', + }, + condition: { + field: 'log.level', + operator: 'eq', + value: 'info', + }, + } as JsonObject, + ], + children: [], + }; + const response = await putStream(supertest, 'logs', body); + expect(response).to.have.property('acknowledged', true); + }); + + it('Index doc not matching condition', async () => { + const doc = { + '@timestamp': '2024-01-01T00:00:10.000Z', + message: '2023-01-01T00:00:10.000Z error test', + }; + const response = await indexDocument(esClient, 'logs', doc); + expect(response.result).to.eql('created'); + await waitForDocumentInIndex({ esClient, indexName: 'logs', retryService, logger }); + + const result = await fetchDocument(esClient, 'logs', response._id); + expect(result._source).to.eql({ + '@timestamp': '2024-01-01T00:00:10.000Z', + message: '2023-01-01T00:00:10.000Z error test', + inner_timestamp: '2023-01-01T00:00:10.000Z', + message2: 'test', + log: { + level: 'error', + }, + }); + }); + + it('Index doc matching condition', async () => { + const doc = { + '@timestamp': '2024-01-01T00:00:11.000Z', + message: '2023-01-01T00:00:10.000Z info mylogger this is the message', + }; + const response = await indexDocument(esClient, 'logs', doc); + expect(response.result).to.eql('created'); + await waitForDocumentInIndex({ + esClient, + indexName: 'logs', + retryService, + logger, + docCountTarget: 2, + }); + + const result = await fetchDocument(esClient, 'logs', response._id); + expect(result._source).to.eql({ + '@timestamp': '2024-01-01T00:00:11.000Z', + message: '2023-01-01T00:00:10.000Z info mylogger this is the message', + inner_timestamp: '2023-01-01T00:00:10.000Z', + log: { + level: 'info', + logger: 'mylogger', + }, + message2: 'mylogger this is the message', + message3: 'this is the message', + }); + }); + + it('Doc is searchable', async () => { + const response = await esClient.search({ + index: 'logs', + body: { + query: { + match: { + message2: 'mylogger', + }, + }, + }, + }); + expect((response.hits.total as SearchTotalHits).value).to.eql(1); + }); + + it('Non-indexed field is not searchable', async () => { + const response = await esClient.search({ + index: 'logs', + body: { + query: { + match: { + 'log.logger': 'mylogger', + }, + }, + }, + }); + expect((response.hits.total as SearchTotalHits).value).to.eql(0); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/streams/full_flow.ts b/x-pack/test/api_integration/apis/streams/full_flow.ts new file mode 100644 index 000000000000..03c0cc9e0e21 --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/full_flow.ts @@ -0,0 +1,140 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { + deleteStream, + enableStreams, + fetchDocument, + forkStream, + indexDocument, +} from './helpers/requests'; +import { FtrProviderContext } from '../../ftr_provider_context'; +import { waitForDocumentInIndex } from '../../../alerting_api_integration/observability/helpers/alerting_wait_for_helpers'; +import { cleanUpRootStream } from './helpers/cleanup'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esClient = getService('es'); + const retryService = getService('retry'); + const logger = getService('log'); + + describe('Basic functionality', () => { + after(async () => { + await deleteStream(supertest, 'logs.nginx'); + await cleanUpRootStream(esClient); + }); + + // Note: Each step is dependent on the previous + describe('Full flow', () => { + it('Enable streams', async () => { + await enableStreams(supertest); + }); + + it('Index a JSON document to logs, should go to logs', async () => { + const doc = { + '@timestamp': '2024-01-01T00:00:00.000Z', + message: JSON.stringify({ + 'log.level': 'info', + 'log.logger': 'nginx', + message: 'test', + }), + }; + const response = await indexDocument(esClient, 'logs', doc); + expect(response.result).to.eql('created'); + await waitForDocumentInIndex({ esClient, indexName: 'logs', retryService, logger }); + + const result = await fetchDocument(esClient, 'logs', response._id); + expect(result._index).to.match(/^\.ds\-logs-.*/); + expect(result._source).to.eql({ + '@timestamp': '2024-01-01T00:00:00.000Z', + message: 'test', + log: { level: 'info', logger: 'nginx' }, + }); + }); + + it('Fork logs to logs.nginx', async () => { + const body = { + stream: { + id: 'logs.nginx', + fields: [], + processing: [], + }, + condition: { + field: 'log.logger', + operator: 'eq', + value: 'nginx', + }, + }; + const response = await forkStream(supertest, 'logs', body); + expect(response).to.have.property('acknowledged', true); + }); + + it('Index an Nginx access log message, should goto logs.nginx', async () => { + const doc = { + '@timestamp': '2024-01-01T00:00:10.000Z', + message: JSON.stringify({ + 'log.level': 'info', + 'log.logger': 'nginx', + message: 'test', + }), + }; + const response = await indexDocument(esClient, 'logs', doc); + expect(response.result).to.eql('created'); + await waitForDocumentInIndex({ esClient, indexName: 'logs.nginx', retryService, logger }); + + const result = await fetchDocument(esClient, 'logs.nginx', response._id); + expect(result._index).to.match(/^\.ds\-logs.nginx-.*/); + expect(result._source).to.eql({ + '@timestamp': '2024-01-01T00:00:10.000Z', + message: 'test', + log: { level: 'info', logger: 'nginx' }, + }); + }); + + it('Fork logs to logs.nginx.access', async () => { + const body = { + stream: { + id: 'logs.nginx.access', + fields: [], + processing: [], + }, + condition: { field: 'log.level', operator: 'eq', value: 'info' }, + }; + const response = await forkStream(supertest, 'logs.nginx', body); + expect(response).to.have.property('acknowledged', true); + }); + + it('Index an Nginx access log message, should goto logs.nginx.access', async () => { + const doc = { + '@timestamp': '2024-01-01T00:00:20.000Z', + message: JSON.stringify({ + 'log.level': 'info', + 'log.logger': 'nginx', + message: 'test', + }), + }; + const response = await indexDocument(esClient, 'logs', doc); + expect(response.result).to.eql('created'); + await waitForDocumentInIndex({ + esClient, + indexName: 'logs.nginx.access', + retryService, + logger, + }); + + const result = await fetchDocument(esClient, 'logs.nginx.access', response._id); + expect(result._index).to.match(/^\.ds\-logs.nginx.access-.*/); + expect(result._source).to.eql({ + '@timestamp': '2024-01-01T00:00:20.000Z', + message: 'test', + log: { level: 'info', logger: 'nginx' }, + }); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/streams/helpers/cleanup.ts b/x-pack/test/api_integration/apis/streams/helpers/cleanup.ts new file mode 100644 index 000000000000..f1d382031d48 --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/helpers/cleanup.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { Client } from '@elastic/elasticsearch'; + +/** +DELETE .kibana_streams +DELETE _data_stream/logs +DELETE /_index_template/logs@stream +DELETE /_component_template/logs@stream.layer +DELETE /_ingest/pipeline/logs@json-pipeline +DELETE /_ingest/pipeline/logs@stream.processing +DELETE /_ingest/pipeline/logs@stream.reroutes +*/ + +export async function cleanUpRootStream(esClient: Client) { + await esClient.indices.delete({ index: '.kibana_streams' }); + await esClient.indices.deleteDataStream({ name: 'logs' }); + await esClient.indices.deleteIndexTemplate({ name: 'logs@stream' }); + await esClient.cluster.deleteComponentTemplate({ name: 'logs@stream.layer' }); + await esClient.ingest.deletePipeline({ id: 'logs@stream.*' }); +} diff --git a/x-pack/test/api_integration/apis/streams/helpers/requests.ts b/x-pack/test/api_integration/apis/streams/helpers/requests.ts new file mode 100644 index 000000000000..7d656e4aacf5 --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/helpers/requests.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { Client } from '@elastic/elasticsearch'; +import { JsonObject } from '@kbn/utility-types'; +import { Agent } from 'supertest'; +import expect from '@kbn/expect'; +import { SearchTotalHits } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +export async function enableStreams(supertest: Agent) { + const req = supertest.post('/api/streams/_enable').set('kbn-xsrf', 'xxx'); + const response = await req.send().expect(200); + return response.body; +} + +export async function indexDocument(esClient: Client, index: string, document: JsonObject) { + const response = await esClient.index({ index, document }); + return response; +} + +export async function fetchDocument(esClient: Client, index: string, id: string) { + const query = { + ids: { values: [id] }, + }; + const response = await esClient.search({ index, query }); + expect((response.hits.total as SearchTotalHits).value).to.eql(1); + return response.hits.hits[0]; +} + +export async function forkStream(supertest: Agent, root: string, body: JsonObject) { + const req = supertest.post(`/api/streams/${root}/_fork`).set('kbn-xsrf', 'xxx'); + const response = await req.send(body).expect(200); + return response.body; +} + +export async function putStream(supertest: Agent, name: string, body: JsonObject) { + const req = supertest.put(`/api/streams/${name}`).set('kbn-xsrf', 'xxx'); + const response = await req.send(body).expect(200); + return response.body; +} + +export async function deleteStream(supertest: Agent, id: string) { + const req = supertest.delete(`/api/streams/${id}`).set('kbn-xsrf', 'xxx'); + const response = await req.send().expect(200); + return response.body; +} diff --git a/x-pack/test/api_integration/apis/streams/index.ts b/x-pack/test/api_integration/apis/streams/index.ts new file mode 100644 index 000000000000..e51d63ac2ae9 --- /dev/null +++ b/x-pack/test/api_integration/apis/streams/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Streams Endpoints', () => { + loadTestFile(require.resolve('./full_flow')); + loadTestFile(require.resolve('./enrichment')); + }); +} diff --git a/x-pack/test/api_integration/apis/synthetics/private_location_apis.ts b/x-pack/test/api_integration/apis/synthetics/private_location_apis.ts index 415c91af2834..a4351ede2eda 100644 --- a/x-pack/test/api_integration/apis/synthetics/private_location_apis.ts +++ b/x-pack/test/api_integration/apis/synthetics/private_location_apis.ts @@ -11,16 +11,21 @@ import { legacyPrivateLocationsSavedObjectName, privateLocationSavedObjectName, } from '@kbn/synthetics-plugin/common/saved_objects/private_locations'; +import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; +import { PrivateLocation } from '@kbn/synthetics-plugin/common/runtime_types'; +import { SyntheticsMonitorTestService } from './services/synthetics_monitor_test_service'; import { FtrProviderContext } from '../../ftr_provider_context'; import { PrivateLocationTestService } from './services/private_location_test_service'; export default function ({ getService }: FtrProviderContext) { describe('PrivateLocationAPI', function () { this.tags('skipCloud'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); const kServer = getService('kibanaServer'); const testPrivateLocations = new PrivateLocationTestService(getService); + const monitorTestService = new SyntheticsMonitorTestService(getService); before(async () => { await testPrivateLocations.installSyntheticsPackage(); @@ -60,5 +65,72 @@ export default function ({ getService }: FtrProviderContext) { expect(e.response.status).to.be(404); } }); + + it('cannot create private location if privileges are missing', async () => { + const apiResponse = await testPrivateLocations.addFleetPolicy(); + const agentPolicyId = apiResponse.body.item.id; + + const { username, password } = await monitorTestService.addsNewSpace(['minimal_all']); + + const location: Omit = { + label: 'Test private location 10', + agentPolicyId: agentPolicyId!, + geo: { + lat: 0, + lon: 0, + }, + }; + const response = await supertestWithoutAuth + .post(SYNTHETICS_API_URLS.PRIVATE_LOCATIONS) + .auth(username, password) + .set('kbn-xsrf', 'true') + .send(location); + + expect(response.status).to.be(403); + }); + + it('can create private location if privileges are added', async () => { + const apiResponse = await testPrivateLocations.addFleetPolicy(); + const agentPolicyId = apiResponse.body.item.id; + + const { username, password } = await monitorTestService.addsNewSpace([ + 'minimal_all', + 'can_manage_private_locations', + ]); + + const location: Omit = { + label: 'Test private location 10', + agentPolicyId: agentPolicyId!, + geo: { + lat: 0, + lon: 0, + }, + }; + const response = await supertestWithoutAuth + .post(SYNTHETICS_API_URLS.PRIVATE_LOCATIONS) + .auth(username, password) + .set('kbn-xsrf', 'true') + .send(location); + + expect(response.status).to.be(200); + }); + + it('can delete private location if privileges are added', async () => { + const locs = await testPrivateLocations.fetchAll(); + + const { username, password } = await monitorTestService.addsNewSpace([ + 'minimal_all', + 'can_manage_private_locations', + ]); + + for (const loc of locs.body) { + const deleteResponse = await supertestWithoutAuth + .delete(`${SYNTHETICS_API_URLS.PRIVATE_LOCATIONS}/${loc.id}`) + .auth(username, password) + .set('kbn-xsrf', 'true'); + + expect(deleteResponse.status).to.be(200); + } + }); }); } diff --git a/x-pack/test/api_integration/apis/synthetics/synthetics_api_security.ts b/x-pack/test/api_integration/apis/synthetics/synthetics_api_security.ts index ddd0d4b20994..3969dcae8821 100644 --- a/x-pack/test/api_integration/apis/synthetics/synthetics_api_security.ts +++ b/x-pack/test/api_integration/apis/synthetics/synthetics_api_security.ts @@ -33,12 +33,18 @@ export default function ({ getService }: FtrProviderContext) { password: string; writeAccess?: boolean; tags?: string; + readUser?: boolean; } ) => { let resp; - const { statusCodes, SPACE_ID, username, password, writeAccess } = options; - const tags = !writeAccess ? '[uptime-read]' : options.tags ?? '[uptime-read,uptime-write]'; - const getStatusMessage = (respStatus: string) => + const { statusCodes, SPACE_ID, username, password, writeAccess, readUser } = options; + let tags = !writeAccess ? '[uptime-read]' : options.tags ?? '[uptime-read,uptime-write]'; + if ((method === 'POST' || method === 'DELETE') && path.includes('private_locations')) { + tags = readUser + ? '[private-location-write,uptime-write]' + : '[uptime-read,private-location-write,uptime-write]'; + } + const getStatusMessage = (respStatus: string | number) => `Expected ${statusCodes?.join( ',' )}, got ${respStatus} status code doesn't match, for path: ${path} and method ${method}`; @@ -132,6 +138,7 @@ export default function ({ getService }: FtrProviderContext) { password, writeAccess: route.writeAccess ?? true, tags: '[uptime-write]', + readUser: true, }); } }); diff --git a/x-pack/test/api_integration/apis/telemetry/telemetry.ts b/x-pack/test/api_integration/apis/telemetry/telemetry.ts index 5e034ce3a184..6159770e253d 100644 --- a/x-pack/test/api_integration/apis/telemetry/telemetry.ts +++ b/x-pack/test/api_integration/apis/telemetry/telemetry.ts @@ -14,8 +14,13 @@ import ossRootTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_root.json'; import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json'; import monitoringRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_monitoring.json'; import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.json'; +import ossPlatformTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_platform.json'; import ossPackagesTelemetrySchema from '@kbn/telemetry-plugin/schema/kbn_packages.json'; import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json'; +import xpackPlatformTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_platform.json'; +import xpackObservabilityTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_observability.json'; +import xpackSearchTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_search.json'; +import xpackSecurityTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_security.json'; import type { UnencryptedTelemetryPayload } from '@kbn/telemetry-plugin/common/types'; import type { UsageStatsPayload, @@ -161,10 +166,17 @@ export default function ({ getService }: FtrProviderContext) { // It's nested because of the way it's collected and declared monitoringRootTelemetrySchema.properties.monitoringTelemetry.properties.stats.items ); - const plugins = deepmerge( - deepmerge(ossPluginsTelemetrySchema, ossPackagesTelemetrySchema), - xpackPluginsTelemetrySchema - ); + + const plugins = [ + ossPluginsTelemetrySchema, + ossPackagesTelemetrySchema, + ossPlatformTelemetrySchema, + xpackPluginsTelemetrySchema, + xpackPlatformTelemetrySchema, + xpackObservabilityTelemetrySchema, + xpackSearchTelemetrySchema, + xpackSecurityTelemetrySchema, + ].reduce((acc, schema) => deepmerge(acc, schema)); try { assertTelemetryPayload({ root, plugins }, localXPack); @@ -172,7 +184,7 @@ export default function ({ getService }: FtrProviderContext) { assertTelemetryPayload({ root: monitoringRoot, plugins }, stats); }); } catch (err) { - err.message = `The telemetry schemas in 'x-pack/plugins/telemetry_collection_xpack/schema/' are out-of-date, please update it as required: ${err.message}`; + err.message = `The telemetry schemas in are out-of-date. Please define the schema of your collector and run "node scripts/telemetry_check --fix" to update them: ${err.message}`; throw err; } }); diff --git a/x-pack/test/api_integration/apis/telemetry/telemetry_local.ts b/x-pack/test/api_integration/apis/telemetry/telemetry_local.ts index d155bfb614cb..3201556bd18f 100644 --- a/x-pack/test/api_integration/apis/telemetry/telemetry_local.ts +++ b/x-pack/test/api_integration/apis/telemetry/telemetry_local.ts @@ -9,9 +9,14 @@ import expect from '@kbn/expect'; import deepmerge from 'deepmerge'; import ossRootTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_root.json'; import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.json'; +import ossPlatformTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_platform.json'; import ossPackagesTelemetrySchema from '@kbn/telemetry-plugin/schema/kbn_packages.json'; import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json'; import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json'; +import xpackPlatformTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_platform.json'; +import xpackObservabilityTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_observability.json'; +import xpackSearchTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_search.json'; +import xpackSecurityTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_security.json'; import { assertTelemetryPayload } from '@kbn/telemetry-tools'; import { ELASTIC_HTTP_VERSION_HEADER, @@ -57,15 +62,21 @@ export default function ({ getService }: FtrProviderContext) { it('should pass the schema validation', () => { const root = deepmerge(ossRootTelemetrySchema, xpackRootTelemetrySchema); - const plugins = deepmerge( - deepmerge(ossPluginsTelemetrySchema, ossPackagesTelemetrySchema), - xpackPluginsTelemetrySchema - ); + const plugins = [ + ossPluginsTelemetrySchema, + ossPackagesTelemetrySchema, + ossPlatformTelemetrySchema, + xpackPluginsTelemetrySchema, + xpackPlatformTelemetrySchema, + xpackObservabilityTelemetrySchema, + xpackSearchTelemetrySchema, + xpackSecurityTelemetrySchema, + ].reduce((acc, schema) => deepmerge(acc, schema)); try { assertTelemetryPayload({ root, plugins }, stats); } catch (err) { - err.message = `The telemetry schemas in 'x-pack/plugins/telemetry_collection_xpack/schema/' are out-of-date, please update it as required: ${err.message}`; + err.message = `The telemetry schemas in are out-of-date. Please define the schema of your collector and run "node scripts/telemetry_check --fix" to update them: ${err.message}`; throw err; } }); diff --git a/x-pack/test/api_integration/apis/upgrade_assistant/config.ts b/x-pack/test/api_integration/apis/upgrade_assistant/config.ts index 5f335f116fef..762cb8baa1ef 100644 --- a/x-pack/test/api_integration/apis/upgrade_assistant/config.ts +++ b/x-pack/test/api_integration/apis/upgrade_assistant/config.ts @@ -13,5 +13,15 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { return { ...baseIntegrationTestsConfig.getAll(), testFiles: [require.resolve('.')], + kbnTestServer: { + ...baseIntegrationTestsConfig.get('kbnTestServer'), + serverArgs: [ + ...baseIntegrationTestsConfig.get('kbnTestServer.serverArgs'), + '--xpack.upgrade_assistant.featureSet.mlSnapshots=true', + '--xpack.upgrade_assistant.featureSet.migrateSystemIndices=true', + '--xpack.upgrade_assistant.featureSet.migrateDataStreams=true', + '--xpack.upgrade_assistant.featureSet.reindexCorrectiveActions=true', + ], + }, }; } diff --git a/x-pack/test/api_integration/apis/upgrade_assistant/upgrade_assistant.ts b/x-pack/test/api_integration/apis/upgrade_assistant/upgrade_assistant.ts index 7d7e035741bb..f03cb6fb80e3 100644 --- a/x-pack/test/api_integration/apis/upgrade_assistant/upgrade_assistant.ts +++ b/x-pack/test/api_integration/apis/upgrade_assistant/upgrade_assistant.ts @@ -14,8 +14,7 @@ export default function ({ getService }: FtrProviderContext) { const es = getService('es'); const supertest = getService('supertest'); - // Failing: See https://github.com/elastic/kibana/issues/199719 - describe.skip('Upgrade Assistant', function () { + describe('Upgrade Assistant', function () { describe('Reindex operation saved object', () => { const dotKibanaIndex = '.kibana'; const fakeSavedObjectId = 'fakeSavedObjectId'; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/index.ts index 46ad39938055..617f9bcae89b 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/index.ts @@ -11,7 +11,6 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) describe('custom_dashboards', () => { loadTestFile(require.resolve('./dependency_metrics.spec.ts')); loadTestFile(require.resolve('./metadata.spec.ts')); - loadTestFile(require.resolve('./service_dependencies.spec.ts')); loadTestFile(require.resolve('./top_dependencies.spec.ts')); loadTestFile(require.resolve('./top_operations.spec.ts')); loadTestFile(require.resolve('./top_spans.spec.ts')); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/service_dependencies.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/service_dependencies.spec.ts deleted file mode 100644 index 4105989e5509..000000000000 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/dependencies/service_dependencies.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import expect from '@kbn/expect'; -import { DependencyNode } from '@kbn/apm-plugin/common/connections'; -import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; -import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; -import { generateData } from './generate_data'; - -export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { - const apmApiClient = getService('apmApi'); - const synthtrace = getService('synthtrace'); - const start = new Date('2021-01-01T00:00:00.000Z').getTime(); - const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; - const dependencyName = 'elasticsearch'; - const serviceName = 'synth-go'; - - async function callApi() { - return await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/services/{serviceName}/dependencies', - params: { - path: { serviceName }, - query: { - environment: 'production', - numBuckets: 20, - offset: '1d', - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - }, - }, - }); - } - - describe('Dependency for service', () => { - describe('when data is not loaded', () => { - it('handles empty state #1', async () => { - const { status, body } = await callApi(); - - expect(status).to.be(200); - expect(body.serviceDependencies).to.empty(); - }); - }); - - describe('when data is loaded', () => { - let apmSynthtraceEsClient: ApmSynthtraceEsClient; - - before(async () => { - apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); - await generateData({ apmSynthtraceEsClient, start, end }); - }); - after(() => apmSynthtraceEsClient.clean()); - - it('returns a list of dependencies for a service', async () => { - const { status, body } = await callApi(); - - expect(status).to.be(200); - expect( - body.serviceDependencies.map( - ({ location }) => (location as DependencyNode).dependencyName - ) - ).to.eql([dependencyName]); - - const currentStatsLatencyValues = - body.serviceDependencies[0].currentStats.latency.timeseries; - expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); - }); - }); - }); -} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/entities/service_logs_rate_timeseries.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/entities/service_logs_rate_timeseries.spec.ts index fb10925b9906..8a2a75851881 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/entities/service_logs_rate_timeseries.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/entities/service_logs_rate_timeseries.spec.ts @@ -150,9 +150,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon it('returns log rate timeseries', async () => { const response = await getLogsRateTimeseries(); expect(response.status).to.be(200); - expect( - response.body.currentPeriod[serviceName].every(({ y }) => y === 0.06666666666666667) - ).to.be(true); + expect(response.body.currentPeriod[serviceName].every(({ y }) => y === 1)).to.be(true); }); it('handles environment filter', async () => { @@ -168,10 +166,8 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon }); expect(response.status).to.be(200); - expect(first(response.body.currentPeriod?.['my-service'])?.y).to.be( - 0.18181818181818182 - ); - expect(last(response.body.currentPeriod?.['my-service'])?.y).to.be(0.09090909090909091); + expect(first(response.body.currentPeriod?.['my-service'])?.y).to.be(2); + expect(last(response.body.currentPeriod?.['my-service'])?.y).to.be(1); }); }); }); diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/generate_data.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/generate_data.ts index ea22c866bd66..485915523948 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/generate_data.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/generate_data.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import { ApmFields, apm, timerange } from '@kbn/apm-synthtrace-client'; import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; export const config = { @@ -25,11 +25,13 @@ export async function generateData({ serviceName, start, end, + overrides, }: { apmSynthtraceEsClient: ApmSynthtraceEsClient; serviceName: string; start: number; end: number; + overrides?: Partial; }) { const serviceGoProdInstance = apm .service({ name: serviceName, environment: 'production', agentName: 'go' }) @@ -40,18 +42,18 @@ export async function generateData({ const documents = [appleTransaction, bananaTransaction].flatMap((transaction, index) => { return [ - interval - .rate(transaction.successRate) - .generator((timestamp) => - serviceGoProdInstance - .transaction({ transactionName: transaction.name }) - .timestamp(timestamp) - .duration(1000) - .success() - ), + interval.rate(transaction.successRate).generator((timestamp) => + serviceGoProdInstance + .transaction({ transactionName: transaction.name }) + .overrides(overrides ? overrides : {}) + .timestamp(timestamp) + .duration(1000) + .success() + ), interval.rate(transaction.failureRate).generator((timestamp) => serviceGoProdInstance .transaction({ transactionName: transaction.name }) + .overrides(overrides ? overrides : {}) .errors( serviceGoProdInstance .error({ message: `Error ${index}`, type: transaction.name }) diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/group_id_samples.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/group_id_samples.spec.ts index 9c20c97fde86..764a5a9bcb4b 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/group_id_samples.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/errors/group_id_samples.spec.ts @@ -136,6 +136,33 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon }); }); + describe('error sample without trace.id', () => { + before(async () => { + await generateData({ + serviceName, + start, + end, + apmSynthtraceEsClient, + overrides: { + 'trace.id': undefined, + }, + }); + }); + + after(() => apmSynthtraceEsClient.clean()); + + it('returns 200', async () => { + const errorsSamplesResponse = await callErrorGroupSamplesApi({ + groupId: '0000000000000000000000000Error 1', + }); + + const errorId = errorsSamplesResponse.body.errorSampleIds[0]; + + const response = await callErrorSampleDetailsApi(errorId); + expect(response.status).to.be(200); + }); + }); + describe('with sampled and unsampled transactions', () => { let errorGroupSamplesResponse: ErrorGroupSamples; diff --git a/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.spec.snap b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/__snapshots__/instances_detailed_statistics.spec.snap similarity index 71% rename from x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.spec.snap rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/__snapshots__/instances_detailed_statistics.spec.snap index a5444cc6a6e3..dfea3c44472a 100644 --- a/x-pack/test/apm_api_integration/tests/service_overview/__snapshots__/instances_detailed_statistics.spec.snap +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/__snapshots__/instances_detailed_statistics.spec.snap @@ -1,69 +1,69 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`APM API tests service_overview/instances_detailed_statistics.spec.ts basic apm_8.0.0 Service overview instances detailed statistics when data is loaded fetching data with comparison returns the right data for current and previous periods 5`] = ` +exports[`Deployment-agnostic APM API integration tests APM service_overview Service Overview Instances detailed statistics when data is loaded fetching data with comparison returns the right data for current and previous periods 5`] = ` Object { "currentPeriod": Object { - "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad": Object { + "instance-a": Object { "cpuUsage": Array [ Object { "x": 1627974300000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974360000, - "y": 0.001, + "y": 0.5, }, Object { "x": 1627974420000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974480000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974540000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974600000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974660000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974720000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974780000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974840000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974900000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974960000, - "y": 0.001, + "y": 0.5, }, Object { "x": 1627975020000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627975080000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627975140000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627975200000, @@ -73,11 +73,11 @@ Object { "errorRate": Array [ Object { "x": 1627974300000, - "y": 0, + "y": null, }, Object { "x": 1627974360000, - "y": null, + "y": 0, }, Object { "x": 1627974420000, @@ -93,15 +93,15 @@ Object { }, Object { "x": 1627974600000, - "y": 0.125, + "y": 0, }, Object { "x": 1627974660000, - "y": 0.6, + "y": 0, }, Object { "x": 1627974720000, - "y": 0.2, + "y": 0, }, Object { "x": 1627974780000, @@ -113,7 +113,7 @@ Object { }, Object { "x": 1627974900000, - "y": 0.0666666666666667, + "y": 0, }, Object { "x": 1627974960000, @@ -129,7 +129,7 @@ Object { }, Object { "x": 1627975140000, - "y": 0.181818181818182, + "y": 0, }, Object { "x": 1627975200000, @@ -139,63 +139,63 @@ Object { "latency": Array [ Object { "x": 1627974300000, - "y": 34887.8888888889, + "y": null, }, Object { "x": 1627974360000, - "y": null, + "y": 1000000, }, Object { "x": 1627974420000, - "y": 4983, + "y": 1000000, }, Object { "x": 1627974480000, - "y": 41285.4, + "y": 1000000, }, Object { "x": 1627974540000, - "y": 13820.3333333333, + "y": 1000000, }, Object { "x": 1627974600000, - "y": 13782, + "y": 1000000, }, Object { "x": 1627974660000, - "y": 13392.6, + "y": 1000000, }, Object { "x": 1627974720000, - "y": 6991, + "y": 1000000, }, Object { "x": 1627974780000, - "y": 6885.85714285714, + "y": 1000000, }, Object { "x": 1627974840000, - "y": 7935, + "y": 1000000, }, Object { "x": 1627974900000, - "y": 10828.3333333333, + "y": 1000000, }, Object { "x": 1627974960000, - "y": 6079, + "y": 1000000, }, Object { "x": 1627975020000, - "y": 5217, + "y": 1000000, }, Object { "x": 1627975080000, - "y": 8477.76923076923, + "y": 1000000, }, Object { "x": 1627975140000, - "y": 5937.18181818182, + "y": 1000000, }, Object { "x": 1627975200000, @@ -205,130 +205,130 @@ Object { "memoryUsage": Array [ Object { "x": 1627974300000, - "y": 0.786640167236328, + "y": 0.416666666666667, }, Object { "x": 1627974360000, - "y": 0.786666870117188, + "y": 0.416666666666667, }, Object { "x": 1627974420000, - "y": 0.786960601806641, + "y": 0.416666666666667, }, Object { "x": 1627974480000, - "y": 0.787132263183594, + "y": 0.416666666666667, }, Object { "x": 1627974540000, - "y": 0.787441253662109, + "y": 0.416666666666667, }, Object { "x": 1627974600000, - "y": 0.787555694580078, + "y": 0.416666666666667, }, Object { "x": 1627974660000, - "y": 0.788524627685547, + "y": 0.416666666666667, }, Object { "x": 1627974720000, - "y": 0.788822174072266, + "y": 0.416666666666667, }, Object { "x": 1627974780000, - "y": 0.789054870605469, + "y": 0.416666666666667, }, Object { "x": 1627974840000, - "y": 0.78936767578125, + "y": 0.416666666666667, }, Object { "x": 1627974900000, - "y": 0.789985656738281, + "y": 0.416666666666667, }, Object { "x": 1627974960000, - "y": 0.790130615234375, + "y": 0.416666666666667, }, Object { "x": 1627975020000, - "y": 0.790508270263672, + "y": 0.416666666666667, }, Object { "x": 1627975080000, - "y": 0.791069030761719, + "y": 0.416666666666667, }, Object { "x": 1627975140000, - "y": 0.791587829589844, + "y": 0.416666666666667, }, Object { "x": 1627975200000, "y": null, }, ], - "serviceNodeName": "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad", + "serviceNodeName": "instance-a", "throughput": Array [ Object { "x": 1627974300000, - "y": 9, + "y": 0, }, Object { "x": 1627974360000, - "y": 0, + "y": 20, }, Object { "x": 1627974420000, - "y": 4, + "y": 20, }, Object { "x": 1627974480000, - "y": 5, + "y": 20, }, Object { "x": 1627974540000, - "y": 6, + "y": 20, }, Object { "x": 1627974600000, - "y": 8, + "y": 20, }, Object { "x": 1627974660000, - "y": 5, + "y": 20, }, Object { "x": 1627974720000, - "y": 5, + "y": 20, }, Object { "x": 1627974780000, - "y": 7, + "y": 20, }, Object { "x": 1627974840000, - "y": 2, + "y": 20, }, Object { "x": 1627974900000, - "y": 15, + "y": 20, }, Object { "x": 1627974960000, - "y": 3, + "y": 20, }, Object { "x": 1627975020000, - "y": 8, + "y": 20, }, Object { "x": 1627975080000, - "y": 13, + "y": 20, }, Object { "x": 1627975140000, - "y": 11, + "y": 20, }, Object { "x": 1627975200000, @@ -338,77 +338,77 @@ Object { }, }, "previousPeriod": Object { - "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad": Object { + "instance-a": Object { "cpuUsage": Array [ Object { "x": 1627974300000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974360000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974420000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974480000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974540000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974600000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974660000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974720000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974780000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974840000, - "y": 0.0045, + "y": 0.5, }, Object { "x": 1627974900000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974960000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627975020000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627975080000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627975140000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627975200000, - "y": null, + "y": 0.5, }, ], "errorRate": Array [ Object { "x": 1627974300000, - "y": 0, + "y": null, }, Object { "x": 1627974360000, @@ -416,11 +416,11 @@ Object { }, Object { "x": 1627974420000, - "y": 0.333333333333333, + "y": 0, }, Object { "x": 1627974480000, - "y": 0.181818181818182, + "y": 0, }, Object { "x": 1627974540000, @@ -432,11 +432,11 @@ Object { }, Object { "x": 1627974660000, - "y": 0.166666666666667, + "y": 0, }, Object { "x": 1627974720000, - "y": 0.181818181818182, + "y": 0, }, Object { "x": 1627974780000, @@ -448,11 +448,11 @@ Object { }, Object { "x": 1627974900000, - "y": 0.0833333333333333, + "y": 0, }, Object { "x": 1627974960000, - "y": 0.0769230769230769, + "y": 0, }, Object { "x": 1627975020000, @@ -460,214 +460,214 @@ Object { }, Object { "x": 1627975080000, - "y": 0.1, + "y": 0, }, Object { "x": 1627975140000, - "y": 0.153846153846154, + "y": 0, }, Object { "x": 1627975200000, - "y": null, + "y": 0, }, ], "latency": Array [ Object { "x": 1627974300000, - "y": 11839, + "y": null, }, Object { "x": 1627974360000, - "y": 7407, + "y": 1000000, }, Object { "x": 1627974420000, - "y": 1925569.66666667, + "y": 1000000, }, Object { "x": 1627974480000, - "y": 9017.18181818182, + "y": 1000000, }, Object { "x": 1627974540000, - "y": 63575, + "y": 1000000, }, Object { "x": 1627974600000, - "y": 7577.66666666667, + "y": 1000000, }, Object { "x": 1627974660000, - "y": 6844.33333333333, + "y": 1000000, }, Object { "x": 1627974720000, - "y": 503471, + "y": 1000000, }, Object { "x": 1627974780000, - "y": 6247.8, + "y": 1000000, }, Object { "x": 1627974840000, - "y": 1137247, + "y": 1000000, }, Object { "x": 1627974900000, - "y": 27951.6666666667, + "y": 1000000, }, Object { "x": 1627974960000, - "y": 10248.8461538462, + "y": 1000000, }, Object { "x": 1627975020000, - "y": 13529, + "y": 1000000, }, Object { "x": 1627975080000, - "y": 6691247.8, + "y": 1000000, }, Object { "x": 1627975140000, - "y": 12098.6923076923, + "y": 1000000, }, Object { "x": 1627975200000, - "y": null, + "y": 1000000, }, ], "memoryUsage": Array [ Object { "x": 1627974300000, - "y": 0.780715942382813, + "y": 0.416666666666667, }, Object { "x": 1627974360000, - "y": 0.780921936035156, + "y": 0.416666666666667, }, Object { "x": 1627974420000, - "y": 0.781166076660156, + "y": 0.416666666666667, }, Object { "x": 1627974480000, - "y": 0.781524658203125, + "y": 0.416666666666667, }, Object { "x": 1627974540000, - "y": 0.781723022460938, + "y": 0.416666666666667, }, Object { "x": 1627974600000, - "y": 0.782463073730469, + "y": 0.416666666666667, }, Object { "x": 1627974660000, - "y": 0.782634735107422, + "y": 0.416666666666667, }, Object { "x": 1627974720000, - "y": 0.782939910888672, + "y": 0.416666666666667, }, Object { "x": 1627974780000, - "y": 0.783458709716797, + "y": 0.416666666666667, }, Object { "x": 1627974840000, - "y": 0.783935546875, + "y": 0.416666666666667, }, Object { "x": 1627974900000, - "y": 0.784690856933594, + "y": 0.416666666666667, }, Object { "x": 1627974960000, - "y": 0.785182952880859, + "y": 0.416666666666667, }, Object { "x": 1627975020000, - "y": 0.785446166992188, + "y": 0.416666666666667, }, Object { "x": 1627975080000, - "y": 0.786224365234375, + "y": 0.416666666666667, }, Object { "x": 1627975140000, - "y": 0.786415100097656, + "y": 0.416666666666667, }, Object { "x": 1627975200000, - "y": null, + "y": 0.416666666666667, }, ], - "serviceNodeName": "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad", + "serviceNodeName": "instance-a", "throughput": Array [ Object { "x": 1627974300000, - "y": 4, + "y": 0, }, Object { "x": 1627974360000, - "y": 2, + "y": 20, }, Object { "x": 1627974420000, - "y": 3, + "y": 20, }, Object { "x": 1627974480000, - "y": 11, + "y": 20, }, Object { "x": 1627974540000, - "y": 4, + "y": 20, }, Object { "x": 1627974600000, - "y": 6, + "y": 20, }, Object { "x": 1627974660000, - "y": 6, + "y": 20, }, Object { "x": 1627974720000, - "y": 11, + "y": 20, }, Object { "x": 1627974780000, - "y": 10, + "y": 20, }, Object { "x": 1627974840000, - "y": 10, + "y": 20, }, Object { "x": 1627974900000, - "y": 12, + "y": 20, }, Object { "x": 1627974960000, - "y": 13, + "y": 20, }, Object { "x": 1627975020000, - "y": 8, + "y": 20, }, Object { "x": 1627975080000, - "y": 10, + "y": 20, }, Object { "x": 1627975140000, - "y": 13, + "y": 20, }, Object { "x": 1627975200000, - "y": 0, + "y": 20, }, ], }, @@ -675,130 +675,130 @@ Object { } `; -exports[`APM API tests service_overview/instances_detailed_statistics.spec.ts basic apm_8.0.0 Service overview instances detailed statistics when data is loaded fetching data without comparison returns the right data 3`] = ` +exports[`Deployment-agnostic APM API integration tests APM service_overview Service Overview Instances detailed statistics when data is loaded fetching data without comparison returns the right data 3`] = ` Object { "currentPeriod": Object { - "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad": Object { + "instance-a": Object { "cpuUsage": Array [ Object { "x": 1627973400000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627973460000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627973520000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627973580000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627973640000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627973700000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627973760000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627973820000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627973880000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627973940000, - "y": 0.0045, + "y": 0.5, }, Object { "x": 1627974000000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974060000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974120000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974180000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974240000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974300000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974360000, - "y": 0.001, + "y": 0.5, }, Object { "x": 1627974420000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974480000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974540000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974600000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974660000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974720000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974780000, - "y": 0.0015, + "y": 0.5, }, Object { "x": 1627974840000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627974900000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627974960000, - "y": 0.001, + "y": 0.5, }, Object { "x": 1627975020000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627975080000, - "y": 0.002, + "y": 0.5, }, Object { "x": 1627975140000, - "y": 0.0025, + "y": 0.5, }, Object { "x": 1627975200000, @@ -808,7 +808,7 @@ Object { "errorRate": Array [ Object { "x": 1627973400000, - "y": 0, + "y": null, }, Object { "x": 1627973460000, @@ -816,11 +816,11 @@ Object { }, Object { "x": 1627973520000, - "y": 0.333333333333333, + "y": 0, }, Object { "x": 1627973580000, - "y": 0.181818181818182, + "y": 0, }, Object { "x": 1627973640000, @@ -832,11 +832,11 @@ Object { }, Object { "x": 1627973760000, - "y": 0.166666666666667, + "y": 0, }, Object { "x": 1627973820000, - "y": 0.181818181818182, + "y": 0, }, Object { "x": 1627973880000, @@ -848,11 +848,11 @@ Object { }, Object { "x": 1627974000000, - "y": 0.0833333333333333, + "y": 0, }, Object { "x": 1627974060000, - "y": 0.0769230769230769, + "y": 0, }, Object { "x": 1627974120000, @@ -860,11 +860,11 @@ Object { }, Object { "x": 1627974180000, - "y": 0.1, + "y": 0, }, Object { "x": 1627974240000, - "y": 0.153846153846154, + "y": 0, }, Object { "x": 1627974300000, @@ -872,7 +872,7 @@ Object { }, Object { "x": 1627974360000, - "y": null, + "y": 0, }, Object { "x": 1627974420000, @@ -888,15 +888,15 @@ Object { }, Object { "x": 1627974600000, - "y": 0.125, + "y": 0, }, Object { "x": 1627974660000, - "y": 0.6, + "y": 0, }, Object { "x": 1627974720000, - "y": 0.2, + "y": 0, }, Object { "x": 1627974780000, @@ -908,7 +908,7 @@ Object { }, Object { "x": 1627974900000, - "y": 0.0666666666666667, + "y": 0, }, Object { "x": 1627974960000, @@ -924,7 +924,7 @@ Object { }, Object { "x": 1627975140000, - "y": 0.181818181818182, + "y": 0, }, Object { "x": 1627975200000, @@ -934,123 +934,123 @@ Object { "latency": Array [ Object { "x": 1627973400000, - "y": 11839, + "y": null, }, Object { "x": 1627973460000, - "y": 7407, + "y": 1000000, }, Object { "x": 1627973520000, - "y": 1925569.66666667, + "y": 1000000, }, Object { "x": 1627973580000, - "y": 9017.18181818182, + "y": 1000000, }, Object { "x": 1627973640000, - "y": 63575, + "y": 1000000, }, Object { "x": 1627973700000, - "y": 7577.66666666667, + "y": 1000000, }, Object { "x": 1627973760000, - "y": 6844.33333333333, + "y": 1000000, }, Object { "x": 1627973820000, - "y": 503471, + "y": 1000000, }, Object { "x": 1627973880000, - "y": 6247.8, + "y": 1000000, }, Object { "x": 1627973940000, - "y": 1137247, + "y": 1000000, }, Object { "x": 1627974000000, - "y": 27951.6666666667, + "y": 1000000, }, Object { "x": 1627974060000, - "y": 10248.8461538462, + "y": 1000000, }, Object { "x": 1627974120000, - "y": 13529, + "y": 1000000, }, Object { "x": 1627974180000, - "y": 6691247.8, + "y": 1000000, }, Object { "x": 1627974240000, - "y": 12098.6923076923, + "y": 1000000, }, Object { "x": 1627974300000, - "y": 34887.8888888889, + "y": 1000000, }, Object { "x": 1627974360000, - "y": null, + "y": 1000000, }, Object { "x": 1627974420000, - "y": 4983, + "y": 1000000, }, Object { "x": 1627974480000, - "y": 41285.4, + "y": 1000000, }, Object { "x": 1627974540000, - "y": 13820.3333333333, + "y": 1000000, }, Object { "x": 1627974600000, - "y": 13782, + "y": 1000000, }, Object { "x": 1627974660000, - "y": 13392.6, + "y": 1000000, }, Object { "x": 1627974720000, - "y": 6991, + "y": 1000000, }, Object { "x": 1627974780000, - "y": 6885.85714285714, + "y": 1000000, }, Object { "x": 1627974840000, - "y": 7935, + "y": 1000000, }, Object { "x": 1627974900000, - "y": 10828.3333333333, + "y": 1000000, }, Object { "x": 1627974960000, - "y": 6079, + "y": 1000000, }, Object { "x": 1627975020000, - "y": 5217, + "y": 1000000, }, Object { "x": 1627975080000, - "y": 8477.76923076923, + "y": 1000000, }, Object { "x": 1627975140000, - "y": 5937.18181818182, + "y": 1000000, }, Object { "x": 1627975200000, @@ -1060,250 +1060,250 @@ Object { "memoryUsage": Array [ Object { "x": 1627973400000, - "y": 0.780715942382813, + "y": 0.416666666666667, }, Object { "x": 1627973460000, - "y": 0.780921936035156, + "y": 0.416666666666667, }, Object { "x": 1627973520000, - "y": 0.781166076660156, + "y": 0.416666666666667, }, Object { "x": 1627973580000, - "y": 0.781524658203125, + "y": 0.416666666666667, }, Object { "x": 1627973640000, - "y": 0.781723022460938, + "y": 0.416666666666667, }, Object { "x": 1627973700000, - "y": 0.782463073730469, + "y": 0.416666666666667, }, Object { "x": 1627973760000, - "y": 0.782634735107422, + "y": 0.416666666666667, }, Object { "x": 1627973820000, - "y": 0.782939910888672, + "y": 0.416666666666667, }, Object { "x": 1627973880000, - "y": 0.783458709716797, + "y": 0.416666666666667, }, Object { "x": 1627973940000, - "y": 0.783935546875, + "y": 0.416666666666667, }, Object { "x": 1627974000000, - "y": 0.784690856933594, + "y": 0.416666666666667, }, Object { "x": 1627974060000, - "y": 0.785182952880859, + "y": 0.416666666666667, }, Object { "x": 1627974120000, - "y": 0.785446166992188, + "y": 0.416666666666667, }, Object { "x": 1627974180000, - "y": 0.786224365234375, + "y": 0.416666666666667, }, Object { "x": 1627974240000, - "y": 0.786415100097656, + "y": 0.416666666666667, }, Object { "x": 1627974300000, - "y": 0.786640167236328, + "y": 0.416666666666667, }, Object { "x": 1627974360000, - "y": 0.786666870117188, + "y": 0.416666666666667, }, Object { "x": 1627974420000, - "y": 0.786960601806641, + "y": 0.416666666666667, }, Object { "x": 1627974480000, - "y": 0.787132263183594, + "y": 0.416666666666667, }, Object { "x": 1627974540000, - "y": 0.787441253662109, + "y": 0.416666666666667, }, Object { "x": 1627974600000, - "y": 0.787555694580078, + "y": 0.416666666666667, }, Object { "x": 1627974660000, - "y": 0.788524627685547, + "y": 0.416666666666667, }, Object { "x": 1627974720000, - "y": 0.788822174072266, + "y": 0.416666666666667, }, Object { "x": 1627974780000, - "y": 0.789054870605469, + "y": 0.416666666666667, }, Object { "x": 1627974840000, - "y": 0.78936767578125, + "y": 0.416666666666667, }, Object { "x": 1627974900000, - "y": 0.789985656738281, + "y": 0.416666666666667, }, Object { "x": 1627974960000, - "y": 0.790130615234375, + "y": 0.416666666666667, }, Object { "x": 1627975020000, - "y": 0.790508270263672, + "y": 0.416666666666667, }, Object { "x": 1627975080000, - "y": 0.791069030761719, + "y": 0.416666666666667, }, Object { "x": 1627975140000, - "y": 0.791587829589844, + "y": 0.416666666666667, }, Object { "x": 1627975200000, "y": null, }, ], - "serviceNodeName": "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad", + "serviceNodeName": "instance-a", "throughput": Array [ Object { "x": 1627973400000, - "y": 4, + "y": 0, }, Object { "x": 1627973460000, - "y": 2, + "y": 20, }, Object { "x": 1627973520000, - "y": 3, + "y": 20, }, Object { "x": 1627973580000, - "y": 11, + "y": 20, }, Object { "x": 1627973640000, - "y": 4, + "y": 20, }, Object { "x": 1627973700000, - "y": 6, + "y": 20, }, Object { "x": 1627973760000, - "y": 6, + "y": 20, }, Object { "x": 1627973820000, - "y": 11, + "y": 20, }, Object { "x": 1627973880000, - "y": 10, + "y": 20, }, Object { "x": 1627973940000, - "y": 10, + "y": 20, }, Object { "x": 1627974000000, - "y": 12, + "y": 20, }, Object { "x": 1627974060000, - "y": 13, + "y": 20, }, Object { "x": 1627974120000, - "y": 8, + "y": 20, }, Object { "x": 1627974180000, - "y": 10, + "y": 20, }, Object { "x": 1627974240000, - "y": 13, + "y": 20, }, Object { "x": 1627974300000, - "y": 9, + "y": 20, }, Object { "x": 1627974360000, - "y": 0, + "y": 20, }, Object { "x": 1627974420000, - "y": 4, + "y": 20, }, Object { "x": 1627974480000, - "y": 5, + "y": 20, }, Object { "x": 1627974540000, - "y": 6, + "y": 20, }, Object { "x": 1627974600000, - "y": 8, + "y": 20, }, Object { "x": 1627974660000, - "y": 5, + "y": 20, }, Object { "x": 1627974720000, - "y": 5, + "y": 20, }, Object { "x": 1627974780000, - "y": 7, + "y": 20, }, Object { "x": 1627974840000, - "y": 2, + "y": 20, }, Object { "x": 1627974900000, - "y": 15, + "y": 20, }, Object { "x": 1627974960000, - "y": 3, + "y": 20, }, Object { "x": 1627975020000, - "y": 8, + "y": 20, }, Object { "x": 1627975080000, - "y": 13, + "y": 20, }, Object { "x": 1627975140000, - "y": 11, + "y": 20, }, Object { "x": 1627975200000, diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/dependencies/index.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/dependencies/index.spec.ts index cb7f81304c3b..a579e196e7aa 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/dependencies/index.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/dependencies/index.spec.ts @@ -4,301 +4,328 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - import expect from '@kbn/expect'; import { last, pick } from 'lodash'; +import { DependencyNode } from '@kbn/apm-plugin/common/connections'; import type { ValuesType } from 'utility-types'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; import { type Node, NodeType } from '@kbn/apm-plugin/common/connections'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED, } from '@kbn/apm-plugin/common/environment_filter_values'; -import type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import { roundNumber } from '../../utils/common'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; +import { roundNumber } from '../../utils/common'; +import { generateDependencyData } from '../generate_data'; import { apmDependenciesMapping, createServiceDependencyDocs } from './es_utils'; export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); const es = getService('es'); - - const { start, end } = { - start: '2021-08-03T06:50:15.910Z', - end: '2021-08-03T07:20:15.910Z', - }; + const start = new Date('2021-01-01T00:00:00.000Z').getTime(); + const end = new Date('2021-01-01T00:15:00.000Z').getTime() - 1; + const dependencyName = 'elasticsearch'; + const serviceName = 'synth-go'; function getName(node: Node) { return node.type === NodeType.service ? node.serviceName : node.dependencyName; } - describe('Service Overview', () => { - describe('Dependencies', () => { - describe('when data is not loaded', () => { - it('handles the empty state', async () => { - const response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, - params: { - path: { serviceName: 'opbeans-java' }, - query: { - start, - end, - numBuckets: 20, - environment: ENVIRONMENT_ALL.value, - }, - }, - }); + async function callApi() { + return await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/services/{serviceName}/dependencies', + params: { + path: { serviceName }, + query: { + environment: 'production', + numBuckets: 20, + offset: '1d', + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, + }, + }); + } - expect(response.status).to.be(200); - expect(response.body.serviceDependencies).to.eql([]); - }); + describe('Dependency for service', () => { + describe('when data is not loaded', () => { + it('handles empty state #1', async () => { + const { status, body } = await callApi(); + + expect(status).to.be(200); + expect(body.serviceDependencies).to.be.empty(); }); + }); - describe('when specific data is loaded', () => { - let response: { - status: number; - body: APIReturnType<'GET /internal/apm/services/{serviceName}/dependencies'>; - }; + describe('when specific data is loaded', () => { + let response: { + status: number; + body: APIReturnType<'GET /internal/apm/services/{serviceName}/dependencies'>; + }; + + const indices = { + metric: 'apm-dependencies-metric', + transaction: 'apm-dependencies-transaction', + span: 'apm-dependencies-span', + }; + + const startTime = new Date(start).getTime(); + const endTime = new Date(end).getTime(); + + after(async () => { + const allIndices = Object.values(indices).join(','); + const indexExists = await es.indices.exists({ index: allIndices }); + if (indexExists) { + await es.indices.delete({ + index: allIndices, + }); + } + }); - const indices = { - metric: 'apm-dependencies-metric', - transaction: 'apm-dependencies-transaction', - span: 'apm-dependencies-span', - }; + before(async () => { + await es.indices.create({ + index: indices.metric, + body: { + mappings: apmDependenciesMapping, + }, + }); - const startTime = new Date(start).getTime(); - const endTime = new Date(end).getTime(); - - after(async () => { - const allIndices = Object.values(indices).join(','); - const indexExists = await es.indices.exists({ index: allIndices }); - if (indexExists) { - await es.indices.delete({ - index: allIndices, - }); - } + await es.indices.create({ + index: indices.transaction, + body: { + mappings: apmDependenciesMapping, + }, }); - before(async () => { - await es.indices.create({ - index: indices.metric, - body: { - mappings: apmDependenciesMapping, - }, - }); + await es.indices.create({ + index: indices.span, + body: { + mappings: apmDependenciesMapping, + }, + }); - await es.indices.create({ - index: indices.transaction, - body: { - mappings: apmDependenciesMapping, + const docs = [ + ...createServiceDependencyDocs({ + service: { + name: 'opbeans-java', + environment: 'production', }, - }); - - await es.indices.create({ - index: indices.span, - body: { - mappings: apmDependenciesMapping, + agentName: 'java', + span: { + type: 'external', + subtype: 'http', }, - }); - - const docs = [ - ...createServiceDependencyDocs({ - service: { - name: 'opbeans-java', - environment: 'production', - }, - agentName: 'java', - span: { - type: 'external', - subtype: 'http', - }, - resource: 'opbeans-node:3000', - outcome: 'success', - responseTime: { - count: 2, - sum: 10, - }, - time: startTime, - to: { - service: { - name: 'opbeans-node', - }, - agentName: 'nodejs', - }, - }), - ...createServiceDependencyDocs({ - service: { - name: 'opbeans-java', - environment: 'production', - }, - agentName: 'java', - span: { - type: 'external', - subtype: 'http', - }, - resource: 'opbeans-node:3000', - outcome: 'failure', - responseTime: { - count: 1, - sum: 10, - }, - time: startTime, - }), - ...createServiceDependencyDocs({ + resource: 'opbeans-node:3000', + outcome: 'success', + responseTime: { + count: 2, + sum: 10, + }, + time: startTime, + to: { service: { - name: 'opbeans-java', - environment: 'production', - }, - agentName: 'java', - span: { - type: 'external', - subtype: 'http', - }, - resource: 'postgres', - outcome: 'success', - responseTime: { - count: 1, - sum: 3, + name: 'opbeans-node', }, - time: startTime, - }), - ...createServiceDependencyDocs({ + agentName: 'nodejs', + }, + }), + ...createServiceDependencyDocs({ + service: { + name: 'opbeans-java', + environment: 'production', + }, + agentName: 'java', + span: { + type: 'external', + subtype: 'http', + }, + resource: 'opbeans-node:3000', + outcome: 'failure', + responseTime: { + count: 1, + sum: 10, + }, + time: startTime, + }), + ...createServiceDependencyDocs({ + service: { + name: 'opbeans-java', + environment: 'production', + }, + agentName: 'java', + span: { + type: 'external', + subtype: 'http', + }, + resource: 'postgres', + outcome: 'success', + responseTime: { + count: 1, + sum: 3, + }, + time: startTime, + }), + ...createServiceDependencyDocs({ + service: { + name: 'opbeans-java', + environment: 'production', + }, + agentName: 'java', + span: { + type: 'external', + subtype: 'http', + }, + resource: 'opbeans-node-via-proxy', + outcome: 'success', + responseTime: { + count: 1, + sum: 1, + }, + time: endTime - 1, + to: { service: { - name: 'opbeans-java', - environment: 'production', - }, - agentName: 'java', - span: { - type: 'external', - subtype: 'http', - }, - resource: 'opbeans-node-via-proxy', - outcome: 'success', - responseTime: { - count: 1, - sum: 1, + name: 'opbeans-node', }, - time: endTime - 1, - to: { - service: { - name: 'opbeans-node', - }, - agentName: 'nodejs', - }, - }), - ]; - - const bulkActions = docs.reduce( - (prev, doc) => { - return [...prev, { index: { _index: indices[doc.processor.event] } }, doc]; + agentName: 'nodejs', }, - [] as Array< - | { - index: { - _index: string; - }; - } - | ValuesType - > - ); - - await es.bulk({ - body: bulkActions, - refresh: 'wait_for', - }); + }), + ]; + + const bulkActions = docs.reduce( + (prev, doc) => { + return [...prev, { index: { _index: indices[doc.processor.event] } }, doc]; + }, + [] as Array< + | { + index: { + _index: string; + }; + } + | ValuesType + > + ); + + await es.bulk({ + body: bulkActions, + refresh: 'wait_for', + }); - response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, - params: { - path: { serviceName: 'opbeans-java' }, - query: { - start, - end, - numBuckets: 20, - environment: ENVIRONMENT_ALL.value, - }, + response = await apmApiClient.readUser({ + endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, + params: { + path: { serviceName: 'opbeans-java' }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + numBuckets: 20, + environment: ENVIRONMENT_ALL.value, }, - }); + }, }); + }); - it('returns a 200', () => { - expect(response.status).to.be(200); - }); + it('returns a 200', () => { + expect(response.status).to.be(200); + }); - it('returns two dependencies', () => { - expect(response.body.serviceDependencies.length).to.be(2); - }); + it('returns two dependencies', () => { + expect(response.body.serviceDependencies.length).to.be(2); + }); - it('returns opbeans-node as a dependency', () => { - const opbeansNode = response.body.serviceDependencies.find( - (item) => getName(item.location) === 'opbeans-node' - ); - - expect(opbeansNode !== undefined).to.be(true); - - const values = { - latency: roundNumber(opbeansNode?.currentStats.latency.value), - throughput: roundNumber(opbeansNode?.currentStats.throughput.value), - errorRate: roundNumber(opbeansNode?.currentStats.errorRate.value), - impact: opbeansNode?.currentStats.impact, - ...pick(opbeansNode?.location, 'serviceName', 'type', 'agentName', 'environment'), - }; - - const count = 4; - const sum = 21; - const errors = 1; - - expect(values).to.eql({ - agentName: 'nodejs', - environment: ENVIRONMENT_NOT_DEFINED.value, - serviceName: 'opbeans-node', - type: 'service', - errorRate: roundNumber(errors / count), - latency: roundNumber(sum / count), - throughput: roundNumber(count / ((endTime - startTime) / 1000 / 60)), - impact: 100, - }); + it('returns opbeans-node as a dependency', () => { + const opbeansNode = response.body.serviceDependencies.find( + (item) => getName(item.location) === 'opbeans-node' + ); - const firstValue = roundNumber(opbeansNode?.currentStats.latency.timeseries[0].y); - const lastValue = roundNumber(last(opbeansNode?.currentStats.latency.timeseries)?.y); + expect(opbeansNode !== undefined).to.be(true); - expect(firstValue).to.be(roundNumber(20 / 3)); - expect(lastValue).to.be(1); + const values = { + latency: roundNumber(opbeansNode?.currentStats.latency.value), + throughput: roundNumber(opbeansNode?.currentStats.throughput.value), + errorRate: roundNumber(opbeansNode?.currentStats.errorRate.value), + impact: opbeansNode?.currentStats.impact, + ...pick(opbeansNode?.location, 'serviceName', 'type', 'agentName', 'environment'), + }; + + const count = 4; + const sum = 21; + const errors = 1; + + expect(values).to.eql({ + agentName: 'nodejs', + environment: ENVIRONMENT_NOT_DEFINED.value, + serviceName: 'opbeans-node', + type: 'service', + errorRate: roundNumber(errors / count), + latency: roundNumber(sum / count), + throughput: roundNumber(count / ((endTime - startTime) / 1000 / 60)), + impact: 100, }); - it('returns postgres as an external dependency', () => { - const postgres = response.body.serviceDependencies.find( - (item) => getName(item.location) === 'postgres' - ); - - expect(postgres !== undefined).to.be(true); - - const values = { - latency: roundNumber(postgres?.currentStats.latency.value), - throughput: roundNumber(postgres?.currentStats.throughput.value), - errorRate: roundNumber(postgres?.currentStats.errorRate.value), - impact: postgres?.currentStats.impact, - ...pick(postgres?.location, 'spanType', 'spanSubtype', 'dependencyName', 'type'), - }; - - const count = 1; - const sum = 3; - const errors = 0; - - expect(values).to.eql({ - spanType: 'external', - spanSubtype: 'http', - dependencyName: 'postgres', - type: 'dependency', - errorRate: roundNumber(errors / count), - latency: roundNumber(sum / count), - throughput: roundNumber(count / ((endTime - startTime) / 1000 / 60)), - impact: 0, - }); + const firstValue = roundNumber(opbeansNode?.currentStats.latency.timeseries[0].y); + const lastValue = roundNumber(last(opbeansNode?.currentStats.latency.timeseries)?.y); + + expect(firstValue).to.be(roundNumber(20 / 3)); + expect(lastValue).to.be(1); + }); + + it('returns postgres as an external dependency', () => { + const postgres = response.body.serviceDependencies.find( + (item) => getName(item.location) === 'postgres' + ); + + expect(postgres !== undefined).to.be(true); + + const values = { + latency: roundNumber(postgres?.currentStats.latency.value), + throughput: roundNumber(postgres?.currentStats.throughput.value), + errorRate: roundNumber(postgres?.currentStats.errorRate.value), + impact: postgres?.currentStats.impact, + ...pick(postgres?.location, 'spanType', 'spanSubtype', 'dependencyName', 'type'), + }; + + const count = 1; + const sum = 3; + const errors = 0; + + expect(values).to.eql({ + spanType: 'external', + spanSubtype: 'http', + dependencyName: 'postgres', + type: 'dependency', + errorRate: roundNumber(errors / count), + latency: roundNumber(sum / count), + throughput: roundNumber(count / ((endTime - startTime) / 1000 / 60)), + impact: 0, }); }); + }); - // UNSUPPORTED TEST CASES - when data is loaded - // TODO: These tests should be migrated to use synthtrace: https://github.com/elastic/kibana/issues/200743 + describe('when data is loaded', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + await generateDependencyData({ apmSynthtraceEsClient, start, end }); + }); + after(() => apmSynthtraceEsClient.clean()); + + it('returns a list of dependencies for a service', async () => { + const { status, body } = await callApi(); + + expect(status).to.be(200); + expect( + body.serviceDependencies.map( + ({ location }) => (location as DependencyNode).dependencyName + ) + ).to.eql([dependencyName]); + + const currentStatsLatencyValues = + body.serviceDependencies[0].currentStats.latency.timeseries; + expect(currentStatsLatencyValues.every(({ y }) => y === 1000000)).to.be(true); + }); }); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/generate_data.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/generate_data.ts new file mode 100644 index 000000000000..150a3ff00fde --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/generate_data.ts @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; + +export const dataConfig = { + rate: 20, + transaction: { + name: 'GET /api/product/list', + duration: 1000, + }, + span: { + name: 'GET apm-*/_search', + type: 'db', + subType: 'elasticsearch', + destination: 'elasticsearch', + }, +} as const; + +export async function generateServiceData({ + apmSynthtraceEsClient, + start, + end, + name, + environment, + agentName, +}: { + apmSynthtraceEsClient: ApmSynthtraceEsClient; + start: number; + end: number; + name: string; + environment: string; + agentName: string; +}) { + const instance = apm.service({ name, environment, agentName }).instance('instance-a'); + const { rate, transaction, span } = dataConfig; + + await apmSynthtraceEsClient.index([ + timerange(start, end) + .interval('1m') + .rate(rate) + .generator((timestamp) => + instance + .transaction({ transactionName: transaction.name }) + .timestamp(timestamp) + .duration(transaction.duration) + .success() + .children( + instance + .span({ spanName: span.name, spanType: span.type, spanSubtype: span.subType }) + .duration(transaction.duration) + .success() + .destination(span.destination) + .timestamp(timestamp) + ) + ), + timerange(start, end) + .interval('1m') + .rate(rate) + .generator((timestamp) => + instance + .appMetrics({ + 'system.process.cpu.total.norm.pct': 0.5, + 'system.memory.total': 120000, + 'system.process.cgroup.memory.mem.usage.bytes': 50000, + }) + .timestamp(timestamp) + ), + ]); +} + +export async function generateDependencyData({ + apmSynthtraceEsClient, + start, + end, +}: { + apmSynthtraceEsClient: ApmSynthtraceEsClient; + start: number; + end: number; +}) { + const instance = apm + .service({ name: 'synth-go', environment: 'production', agentName: 'go' }) + .instance('instance-a'); + const { rate, transaction, span } = dataConfig; + + await apmSynthtraceEsClient.index( + timerange(start, end) + .interval('1m') + .rate(rate) + .generator((timestamp) => + instance + .transaction({ transactionName: transaction.name }) + .timestamp(timestamp) + .duration(transaction.duration) + .success() + .children( + instance + .span({ spanName: span.name, spanType: span.type, spanSubtype: span.subType }) + .duration(transaction.duration) + .success() + .destination(span.destination) + .timestamp(timestamp) + ) + ) + ); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/instances_detailed_statistics.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/instances_detailed_statistics.spec.ts index b2596ae43c95..7fd39b650b71 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/instances_detailed_statistics.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/service_overview/instances_detailed_statistics.spec.ts @@ -6,12 +6,19 @@ */ import expect from '@kbn/expect'; +import moment from 'moment'; +import type { Coordinate } from '@kbn/apm-plugin/typings/timeseries'; import { LatencyAggregationType } from '@kbn/apm-plugin/common/latency_aggregation_types'; +import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import { isFiniteNumber } from '@kbn/apm-plugin/common/utils/is_finite_number'; import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; import { getServiceNodeIds } from './get_service_node_ids'; +import { generateServiceData } from './generate_data'; export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); const serviceName = 'opbeans-java'; @@ -20,6 +27,11 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon end: '2021-08-03T07:20:15.910Z', }; + interface Response { + status: number; + body: APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; + } + describe('Service Overview', () => { describe('Instances detailed statistics', () => { describe('when data is not loaded', () => { @@ -49,8 +61,166 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon }); }); - // UNSUPPORTED TEST CASES - when data is loaded - // TODO: These tests should be migrated to use synthtrace: https://github.com/elastic/kibana/issues/200743 + describe('when data is loaded', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + await generateServiceData({ + apmSynthtraceEsClient, + start: new Date(start).getTime(), + end: new Date(end).getTime(), + name: serviceName, + environment: 'ENVIRONMENT_ALL', + agentName: 'java', + }); + }); + + after(() => apmSynthtraceEsClient.clean()); + + describe('fetching data without comparison', () => { + let response: Response; + let serviceNodeIds: string[]; + + beforeEach(async () => { + serviceNodeIds = await getServiceNodeIds({ + apmApiClient, + start, + end, + }); + + response = await apmApiClient.readUser({ + endpoint: + 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics', + params: { + path: { serviceName }, + query: { + latencyAggregationType: LatencyAggregationType.avg, + start, + end, + numBuckets: 20, + transactionType: 'request', + serviceNodeIds: JSON.stringify(serviceNodeIds), + environment: 'ENVIRONMENT_ALL', + kuery: '', + }, + }, + }); + }); + + it('returns a service node item', () => { + expect(Object.values(response.body.currentPeriod).length).to.be.greaterThan(0); + expect(Object.values(response.body.previousPeriod)).to.eql(0); + }); + + it('returns statistics for each service node', () => { + const item = response.body.currentPeriod[serviceNodeIds[0]]; + + expect(item?.cpuUsage?.some((point) => isFiniteNumber(point.y))).to.be(true); + expect(item?.memoryUsage?.some((point) => isFiniteNumber(point.y))).to.be(true); + expect(item?.errorRate?.some((point) => isFiniteNumber(point.y))).to.be(true); + expect(item?.throughput?.some((point) => isFiniteNumber(point.y))).to.be(true); + expect(item?.latency?.some((point) => isFiniteNumber(point.y))).to.be(true); + }); + + it('returns the right data', () => { + expectSnapshot(Object.values(response.body.currentPeriod).length).toMatchInline(`1`); + + expectSnapshot(Object.keys(response.body.currentPeriod)).toMatchInline(` + Array [ + "instance-a", + ] + `); + + expectSnapshot(response.body).toMatch(); + }); + }); + + describe('fetching data with comparison', () => { + let response: Response; + let serviceNodeIds: string[]; + + beforeEach(async () => { + serviceNodeIds = await getServiceNodeIds({ + apmApiClient, + start, + end, + }); + response = await apmApiClient.readUser({ + endpoint: + 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics', + params: { + path: { serviceName }, + query: { + latencyAggregationType: LatencyAggregationType.avg, + numBuckets: 20, + transactionType: 'request', + serviceNodeIds: JSON.stringify(serviceNodeIds), + start: moment(end).subtract(15, 'minutes').toISOString(), + end, + offset: '15m', + environment: 'ENVIRONMENT_ALL', + kuery: '', + }, + }, + }); + }); + + it('returns a service node item for current and previous periods', () => { + expect(Object.values(response.body.currentPeriod).length).to.be.greaterThan(0); + expect(Object.values(response.body.previousPeriod).length).to.be.greaterThan(0); + }); + + it('returns statistics for current and previous periods', () => { + const currentPeriodItem = response.body.currentPeriod[serviceNodeIds[0]]; + + function hasValidYCoordinate(point: Coordinate) { + return isFiniteNumber(point.y); + } + + expect(currentPeriodItem?.cpuUsage?.some(hasValidYCoordinate)).to.be(true); + expect(currentPeriodItem?.memoryUsage?.some(hasValidYCoordinate)).to.be(true); + expect(currentPeriodItem?.errorRate?.some(hasValidYCoordinate)).to.be(true); + expect(currentPeriodItem?.throughput?.some(hasValidYCoordinate)).to.be(true); + expect(currentPeriodItem?.latency?.some(hasValidYCoordinate)).to.be(true); + + const previousPeriodItem = response.body.previousPeriod[serviceNodeIds[0]]; + + expect(previousPeriodItem?.cpuUsage?.some(hasValidYCoordinate)).to.be(true); + expect(previousPeriodItem?.memoryUsage?.some(hasValidYCoordinate)).to.be(true); + expect(previousPeriodItem?.errorRate?.some(hasValidYCoordinate)).to.be(true); + expect(previousPeriodItem?.throughput?.some(hasValidYCoordinate)).to.be(true); + expect(previousPeriodItem?.latency?.some(hasValidYCoordinate)).to.be(true); + }); + + it('returns the right data for current and previous periods', () => { + expectSnapshot(Object.values(response.body.currentPeriod).length).toMatchInline(`1`); + expectSnapshot(Object.values(response.body.previousPeriod).length).toMatchInline(`1`); + + expectSnapshot(Object.keys(response.body.currentPeriod)).toMatchInline(` + Array [ + "instance-a", + ] + `); + expectSnapshot(Object.keys(response.body.previousPeriod)).toMatchInline(` + Array [ + "instance-a", + ] + `); + + expectSnapshot(response.body).toMatch(); + }); + + it('matches x-axis on current period and previous period', () => { + const currentLatencyItems = response.body.currentPeriod[serviceNodeIds[0]]?.latency; + const previousLatencyItems = response.body.previousPeriod[serviceNodeIds[0]]?.latency; + + expect(currentLatencyItems?.map(({ x }) => x)).to.be.eql( + previousLatencyItems?.map(({ x }) => x) + ); + }); + }); + }); }); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/latency.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/latency.spec.ts index f369bc63ca4e..df72ca433340 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/latency.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/latency.spec.ts @@ -58,6 +58,14 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon } describe('Latency', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + }); + + after(() => apmSynthtraceEsClient.clean()); + describe('when data is not loaded ', () => { it('handles the empty state', async () => { const response = await fetchLatencyCharts(); @@ -75,10 +83,8 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon const GO_DEV_RATE = 20; const GO_PROD_DURATION = 1000; const GO_DEV_DURATION = 500; - let apmSynthtraceEsClient: ApmSynthtraceEsClient; before(async () => { - apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); const serviceGoProdInstance = apm .service({ name: serviceName, environment: 'production', agentName: 'go' }) .instance('instance-a'); @@ -86,7 +92,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon .service({ name: serviceName, environment: 'development', agentName: 'go' }) .instance('instance-b'); - await apmSynthtraceEsClient.index([ + return apmSynthtraceEsClient.index([ timerange(start, end) .ratePerMinute(GO_PROD_RATE) .generator((timestamp) => diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_alerts.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_alerts.spec.ts index 6abefb559bc2..7fd74d0efc6b 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_alerts.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/transactions/transactions_groups_alerts.spec.ts @@ -73,7 +73,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon return response.body as TransactionsGroupsMainStatistics; } - describe('Transaction groups alerts', () => { + describe('Transaction groups alerts', function () { describe('when data is loaded', () => { const transactions = [ { @@ -108,6 +108,7 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon before(async () => { roleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + await apmSynthtraceEsClient.clean(); const serviceGoProdInstance = apm .service({ name: serviceName, environment: 'production', agentName: 'go' }) .instance('instance-a'); @@ -150,6 +151,13 @@ export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderCon let alerts: Alerts; before(async () => { + await alertingApi.cleanUpAlerts({ + alertIndexName: APM_ALERTS_INDEX, + connectorIndexName: APM_ACTION_VARIABLE_INDEX, + consumer: 'apm', + roleAuthc, + }); + const createdRule = await alertingApi.createRule({ name: `Latency threshold | ${serviceName}`, params: { diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/check_and_load_integration.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/check_and_load_integration.ts new file mode 100644 index 000000000000..801b5cde5883 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/check_and_load_integration.ts @@ -0,0 +1,175 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { log, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; + +import { LogsSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import { DeploymentAgnosticFtrProviderContext } from '../../../ftr_provider_context'; +import { RoleCredentials, SupertestWithRoleScopeType } from '../../../services'; + +export default function ({ getService }: DeploymentAgnosticFtrProviderContext) { + const samlAuth = getService('samlAuth'); + const roleScopedSupertest = getService('roleScopedSupertest'); + const synthtrace = getService('synthtrace'); + const packageApi = getService('packageApi'); + const start = '2024-11-04T11:00:00.000Z'; + const end = '2024-11-04T11:01:00.000Z'; + const type = 'logs'; + const dataset = 'synth'; + const nginxDataset = 'nginx.access'; + const apmDataset = 'apm.app.test'; + const namespace = 'default'; + const serviceName = 'my-service'; + const hostName = 'synth-host'; + const dataStreamName = `${type}-${dataset}-${namespace}`; + const nginxDataStreamName = `${type}-${nginxDataset}-${namespace}`; + const apmAppDataStreamName = `${type}-${apmDataset}-${namespace}`; + + const pkg = 'nginx'; + + async function callApiAs({ + roleScopedSupertestWithCookieCredentials, + apiParams: { dataStream }, + }: { + roleScopedSupertestWithCookieCredentials: SupertestWithRoleScopeType; + apiParams: { + dataStream: string; + }; + }) { + return roleScopedSupertestWithCookieCredentials.get( + `/internal/dataset_quality/data_streams/${dataStream}/integration/check` + ); + } + + describe('Check and load integrations', function () { + let adminRoleAuthc: RoleCredentials; + let supertestAdminWithCookieCredentials: SupertestWithRoleScopeType; + let synthtraceLogsEsClient: LogsSynthtraceEsClient; + + before(async () => { + synthtraceLogsEsClient = await synthtrace.createLogsSynthtraceEsClient(); + adminRoleAuthc = await samlAuth.createM2mApiKeyWithRoleScope('admin'); + supertestAdminWithCookieCredentials = await roleScopedSupertest.getSupertestWithRoleScope( + 'admin', + { + useCookieHeader: true, + withInternalHeaders: true, + } + ); + // Install nginx package + await packageApi.installPackage({ + roleAuthc: adminRoleAuthc, + pkg, + }); + + await synthtraceLogsEsClient.index([ + // Ingest degraded data in Nginx data stream + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(nginxDataset) + .namespace(namespace) + .defaults({ + 'log.file.path': '/my-service.log', + 'service.name': serviceName, + 'host.name': hostName, + }) + ), + // ingest data in apm app data stream + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(apmDataset) + .namespace(namespace) + .defaults({ + 'log.file.path': '/my-service.log', + 'service.name': serviceName, + 'host.name': hostName, + }) + ), + + // Ingest data in regular datastream which is not an integration + timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => + log + .create() + .message('This is a log message') + .timestamp(timestamp) + .dataset(dataset) + .namespace(namespace) + .defaults({ + 'log.file.path': '/my-service.log', + 'service.name': serviceName, + 'host.name': hostName, + }) + ), + ]); + }); + + after(async () => { + await synthtraceLogsEsClient.clean(); + await packageApi.uninstallPackage({ + roleAuthc: adminRoleAuthc, + pkg, + }); + await samlAuth.invalidateM2mApiKeyWithRoleScope(adminRoleAuthc); + }); + + describe('returns integration status', () => { + it('returns integration as false for regular data stream', async () => { + const resp = await callApiAs({ + roleScopedSupertestWithCookieCredentials: supertestAdminWithCookieCredentials, + apiParams: { + dataStream: dataStreamName, + }, + }); + + expect(resp.body.isIntegration).to.be(false); + expect(resp.body.areAssetsAvailable).to.be(false); + }); + + it('returns integration as true for nginx data stream as we installed the integration', async () => { + const resp = await callApiAs({ + roleScopedSupertestWithCookieCredentials: supertestAdminWithCookieCredentials, + apiParams: { + dataStream: nginxDataStreamName, + }, + }); + + expect(resp.body.isIntegration).to.be(true); + expect(resp.body.areAssetsAvailable).to.be(true); + expect(resp.body.integration.name).to.be(pkg); + expect(resp.body.integration.datasets[nginxDataset]).to.be.a('string'); + }); + + it('returns integration as false but assets are available for apm.app data stream as its preinstalled', async () => { + const resp = await callApiAs({ + roleScopedSupertestWithCookieCredentials: supertestAdminWithCookieCredentials, + apiParams: { + dataStream: apmAppDataStreamName, + }, + }); + + expect(resp.body.isIntegration).to.be(false); + expect(resp.body.areAssetsAvailable).to.be(true); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/index.ts index 0481e882aee6..17ce93321b51 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/dataset_quality/index.ts @@ -14,6 +14,7 @@ export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) loadTestFile(require.resolve('./data_stream_settings')); loadTestFile(require.resolve('./data_stream_rollover')); loadTestFile(require.resolve('./update_field_limit')); + loadTestFile(require.resolve('./check_and_load_integration')); loadTestFile(require.resolve('./data_stream_total_docs')); loadTestFile(require.resolve('./degraded_docs')); loadTestFile(require.resolve('./degraded_fields')); diff --git a/x-pack/test/api_integration/deployment_agnostic/services/alerting_api.ts b/x-pack/test/api_integration/deployment_agnostic/services/alerting_api.ts index ee1047d6024c..d6660581938f 100644 --- a/x-pack/test/api_integration/deployment_agnostic/services/alerting_api.ts +++ b/x-pack/test/api_integration/deployment_agnostic/services/alerting_api.ts @@ -1141,7 +1141,7 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide .set(samlAuth.getInternalRequestHeader()); }, - async deleteRules({ roleAuthc, filter }: { roleAuthc: RoleCredentials; filter: string }) { + async deleteRules({ roleAuthc, filter = '' }: { roleAuthc: RoleCredentials; filter?: string }) { const response = await this.searchRules(roleAuthc, filter); return Promise.all( response.body.data.map((rule: any) => this.deleteRuleById({ roleAuthc, ruleId: rule.id })) @@ -1186,14 +1186,14 @@ export function AlertingApiProvider({ getService }: DeploymentAgnosticFtrProvide connectorIndexName, }: { roleAuthc: RoleCredentials; - ruleId: string; + ruleId?: string; consumer?: string; alertIndexName?: string; connectorIndexName?: string; }) { return Promise.allSettled([ // Delete the rule by ID - this.deleteRuleById({ roleAuthc, ruleId }), + ruleId ? this.deleteRuleById({ roleAuthc, ruleId }) : this.deleteRules({ roleAuthc }), // Delete all documents in the alert index if specified alertIndexName ? es.deleteByQuery({ diff --git a/x-pack/test/api_integration/services/security_solution_api.gen.ts b/x-pack/test/api_integration/services/security_solution_api.gen.ts index 3574199709ae..a0b1bf74926b 100644 --- a/x-pack/test/api_integration/services/security_solution_api.gen.ts +++ b/x-pack/test/api_integration/services/security_solution_api.gen.ts @@ -80,7 +80,7 @@ import { GetEndpointSuggestionsRequestBodyInput, } from '@kbn/security-solution-plugin/common/api/endpoint/suggestions/get_suggestions.gen'; import { GetEntityEngineRequestParamsInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/engine/get.gen'; -import { GetEntityEngineStatsRequestParamsInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/engine/stats.gen'; +import { GetEntityStoreStatusRequestQueryInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/status.gen'; import { GetNotesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/timeline/get_notes/get_notes_route.gen'; import { GetPolicyResponseRequestQueryInput } from '@kbn/security-solution-plugin/common/api/endpoint/policy/policy_response.gen'; import { GetProtectionUpdatesNoteRequestParamsInput } from '@kbn/security-solution-plugin/common/api/endpoint/protection_updates_note/protection_updates_note.gen'; @@ -106,8 +106,13 @@ import { InitEntityEngineRequestParamsInput, InitEntityEngineRequestBodyInput, } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/engine/init.gen'; -import { InitEntityStoreRequestBodyInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/enablement.gen'; +import { InitEntityStoreRequestBodyInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/enable.gen'; +import { + InstallMigrationRulesRequestParamsInput, + InstallMigrationRulesRequestBodyInput, +} from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; import { InstallPrepackedTimelinesRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/install_prepackaged_timelines/install_prepackaged_timelines_route.gen'; +import { InstallTranslatedMigrationRulesRequestParamsInput } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen'; import { ListEntitiesRequestQueryInput } from '@kbn/security-solution-plugin/common/api/entity_analytics/entity_store/entities/list_entities.gen'; import { PatchRuleRequestBodyInput } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen'; import { PatchTimelineRequestBodyInput } from '@kbn/security-solution-plugin/common/api/timeline/patch_timelines/patch_timeline_route.gen'; @@ -832,24 +837,13 @@ finalize it. .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, - getEntityEngineStats(props: GetEntityEngineStatsProps, kibanaSpace: string = 'default') { - return supertest - .post( - routeWithNamespace( - replaceParams('/api/entity_store/engines/{entityType}/stats', props.params), - kibanaSpace - ) - ) - .set('kbn-xsrf', 'true') - .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); - }, - getEntityStoreStatus(kibanaSpace: string = 'default') { + getEntityStoreStatus(props: GetEntityStoreStatusProps, kibanaSpace: string = 'default') { return supertest .get(routeWithNamespace('/api/entity_store/status', kibanaSpace)) .set('kbn-xsrf', 'true') .set(ELASTIC_HTTP_VERSION_HEADER, '2023-10-31') - .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .query(props.query); }, /** * Get all notes for a given document. @@ -1057,6 +1051,22 @@ finalize it. .set(ELASTIC_HTTP_VERSION_HEADER, '1') .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); }, + /** + * Installs migration rules + */ + installMigrationRules(props: InstallMigrationRulesProps, kibanaSpace: string = 'default') { + return supertest + .post( + routeWithNamespace( + replaceParams('/internal/siem_migrations/rules/{migration_id}/install', props.params), + kibanaSpace + ) + ) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') + .send(props.body as object); + }, /** * Install and update all Elastic prebuilt detection rules and Timelines. */ @@ -1081,6 +1091,27 @@ finalize it. .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana') .send(props.body as object); }, + /** + * Installs all translated migration rules + */ + installTranslatedMigrationRules( + props: InstallTranslatedMigrationRulesProps, + kibanaSpace: string = 'default' + ) { + return supertest + .post( + routeWithNamespace( + replaceParams( + '/internal/siem_migrations/rules/{migration_id}/install_translated', + props.params + ), + kibanaSpace + ) + ) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, '1') + .set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana'); + }, internalUploadAssetCriticalityRecords(kibanaSpace: string = 'default') { return supertest .post(routeWithNamespace('/internal/asset_criticality/upload_csv', kibanaSpace)) @@ -1615,8 +1646,8 @@ export interface GetEndpointSuggestionsProps { export interface GetEntityEngineProps { params: GetEntityEngineRequestParamsInput; } -export interface GetEntityEngineStatsProps { - params: GetEntityEngineStatsRequestParamsInput; +export interface GetEntityStoreStatusProps { + query: GetEntityStoreStatusRequestQueryInput; } export interface GetNotesProps { query: GetNotesRequestQueryInput; @@ -1664,9 +1695,16 @@ export interface InitEntityEngineProps { export interface InitEntityStoreProps { body: InitEntityStoreRequestBodyInput; } +export interface InstallMigrationRulesProps { + params: InstallMigrationRulesRequestParamsInput; + body: InstallMigrationRulesRequestBodyInput; +} export interface InstallPrepackedTimelinesProps { body: InstallPrepackedTimelinesRequestBodyInput; } +export interface InstallTranslatedMigrationRulesProps { + params: InstallTranslatedMigrationRulesRequestParamsInput; +} export interface ListEntitiesProps { query: ListEntitiesRequestQueryInput; } diff --git a/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.spec.ts b/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.spec.ts deleted file mode 100644 index fd06ee9f9526..000000000000 --- a/x-pack/test/apm_api_integration/tests/service_overview/dependencies/index.spec.ts +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import { omit, sortBy } from 'lodash'; -import { type Node, NodeType } from '@kbn/apm-plugin/common/connections'; -import { ENVIRONMENT_ALL } from '@kbn/apm-plugin/common/environment_filter_values'; -import type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import archives from '../../../common/fixtures/es_archiver/archives_metadata'; -import type { FtrProviderContext } from '../../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - - const archiveName = 'apm_8.0.0'; - const { start, end } = archives[archiveName]; - - function getName(node: Node) { - return node.type === NodeType.service ? node.serviceName : node.dependencyName; - } - - registry.when( - 'Service overview dependencies when data is loaded', - { config: 'basic', archives: [archiveName] }, - () => { - let response: { - status: number; - body: APIReturnType<'GET /internal/apm/services/{serviceName}/dependencies'>; - }; - - before(async () => { - response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/services/{serviceName}/dependencies`, - params: { - path: { serviceName: 'opbeans-python' }, - query: { - start, - end, - numBuckets: 20, - environment: ENVIRONMENT_ALL.value, - }, - }, - }); - }); - - it('returns a successful response', () => { - expect(response.status).to.be(200); - }); - - it('returns at least one item', () => { - expect(response.body.serviceDependencies.length).to.be.greaterThan(0); - - expectSnapshot(response.body.serviceDependencies.length).toMatchInline(`4`); - - const { currentStats, ...firstItem } = sortBy( - response.body.serviceDependencies, - 'currentStats.impact' - ).reverse()[0]; - - expectSnapshot(firstItem.location).toMatchInline(` - Object { - "agentName": "dotnet", - "dependencyName": "opbeans:3000", - "environment": "production", - "id": "5948c153c2d8989f92a9c75ef45bb845f53e200d", - "serviceName": "opbeans-dotnet", - "type": "service", - } - `); - - expectSnapshot( - omit(currentStats, [ - 'errorRate.timeseries', - 'throughput.timeseries', - 'latency.timeseries', - 'totalTime.timeseries', - ]) - ).toMatchInline(` - Object { - "errorRate": Object { - "value": 0.163636363636364, - }, - "impact": 100, - "latency": Object { - "value": 1117085.74545455, - }, - "throughput": Object { - "value": 1.83333333333333, - }, - "totalTime": Object { - "value": 61439716, - }, - } - `); - }); - - it('returns the right names', () => { - const names = response.body.serviceDependencies.map((item) => getName(item.location)); - expectSnapshot(names.sort()).toMatchInline(` - Array [ - "elasticsearch", - "opbeans-dotnet", - "postgresql", - "redis", - ] - `); - }); - - it('returns the right service names', () => { - const serviceNames = response.body.serviceDependencies - .map((item) => - item.location.type === NodeType.service ? getName(item.location) : undefined - ) - .filter(Boolean); - - expectSnapshot(serviceNames.sort()).toMatchInline(` - Array [ - "opbeans-dotnet", - ] - `); - }); - - it('returns the right latency values', () => { - const latencyValues = sortBy( - response.body.serviceDependencies.map((item) => ({ - name: getName(item.location), - latency: item.currentStats.latency.value, - })), - 'name' - ); - - expectSnapshot(latencyValues).toMatchInline(` - Array [ - Object { - "latency": 9496.32291666667, - "name": "elasticsearch", - }, - Object { - "latency": 1117085.74545455, - "name": "opbeans-dotnet", - }, - Object { - "latency": 27826.9968314322, - "name": "postgresql", - }, - Object { - "latency": 1468.27242524917, - "name": "redis", - }, - ] - `); - }); - - it('returns the right throughput values', () => { - const throughputValues = sortBy( - response.body.serviceDependencies.map((item) => ({ - name: getName(item.location), - throughput: item.currentStats.throughput.value, - })), - 'name' - ); - - expectSnapshot(throughputValues).toMatchInline(` - Array [ - Object { - "name": "elasticsearch", - "throughput": 3.2, - }, - Object { - "name": "opbeans-dotnet", - "throughput": 1.83333333333333, - }, - Object { - "name": "postgresql", - "throughput": 52.6, - }, - Object { - "name": "redis", - "throughput": 40.1333333333333, - }, - ] - `); - }); - - it('returns the right impact values', () => { - const impactValues = sortBy( - response.body.serviceDependencies.map((item) => ({ - name: getName(item.location), - impact: item.currentStats.impact, - })), - 'name' - ); - - expectSnapshot(impactValues).toMatchInline(` - Array [ - Object { - "impact": 0, - "name": "elasticsearch", - }, - Object { - "impact": 100, - "name": "opbeans-dotnet", - }, - Object { - "impact": 71.0403531954737, - "name": "postgresql", - }, - Object { - "impact": 1.41447268043525, - "name": "redis", - }, - ] - `); - }); - - it('returns the right totalTime values', () => { - const totalTimeValues = sortBy( - response.body.serviceDependencies.map((item) => ({ - name: getName(item.location), - totalTime: item.currentStats.totalTime.value, - })), - 'name' - ); - - expectSnapshot(totalTimeValues).toMatchInline(` - Array [ - Object { - "name": "elasticsearch", - "totalTime": 911647, - }, - Object { - "name": "opbeans-dotnet", - "totalTime": 61439716, - }, - Object { - "name": "postgresql", - "totalTime": 43911001, - }, - Object { - "name": "redis", - "totalTime": 1767800, - }, - ] - `); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts b/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts deleted file mode 100644 index 751f772fb750..000000000000 --- a/x-pack/test/apm_api_integration/tests/service_overview/get_service_node_ids.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import { take } from 'lodash'; -import { LatencyAggregationType } from '@kbn/apm-plugin/common/latency_aggregation_types'; -import type { ApmServices } from '../../common/config'; - -export async function getServiceNodeIds({ - apmApiClient, - start, - end, - serviceName = 'opbeans-java', - count = 1, -}: { - apmApiClient: Awaited>; - start: string; - end: string; - serviceName?: string; - count?: number; -}) { - const { body } = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/services/{serviceName}/service_overview_instances/main_statistics`, - params: { - path: { serviceName }, - query: { - latencyAggregationType: LatencyAggregationType.avg, - start, - end, - transactionType: 'request', - environment: 'ENVIRONMENT_ALL', - kuery: '', - sortField: 'throughput', - sortDirection: 'desc', - }, - }, - }); - - return take(body.currentPeriod.map((item) => item.serviceNodeName).sort(), count); -} diff --git a/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.spec.ts b/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.spec.ts deleted file mode 100644 index af28697a254c..000000000000 --- a/x-pack/test/apm_api_integration/tests/service_overview/instances_detailed_statistics.spec.ts +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; -import moment from 'moment'; -import type { Coordinate } from '@kbn/apm-plugin/typings/timeseries'; -import { LatencyAggregationType } from '@kbn/apm-plugin/common/latency_aggregation_types'; -import { isFiniteNumber } from '@kbn/apm-plugin/common/utils/is_finite_number'; -import type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import type { FtrProviderContext } from '../../common/ftr_provider_context'; -import archives from '../../common/fixtures/es_archiver/archives_metadata'; -import { getServiceNodeIds } from './get_service_node_ids'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - - const serviceName = 'opbeans-java'; - const archiveName = 'apm_8.0.0'; - const { start, end } = archives[archiveName]; - - interface Response { - status: number; - body: APIReturnType<'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics'>; - } - - registry.when( - 'Service overview instances detailed statistics when data is loaded', - { config: 'basic', archives: [archiveName] }, - () => { - describe('fetching data without comparison', () => { - let response: Response; - let serviceNodeIds: string[]; - - beforeEach(async () => { - serviceNodeIds = await getServiceNodeIds({ - apmApiClient, - start, - end, - }); - - response = await apmApiClient.readUser({ - endpoint: - 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics', - params: { - path: { serviceName }, - query: { - latencyAggregationType: LatencyAggregationType.avg, - start, - end, - numBuckets: 20, - transactionType: 'request', - serviceNodeIds: JSON.stringify(serviceNodeIds), - environment: 'ENVIRONMENT_ALL', - kuery: '', - }, - }, - }); - }); - - it('returns a service node item', () => { - expect(Object.values(response.body.currentPeriod).length).to.be.greaterThan(0); - expect(Object.values(response.body.previousPeriod)).to.eql(0); - }); - - it('returns statistics for each service node', async () => { - const item = response.body.currentPeriod[serviceNodeIds[0]]; - - expect(item?.cpuUsage?.some((point) => isFiniteNumber(point.y))).to.be(true); - expect(item?.memoryUsage?.some((point) => isFiniteNumber(point.y))).to.be(true); - expect(item?.errorRate?.some((point) => isFiniteNumber(point.y))).to.be(true); - expect(item?.throughput?.some((point) => isFiniteNumber(point.y))).to.be(true); - expect(item?.latency?.some((point) => isFiniteNumber(point.y))).to.be(true); - }); - - it('returns the right data', () => { - expectSnapshot(Object.values(response.body.currentPeriod).length).toMatchInline(`1`); - - expectSnapshot(Object.keys(response.body.currentPeriod)).toMatchInline(` - Array [ - "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad", - ] - `); - - expectSnapshot(response.body).toMatch(); - }); - }); - - describe('fetching data with comparison', () => { - let response: Response; - let serviceNodeIds: string[]; - - beforeEach(async () => { - serviceNodeIds = await getServiceNodeIds({ - apmApiClient, - start, - end, - }); - response = await apmApiClient.readUser({ - endpoint: - 'GET /internal/apm/services/{serviceName}/service_overview_instances/detailed_statistics', - params: { - path: { serviceName }, - query: { - latencyAggregationType: LatencyAggregationType.avg, - numBuckets: 20, - transactionType: 'request', - serviceNodeIds: JSON.stringify(serviceNodeIds), - start: moment(end).subtract(15, 'minutes').toISOString(), - end, - offset: '15m', - environment: 'ENVIRONMENT_ALL', - kuery: '', - }, - }, - }); - }); - - it('returns a service node item for current and previous periods', () => { - expect(Object.values(response.body.currentPeriod).length).to.be.greaterThan(0); - expect(Object.values(response.body.previousPeriod).length).to.be.greaterThan(0); - }); - - it('returns statistics for current and previous periods', () => { - const currentPeriodItem = response.body.currentPeriod[serviceNodeIds[0]]; - - function hasValidYCoordinate(point: Coordinate) { - return isFiniteNumber(point.y); - } - - expect(currentPeriodItem?.cpuUsage?.some(hasValidYCoordinate)).to.be(true); - expect(currentPeriodItem?.memoryUsage?.some(hasValidYCoordinate)).to.be(true); - expect(currentPeriodItem?.errorRate?.some(hasValidYCoordinate)).to.be(true); - expect(currentPeriodItem?.throughput?.some(hasValidYCoordinate)).to.be(true); - expect(currentPeriodItem?.latency?.some(hasValidYCoordinate)).to.be(true); - - const previousPeriodItem = response.body.previousPeriod[serviceNodeIds[0]]; - - expect(previousPeriodItem?.cpuUsage?.some(hasValidYCoordinate)).to.be(true); - expect(previousPeriodItem?.memoryUsage?.some(hasValidYCoordinate)).to.be(true); - expect(previousPeriodItem?.errorRate?.some(hasValidYCoordinate)).to.be(true); - expect(previousPeriodItem?.throughput?.some(hasValidYCoordinate)).to.be(true); - expect(previousPeriodItem?.latency?.some(hasValidYCoordinate)).to.be(true); - }); - - it('returns the right data for current and previous periods', () => { - expectSnapshot(Object.values(response.body.currentPeriod).length).toMatchInline(`1`); - expectSnapshot(Object.values(response.body.previousPeriod).length).toMatchInline(`1`); - - expectSnapshot(Object.keys(response.body.currentPeriod)).toMatchInline(` - Array [ - "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad", - ] - `); - expectSnapshot(Object.keys(response.body.previousPeriod)).toMatchInline(` - Array [ - "31651f3c624b81c55dd4633df0b5b9f9ab06b151121b0404ae796632cd1f87ad", - ] - `); - - expectSnapshot(response.body).toMatch(); - }); - - it('matches x-axis on current period and previous period', () => { - const currentLatencyItems = response.body.currentPeriod[serviceNodeIds[0]]?.latency; - const previousLatencyItems = response.body.previousPeriod[serviceNodeIds[0]]?.latency; - - expect(currentLatencyItems?.map(({ x }) => x)).to.be.eql( - previousLatencyItems?.map(({ x }) => x) - ); - }); - }); - } - ); -} diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/metrics/get_cases_metrics.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/metrics/get_cases_metrics.ts index f7089db84985..ca4e6414c0df 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/metrics/get_cases_metrics.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/common/internal/metrics/get_cases_metrics.ts @@ -25,7 +25,7 @@ import { getCasesMetrics, updateCase, } from '../../../../../common/lib/api'; -import { getPostCaseRequest } from '../../../../../common/lib/mock'; +import { getPostCaseRequest, postCaseReq } from '../../../../../common/lib/mock'; // eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext): void => { @@ -42,8 +42,6 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(metrics).to.eql({ mttr: null }); - - await deleteAllCaseItems(es); }); describe(CaseMetricsFeature.MTTR, () => { @@ -79,6 +77,8 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(metrics).to.eql({ mttr: null }); + + await deleteAllCaseItems(es); }); describe('closed and open cases from kbn archive', () => { @@ -92,6 +92,7 @@ export default ({ getService }: FtrProviderContext): void => { await kibanaServer.importExport.unload( 'x-pack/test/functional/fixtures/kbn_archiver/cases/8.3.0/all_cases_metrics.json' ); + await deleteAllCaseItems(es); }); @@ -119,6 +120,62 @@ export default ({ getService }: FtrProviderContext): void => { }); }); + describe(CaseMetricsFeature.STATUS, () => { + it('responses with zeros if there are no cases', async () => { + const metrics = await getCasesMetrics({ + supertest, + features: [CaseMetricsFeature.STATUS], + }); + + expect(metrics).to.eql({ + status: { + closed: 0, + inProgress: 0, + open: 0, + }, + }); + }); + + it('should return case statuses', async () => { + const [, inProgressCase, postedCase] = await Promise.all([ + createCase(supertest, postCaseReq), + createCase(supertest, postCaseReq), + createCase(supertest, postCaseReq), + ]); + + await updateCase({ + supertest, + params: { + cases: [ + { + id: inProgressCase.id, + version: inProgressCase.version, + status: CaseStatuses['in-progress'], + }, + { + id: postedCase.id, + version: postedCase.version, + status: CaseStatuses.closed, + }, + ], + }, + }); + + const metrics = await getCasesMetrics({ + supertest, + features: [CaseMetricsFeature.STATUS], + }); + + expect(metrics.status).to.eql({ + open: 1, + inProgress: 1, + closed: 1, + }); + + await deleteAllCaseItems(es); + }); + }); + describe('rbac', () => { before(async () => { await kibanaServer.importExport.load( @@ -132,6 +189,7 @@ export default ({ getService }: FtrProviderContext): void => { 'x-pack/test/functional/fixtures/kbn_archiver/cases/8.3.0/all_cases_metrics.json', { space: 'space1' } ); + await deleteAllCaseItems(es); }); @@ -139,29 +197,68 @@ export default ({ getService }: FtrProviderContext): void => { for (const scenario of [ { user: globalRead, - expectedMetrics: { mttr: 220 }, + expectedMetrics: { + mttr: 220, + status: { + closed: 3, + inProgress: 0, + open: 1, + }, + }, owners: ['securitySolutionFixture', 'observabilityFixture'], }, { user: superUser, - expectedMetrics: { mttr: 220 }, + expectedMetrics: { + mttr: 220, + status: { + closed: 3, + inProgress: 0, + open: 1, + }, + }, owners: ['securitySolutionFixture', 'observabilityFixture'], }, { user: secOnlyRead, - expectedMetrics: { mttr: 250 }, + expectedMetrics: { + mttr: 250, + status: { + closed: 2, + inProgress: 0, + open: 1, + }, + }, owners: ['securitySolutionFixture'], }, - { user: obsOnlyRead, expectedMetrics: { mttr: 160 }, owners: ['observabilityFixture'] }, + { + user: obsOnlyRead, + expectedMetrics: { + mttr: 160, + status: { + closed: 1, + inProgress: 0, + open: 0, + }, + }, + owners: ['observabilityFixture'], + }, { user: obsSecRead, - expectedMetrics: { mttr: 220 }, + expectedMetrics: { + mttr: 220, + status: { + closed: 3, + inProgress: 0, + open: 1, + }, + }, owners: ['securitySolutionFixture', 'observabilityFixture'], }, ]) { const metrics = await getCasesMetrics({ supertest: supertestWithoutAuth, - features: [CaseMetricsFeature.MTTR], + features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS], auth: { user: scenario.user, space: 'space1', @@ -182,7 +279,7 @@ export default ({ getService }: FtrProviderContext): void => { // user should not be able to read cases at the appropriate space await getCasesMetrics({ supertest: supertestWithoutAuth, - features: [CaseMetricsFeature.MTTR], + features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS], auth: { user: scenario.user, space: scenario.space, @@ -195,7 +292,7 @@ export default ({ getService }: FtrProviderContext): void => { it('should respect the owner filter when having permissions', async () => { const metrics = await getCasesMetrics({ supertest: supertestWithoutAuth, - features: [CaseMetricsFeature.MTTR], + features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS], query: { owner: 'securitySolutionFixture', }, @@ -205,13 +302,20 @@ export default ({ getService }: FtrProviderContext): void => { }, }); - expect(metrics).to.eql({ mttr: 250 }); + expect(metrics).to.eql({ + mttr: 250, + status: { + closed: 2, + inProgress: 0, + open: 1, + }, + }); }); it('should return the correct cases when trying to exploit RBAC through the owner query parameter', async () => { const metrics = await getCasesMetrics({ supertest: supertestWithoutAuth, - features: [CaseMetricsFeature.MTTR], + features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS], query: { owner: ['securitySolutionFixture', 'observabilityFixture'], }, @@ -221,13 +325,20 @@ export default ({ getService }: FtrProviderContext): void => { }, }); - expect(metrics).to.eql({ mttr: 250 }); + expect(metrics).to.eql({ + mttr: 250, + status: { + closed: 2, + inProgress: 0, + open: 1, + }, + }); }); it('should respect the owner filter when using range queries', async () => { const metrics = await getCasesMetrics({ supertest: supertestWithoutAuth, - features: [CaseMetricsFeature.MTTR], + features: [CaseMetricsFeature.MTTR, CaseMetricsFeature.STATUS], query: { from: '2022-04-20', to: '2022-04-30', @@ -238,7 +349,14 @@ export default ({ getService }: FtrProviderContext): void => { }, }); - expect(metrics).to.eql({ mttr: 250 }); + expect(metrics).to.eql({ + mttr: 250, + status: { + closed: 2, + inProgress: 0, + open: 0, + }, + }); }); }); }); diff --git a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts index 0969a9261df2..bc618b1beab4 100644 --- a/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts +++ b/x-pack/test/cases_api_integration/security_and_spaces/tests/trial/attachments_framework/registered_persistable_state_trial.ts @@ -40,6 +40,7 @@ export default ({ getService }: FtrProviderContext): void => { ml_anomaly_swimlane: 'a3517f3e53fb041e9cbb150477fb6ef0f731bd5f', ml_single_metric_viewer: '8b9532b0a40dfdfa282e262949b82cc1a643147c', aiopsPatternAnalysisEmbeddable: '6c2809a0c51e668d11794de0815b293fdb3a9060', + aiopsLogRateAnalysisEmbeddable: '6a2e9953140fa8e89f82c394d8bff3c1a5aefe66', }); }); }); diff --git a/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts b/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts index 2065d1307fbd..c831070f4439 100644 --- a/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts +++ b/x-pack/test/cloud_security_posture_functional/agentless/create_agent.ts @@ -8,10 +8,13 @@ import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import * as http from 'http'; import expect from '@kbn/expect'; +import equals from 'fast-deep-equal'; import type { FtrProviderContext } from '../ftr_provider_context'; import { setupMockServer } from './mock_agentless_api'; // eslint-disable-next-line import/no-default-export export default function ({ getPageObjects, getService }: FtrProviderContext) { + const agentCreationTimeout = 1000 * 60 * 1; // 1 minute + const retry = getService('retry'); const mockAgentlessApiService = setupMockServer(); const pageObjects = getPageObjects([ 'common', @@ -65,12 +68,17 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cisIntegration.navigateToIntegrationCspList(); await pageObjects.header.waitUntilLoadingHasFinished(); - expect(await cisIntegration.getFirstCspmIntegrationPageIntegration()).to.be( + expect(await cisIntegration.getFirstCspmIntegrationPageAgentlessIntegration()).to.be( integrationPolicyName ); - expect(await cisIntegration.getFirstCspmIntegrationPageAgent()).to.be( - `Agentless policy for ${integrationPolicyName}` - ); + + // wait for eventually Pending or Healthy status + // purpose of this retry is to wait for the agent to be created and the status to be updated + // not to wait for the agent to be healthy + await retry.tryForTime(agentCreationTimeout, async () => { + const resStatus = await cisIntegration.getFirstCspmIntegrationPageAgentlessStatus(); + expect(equals(resStatus, 'Healthy') || equals(resStatus, 'Pending')).to.be(true); + }); }); it(`should show setup technology selector in edit mode`, async () => { @@ -97,7 +105,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cisIntegration.navigateToIntegrationCspList(); await pageObjects.header.waitUntilLoadingHasFinished(); - await cisIntegration.navigateToEditIntegrationPage(); + await cisIntegration.navigateToEditAgentlessIntegrationPage(); await pageObjects.header.waitUntilLoadingHasFinished(); expect(await cisIntegration.showSetupTechnologyComponent()).to.be(true); diff --git a/x-pack/test/cloud_security_posture_functional/cloud_tests/agentless_api_sanity.ts b/x-pack/test/cloud_security_posture_functional/cloud_tests/agentless_api_sanity.ts new file mode 100644 index 000000000000..da4eb02a813c --- /dev/null +++ b/x-pack/test/cloud_security_posture_functional/cloud_tests/agentless_api_sanity.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../ftr_provider_context'; +// eslint-disable-next-line import/no-default-export +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const queryBar = getService('queryBar'); + const pageObjects = getPageObjects(['common', 'header', 'cisAddIntegration', 'findings']); + + describe('Agentless Cloud - Sanity Tests', function () { + this.tags(['cloud_security_posture_ui_sanity']); + + it(`should have agentless agent findings for AWS provider`, async () => { + const findings = pageObjects.findings; + + await findings.navigateToLatestFindingsPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await queryBar.setQuery('agent.name: *agentless* and cloud.provider : "aws"'); + await queryBar.submitQuery(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + const agentlessFindingsRowsCount = await findings + .createDataTableObject('latest_findings_table') + .getRowsCount(); + + expect(agentlessFindingsRowsCount).to.be.greaterThan(0); + }); + + it(`should have agentless agent findings for Azure provider`, async () => { + const findings = pageObjects.findings; + + await findings.navigateToLatestFindingsPage(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await queryBar.setQuery('agent.name: *agentless* and cloud.provider : "gcp"'); + await queryBar.submitQuery(); + await pageObjects.header.waitUntilLoadingHasFinished(); + + const agentlessFindingsRowsCount = await findings + .createDataTableObject('latest_findings_table') + .getRowsCount(); + + expect(agentlessFindingsRowsCount).to.be.greaterThan(0); + }); + }); +} diff --git a/x-pack/test/cloud_security_posture_functional/cloud_tests/index.ts b/x-pack/test/cloud_security_posture_functional/cloud_tests/index.ts index 80afb0456332..37e74d1d6ede 100644 --- a/x-pack/test/cloud_security_posture_functional/cloud_tests/index.ts +++ b/x-pack/test/cloud_security_posture_functional/cloud_tests/index.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../ftr_provider_context'; // eslint-disable-next-line import/no-default-export export default function ({ loadTestFile }: FtrProviderContext) { describe('Cloud Security Posture', function () { + loadTestFile(require.resolve('./agentless_api_sanity')); loadTestFile(require.resolve('./dashboard_sanity')); loadTestFile(require.resolve('./benchmark_sanity')); loadTestFile(require.resolve('./findings_sanity')); diff --git a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts index 563507d70558..fe95c0887711 100644 --- a/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts +++ b/x-pack/test/cloud_security_posture_functional/page_objects/add_cis_integration_form_page.ts @@ -218,6 +218,10 @@ export function AddCisIntegrationFormPageProvider({ await testSubjects.click('integrationNameLink'); }; + const navigateToEditAgentlessIntegrationPage = async () => { + await testSubjects.click('agentlessIntegrationNameLink'); + }; + const navigateToAddIntegrationKspmPage = async (space?: string) => { const options = space ? { @@ -485,7 +489,7 @@ export function AddCisIntegrationFormPageProvider({ await navigateToIntegrationCspList(); await PageObjects.header.waitUntilLoadingHasFinished(); - await navigateToEditIntegrationPage(); + await navigateToEditAgentlessIntegrationPage(); await PageObjects.header.waitUntilLoadingHasFinished(); // Fill out form to edit an agentless integration @@ -498,7 +502,7 @@ export function AddCisIntegrationFormPageProvider({ // Check if the Direct Access Key is updated package policy api with successful toast expect(await testSubjects.exists('policyUpdateSuccessToast')).to.be(true); - await navigateToEditIntegrationPage(); + await navigateToEditAgentlessIntegrationPage(); await PageObjects.header.waitUntilLoadingHasFinished(); }; @@ -511,12 +515,23 @@ export function AddCisIntegrationFormPageProvider({ return await integration.getVisibleText(); }; + const getFirstCspmIntegrationPageAgentlessIntegration = async () => { + const integration = await testSubjects.find('agentlessIntegrationNameLink'); + return await integration.getVisibleText(); + }; + const getFirstCspmIntegrationPageAgent = async () => { const agent = await testSubjects.find('agentPolicyNameLink'); // this is assuming that the agent was just created therefor should be the first element return await agent.getVisibleText(); }; + const getFirstCspmIntegrationPageAgentlessStatus = async () => { + const agent = await testSubjects.find('agentlessStatusBadge'); + // this is assuming that the agent was just created therefor should be the first element + return await agent.getVisibleText(); + }; + const getAgentBasedPolicyValue = async () => { const agentName = await testSubjects.find('createAgentPolicyNameField'); return await agentName.getAttribute('value'); @@ -568,10 +583,13 @@ export function AddCisIntegrationFormPageProvider({ testSubjectIds, inputIntegrationName, getFirstCspmIntegrationPageIntegration, + getFirstCspmIntegrationPageAgentlessIntegration, getFirstCspmIntegrationPageAgent, + getFirstCspmIntegrationPageAgentlessStatus, getAgentBasedPolicyValue, showSuccessfulToast, showSetupTechnologyComponent, navigateToEditIntegrationPage, + navigateToEditAgentlessIntegrationPage, }; } diff --git a/x-pack/test/common/services/search_secure.ts b/x-pack/test/common/services/search_secure.ts index f46e9e57ef27..9f25140df5d2 100644 --- a/x-pack/test/common/services/search_secure.ts +++ b/x-pack/test/common/services/search_secure.ts @@ -44,10 +44,12 @@ export class SearchSecureService extends FtrService { space, }: SendOptions) { const spaceUrl = getSpaceUrlPrefix(space); + const statusesWithoutRetry = [200, 400, 403, 500]; const { body } = await this.retry.try(async () => { let result; const url = `${spaceUrl}/internal/search/${strategy}`; + if (referer && kibanaVersion) { result = await supertestWithoutAuth .post(url) @@ -89,9 +91,11 @@ export class SearchSecureService extends FtrService { .set('kbn-xsrf', 'true') .send(options); } - if ((result.status === 500 || result.status === 200) && result.body) { + + if (statusesWithoutRetry.includes(result.status) && result.body) { return result; } + throw new Error('try again'); }); diff --git a/x-pack/test/fleet_api_integration/apis/agents/status.ts b/x-pack/test/fleet_api_integration/apis/agents/status.ts index 42b60a0624a9..4b56601078da 100644 --- a/x-pack/test/fleet_api_integration/apis/agents/status.ts +++ b/x-pack/test/fleet_api_integration/apis/agents/status.ts @@ -334,5 +334,31 @@ export default function ({ getService }: FtrProviderContext) { .set('kbn-xsrf', 'xxxx') .expect(400); }); + + it('should return incoming data status for specified agents', async () => { + // force install the system package to override package verification + await supertest + .post(`/api/fleet/epm/packages/system/1.50.0`) + .set('kbn-xsrf', 'xxxx') + .send({ force: true }) + .expect(200); + + const { body: apiResponse1 } = await supertest + .get(`/api/fleet/agent_status/data?agentsIds=agent1&agentsIds=agent2`) + .expect(200); + const { body: apiResponse2 } = await supertest + .get( + `/api/fleet/agent_status/data?agentsIds=agent1&agentsIds=agent2&pkgName=system&pkgVersion=1.50.0` + ) + .expect(200); + expect(apiResponse1).to.eql({ + items: [{ agent1: { data: false } }, { agent2: { data: false } }], + dataPreview: [], + }); + expect(apiResponse2).to.eql({ + items: [{ agent1: { data: false } }, { agent2: { data: false } }], + dataPreview: [], + }); + }); }); } diff --git a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts index b5376142ab85..35b343bacb7c 100644 --- a/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts +++ b/x-pack/test/fleet_api_integration/apis/integrations/inputs_with_standalone_docker_agent.ts @@ -25,8 +25,7 @@ export default function (providerContext: FtrProviderContext) { const config = getService('config'); const log = getService('log'); - // Failing: See https://github.com/elastic/kibana/issues/193625 - describe.skip('inputs_with_standalone_docker_agent', () => { + describe('inputs_with_standalone_docker_agent', () => { skipIfNoDockerRegistry(providerContext); let apiKey: string; let agent: AgentProcess; @@ -77,17 +76,22 @@ ${inputsYaml} const MAX_ITERATIONS = 20; let foundMetrics = false; for (let i = 0; i < MAX_ITERATIONS; i++) { - const searchRes = await es.search({ - index: 'metrics-system.cpu-default', - q: `agent.name:${agent.name}`, - ignore_unavailable: true, - }); - - // @ts-expect-error TotalHit - if (searchRes.hits.total.value > 0) { - foundMetrics = true; - break; + try { + const searchRes = await es.search({ + index: 'metrics-system.cpu-default', + q: `agent.name:${agent.name}`, + ignore_unavailable: true, + }); + + // @ts-expect-error TotalHit + if (searchRes.hits.total.value > 0) { + foundMetrics = true; + break; + } + } catch (err) { + log.error(err); } + // await agent.log(); uncomment if you need to debug agent logs await new Promise((resolve) => setTimeout(resolve, 5 * 1000)); } diff --git a/x-pack/test/functional/apps/aiops/change_point_detection.ts b/x-pack/test/functional/apps/aiops/change_point_detection.ts index 3f80d9e12e1e..6ee14d5fd31b 100644 --- a/x-pack/test/functional/apps/aiops/change_point_detection.ts +++ b/x-pack/test/functional/apps/aiops/change_point_detection.ts @@ -7,19 +7,16 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; -import { USER } from '../../services/ml/security_common'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const elasticChart = getService('elasticChart'); const esArchiver = getService('esArchiver'); const aiops = getService('aiops'); - const cases = getService('cases'); // aiops lives in the ML UI so we need some related services. const ml = getService('ml'); - // FLAKY: https://github.com/elastic/kibana/issues/200091 - describe.skip('change point detection', function () { + describe('change point detection UI', function () { before(async () => { await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); @@ -29,7 +26,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { after(async () => { await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); - await cases.api.deleteAllCases(); }); it(`loads the change point detection page`, async () => { @@ -104,34 +100,5 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await aiops.changePointDetectionPage.addChangePointConfig(); await aiops.changePointDetectionPage.assertPanelExist(1); }); - - it('attaches change point charts to a dashboard', async () => { - await aiops.changePointDetectionPage.assertPanelExist(0); - await aiops.changePointDetectionPage.attachChartsToDashboard(0, { - applyTimeRange: true, - maxSeries: 1, - }); - }); - - it('attaches change point charts to a case', async () => { - await ml.navigation.navigateToMl(); - await elasticChart.setNewChartUiDebugFlag(true); - await aiops.changePointDetectionPage.navigateToDataViewSelection(); - await ml.jobSourceSelection.selectSourceForChangePointDetection('ft_ecommerce'); - await aiops.changePointDetectionPage.assertChangePointDetectionPageExists(); - - await aiops.changePointDetectionPage.clickUseFullDataButton(); - await aiops.changePointDetectionPage.selectMetricField(0, 'products.discount_amount'); - - const caseParams = { - title: 'ML Change Point Detection case', - description: 'Case with a change point detection attachment', - tag: 'ml_change_point_detection', - reporter: USER.ML_POWERUSER, - }; - - await aiops.changePointDetectionPage.attachChartsToCases(0, caseParams); - await ml.cases.assertCaseWithChangePointDetectionChartsAttachment(caseParams); - }); }); } diff --git a/x-pack/test/functional/apps/aiops/change_point_detection_cases.ts b/x-pack/test/functional/apps/aiops/change_point_detection_cases.ts new file mode 100644 index 000000000000..328a102ec12f --- /dev/null +++ b/x-pack/test/functional/apps/aiops/change_point_detection_cases.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; +import { USER } from '../../services/ml/security_common'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const elasticChart = getService('elasticChart'); + const esArchiver = getService('esArchiver'); + const aiops = getService('aiops'); + const cases = getService('cases'); + + // aiops lives in the ML UI so we need some related services. + const ml = getService('ml'); + + describe('change point detection in cases', function () { + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.setKibanaTimeZoneToUTC(); + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); + await cases.api.deleteAllCases(); + }); + + it('attaches change point charts to a case', async () => { + await ml.navigation.navigateToMl(); + await elasticChart.setNewChartUiDebugFlag(true); + await aiops.changePointDetectionPage.navigateToDataViewSelection(); + await ml.jobSourceSelection.selectSourceForChangePointDetection('ft_ecommerce'); + await aiops.changePointDetectionPage.assertChangePointDetectionPageExists(); + + await aiops.changePointDetectionPage.clickUseFullDataButton(); + await aiops.changePointDetectionPage.selectMetricField(0, 'products.discount_amount'); + + const caseParams = { + title: 'ML Change Point Detection case', + description: 'Case with a change point detection attachment', + tag: 'ml_change_point_detection', + reporter: USER.ML_POWERUSER, + }; + + await ml.testExecution.logTestStep('attaches chart to a case'); + await aiops.changePointDetectionPage.attachChartsToCases(0, caseParams); + + await ml.testExecution.logTestStep('checks if attachment is present in the case'); + await ml.cases.assertCaseWithChangePointDetectionChartsAttachment(caseParams); + }); + }); +} diff --git a/x-pack/test/functional/apps/aiops/change_point_detection_dashboard.ts b/x-pack/test/functional/apps/aiops/change_point_detection_dashboard.ts new file mode 100644 index 000000000000..b152bc45bd17 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/change_point_detection_dashboard.ts @@ -0,0 +1,48 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const elasticChart = getService('elasticChart'); + const esArchiver = getService('esArchiver'); + const aiops = getService('aiops'); + + // aiops lives in the ML UI so we need some related services. + const ml = getService('ml'); + + describe('change point detection in dashboard', function () { + before(async () => { + await esArchiver.loadIfNeeded('x-pack/test/functional/es_archives/ml/ecommerce'); + await ml.testResources.createDataViewIfNeeded('ft_ecommerce', 'order_date'); + await ml.testResources.setKibanaTimeZoneToUTC(); + await ml.securityUI.loginAsMlPowerUser(); + }); + + after(async () => { + await ml.testResources.deleteDataViewByTitle('ft_ecommerce'); + }); + + it('attaches change point charts to a dashboard from the ML app', async () => { + await ml.navigation.navigateToMl(); + await elasticChart.setNewChartUiDebugFlag(true); + await aiops.changePointDetectionPage.navigateToDataViewSelection(); + await ml.jobSourceSelection.selectSourceForChangePointDetection('ft_ecommerce'); + await aiops.changePointDetectionPage.assertChangePointDetectionPageExists(); + + await aiops.changePointDetectionPage.clickUseFullDataButton(); + await aiops.changePointDetectionPage.selectMetricField(0, 'products.discount_amount'); + await aiops.changePointDetectionPage.selectSplitField(0, 'geoip.city_name'); + + await aiops.changePointDetectionPage.assertPanelExist(0); + await aiops.changePointDetectionPage.attachChartsToDashboard(0, { + applyTimeRange: true, + maxSeries: 1, + }); + }); + }); +} diff --git a/x-pack/test/functional/apps/aiops/index.ts b/x-pack/test/functional/apps/aiops/index.ts index 75ad41f2e21f..981ae301a6dc 100644 --- a/x-pack/test/functional/apps/aiops/index.ts +++ b/x-pack/test/functional/apps/aiops/index.ts @@ -32,7 +32,10 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./log_rate_analysis')); loadTestFile(require.resolve('./log_rate_analysis_anomaly_table')); loadTestFile(require.resolve('./log_rate_analysis_dashboard_embeddable')); + loadTestFile(require.resolve('./log_rate_analysis_cases')); loadTestFile(require.resolve('./change_point_detection')); + loadTestFile(require.resolve('./change_point_detection_dashboard')); + loadTestFile(require.resolve('./change_point_detection_cases')); loadTestFile(require.resolve('./log_pattern_analysis')); loadTestFile(require.resolve('./log_pattern_analysis_in_discover')); }); diff --git a/x-pack/test/functional/apps/aiops/log_rate_analysis_cases.ts b/x-pack/test/functional/apps/aiops/log_rate_analysis_cases.ts new file mode 100644 index 000000000000..07c632ea7df0 --- /dev/null +++ b/x-pack/test/functional/apps/aiops/log_rate_analysis_cases.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 { FtrProviderContext } from '../../ftr_provider_context'; +import { USER } from '../../services/ml/security_common'; +import { logRateAnalysisTestData } from './log_rate_analysis_test_data'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const elasticChart = getService('elasticChart'); + const aiops = getService('aiops'); + const cases = getService('cases'); + + const testData = logRateAnalysisTestData[0]; + + // aiops lives in the ML UI so we need some related services. + const ml = getService('ml'); + + describe('log rate analysis in cases', function () { + before(async () => { + await aiops.logRateAnalysisDataGenerator.generateData(testData.dataGenerator); + await ml.testResources.setKibanaTimeZoneToUTC(); + await ml.securityUI.loginAsMlPowerUser(); + await ml.testResources.createDataViewIfNeeded( + testData.sourceIndexOrSavedSearch, + '@timestamp' + ); + await elasticChart.setNewChartUiDebugFlag(true); + await ml.navigation.navigateToMl(); + }); + + after(async () => { + await ml.testResources.deleteDataViewByTitle(testData.sourceIndexOrSavedSearch); + await aiops.logRateAnalysisDataGenerator.removeGeneratedData(testData.dataGenerator); + await elasticChart.setNewChartUiDebugFlag(false); + await cases.api.deleteAllCases(); + }); + + it('attaches log rate analysis to a case', async () => { + await aiops.logRateAnalysisPage.navigateToDataViewSelection(); + await ml.jobSourceSelection.selectSourceForLogRateAnalysis(testData.sourceIndexOrSavedSearch); + + await aiops.logRateAnalysisPage.openAttachmentsMenu(); + await aiops.logRateAnalysisPage.assertAttachToCaseButtonDisabled(); + + await aiops.logRateAnalysisPage.clickUseFullDataButton( + testData.expected.totalDocCountFormatted + ); + + await aiops.logRateAnalysisPage.clickDocumentCountChart(testData.chartClickCoordinates); + + const caseParams = { + title: 'Log rate analysis case', + description: 'Case with log rate analysis attachment', + tag: 'ml_log_rate_analysis', + reporter: USER.ML_POWERUSER, + }; + + await aiops.logRateAnalysisPage.attachToCase(caseParams); + + await ml.cases.assertCaseWithLogRateAnalysisAttachment(caseParams); + }); + }); +} diff --git a/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts b/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts index 541405265ee3..f484cbdcd2e3 100644 --- a/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts +++ b/x-pack/test/functional/apps/apm/correlations/failed_transaction_correlations.ts @@ -46,7 +46,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { basePath: '/s/custom_space', }); const navLinks = (await appsMenu.readLinks()).map((link) => link.text); - expect(navLinks).to.contain('APM'); + expect(navLinks).to.contain('Applications'); }); it('can navigate to APM app', async () => { diff --git a/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts b/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts index 5deb2a9060f4..5c5514265225 100644 --- a/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts +++ b/x-pack/test/functional/apps/apm/correlations/latency_correlations.ts @@ -47,7 +47,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { basePath: '/s/custom_space', }); const navLinks = (await appsMenu.readLinks()).map((link) => link.text); - expect(navLinks).to.contain('APM'); + expect(navLinks).to.contain('Applications'); }); it('can navigate to APM app', async () => { diff --git a/x-pack/test/functional/apps/apm/feature_controls/apm_security.ts b/x-pack/test/functional/apps/apm/feature_controls/apm_security.ts index b5a206a43aeb..900f2ec9f214 100644 --- a/x-pack/test/functional/apps/apm/feature_controls/apm_security.ts +++ b/x-pack/test/functional/apps/apm/feature_controls/apm_security.ts @@ -64,7 +64,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(navLinks.map((link) => link.text)).to.eql([ 'Overview', 'Alerts', - 'APM', + 'Applications', 'User Experience', 'Stack Management', ]); @@ -119,7 +119,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { expect(navLinks).to.eql([ 'Overview', 'Alerts', - 'APM', + 'Applications', 'User Experience', 'Stack Management', ]); @@ -175,7 +175,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it(`doesn't show APM navlink`, async () => { const navLinks = (await appsMenu.readLinks()).map((link) => link.text); - expect(navLinks).not.to.contain('APM'); + expect(navLinks).not.to.contain('Applications'); }); it(`renders no permission page`, async () => { diff --git a/x-pack/test/functional/apps/apm/feature_controls/apm_spaces.ts b/x-pack/test/functional/apps/apm/feature_controls/apm_spaces.ts index 3a375adf0613..06727d1c3197 100644 --- a/x-pack/test/functional/apps/apm/feature_controls/apm_spaces.ts +++ b/x-pack/test/functional/apps/apm/feature_controls/apm_spaces.ts @@ -33,7 +33,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { basePath: '/s/custom_space', }); const navLinks = (await appsMenu.readLinks()).map((link) => link.text); - expect(navLinks).to.contain('APM'); + expect(navLinks).to.contain('Applications'); }); it('can navigate to Uptime app', async () => { @@ -62,7 +62,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { basePath: '/s/custom_space', }); const navLinks = (await appsMenu.readLinks()).map((link) => link.text); - expect(navLinks).not.to.contain('APM'); + expect(navLinks).not.to.contain('Applications'); }); it(`renders not found page`, async () => { diff --git a/x-pack/test/functional/apps/dashboard/group1/feature_controls/time_to_visualize_security.ts b/x-pack/test/functional/apps/dashboard/group1/feature_controls/time_to_visualize_security.ts index 8922bca6d7fd..995d26d5efc9 100644 --- a/x-pack/test/functional/apps/dashboard/group1/feature_controls/time_to_visualize_security.ts +++ b/x-pack/test/functional/apps/dashboard/group1/feature_controls/time_to_visualize_security.ts @@ -101,7 +101,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('edits to a by value lens panel are properly applied', async () => { await dashboard.waitForRenderComplete(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.switchToVisualization('pie'); await lens.saveAndReturn(); await dashboard.waitForRenderComplete(); @@ -112,7 +112,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('disables save to library button without visualize save permissions', async () => { await dashboard.waitForRenderComplete(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); const saveButton = await testSubjects.find('lnsApp_saveButton'); expect(await saveButton.getAttribute('disabled')).to.equal('true'); await lens.saveAndReturn(); diff --git a/x-pack/test/functional/apps/dashboard/group2/dashboard_lens_by_value.ts b/x-pack/test/functional/apps/dashboard/group2/dashboard_lens_by_value.ts index a974eb8c1284..804790e7ee06 100644 --- a/x-pack/test/functional/apps/dashboard/group2/dashboard_lens_by_value.ts +++ b/x-pack/test/functional/apps/dashboard/group2/dashboard_lens_by_value.ts @@ -47,7 +47,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('edits to a by value lens panel are properly applied', async () => { await dashboard.waitForRenderComplete(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.switchToVisualization('pie'); await lens.saveAndReturn(); await dashboard.waitForRenderComplete(); @@ -59,7 +59,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('editing and saving a lens by value panel retains number of panels', async () => { const originalPanelCount = await dashboard.getPanelCount(); await dashboard.waitForRenderComplete(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.switchToVisualization('treemap'); await lens.saveAndReturn(); await dashboard.waitForRenderComplete(); @@ -71,7 +71,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const newTitle = 'look out library, here I come!'; const originalPanelCount = await dashboard.getPanelCount(); await dashboard.waitForRenderComplete(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.save(newTitle, false, true); await dashboard.waitForRenderComplete(); const newPanelCount = await dashboard.getPanelCount(); diff --git a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts index 81fade0255cf..df5860fd20a8 100644 --- a/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts +++ b/x-pack/test/functional/apps/dashboard/group2/migration_smoke_tests/lens_migration_smoke_test.ts @@ -69,7 +69,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // All panels should be editable. This will catch cases where an error does not create an error embeddable. const panelTitles = await dashboard.getPanelTitles(); for (const title of panelTitles) { - await dashboardPanelActions.expectExistsEditPanelAction(title, true); + await dashboardPanelActions.expectExistsEditPanelAction(title); } }); diff --git a/x-pack/test/functional/apps/dashboard/group2/panel_time_range.ts b/x-pack/test/functional/apps/dashboard/group2/panel_time_range.ts index d5070b931b18..78b34f1d5593 100644 --- a/x-pack/test/functional/apps/dashboard/group2/panel_time_range.ts +++ b/x-pack/test/functional/apps/dashboard/group2/panel_time_range.ts @@ -58,7 +58,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('by reference', () => { it('can add a custom time range to panel', async () => { - await dashboardPanelActions.legacySaveToLibrary('My by reference visualization'); + await dashboardPanelActions.saveToLibrary('My by reference visualization'); await dashboardPanelActions.customizePanel(); await dashboardCustomizePanel.enableCustomTimeRange(); await dashboardCustomizePanel.openDatePickerQuickMenu(); diff --git a/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts b/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts index 7d8456a9e81a..19109ef3b76e 100644 --- a/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts +++ b/x-pack/test/functional/apps/dashboard/group2/panel_titles.ts @@ -92,7 +92,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardPanelActions.customizePanel(); await dashboardCustomizePanel.setCustomPanelTitle('Custom title'); await dashboardCustomizePanel.clickSaveButton(); - await dashboardPanelActions.legacySaveToLibrary(getVisTitle(true)); + await dashboardPanelActions.saveToLibrary(getVisTitle(true)); await retry.tryForTime(500, async () => { // need to surround in 'retry' due to delays in HTML updates causing the title read to be behind const [newPanelTitle] = await dashboard.getPanelTitles(); @@ -113,7 +113,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('resetting description on a by reference panel sets it to the library title', async () => { await dashboardPanelActions.navigateToEditorFromFlyout(); - // legacySaveToLibrary UI cannot set description await lens.save( getVisTitle(true), false, @@ -142,7 +141,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardPanelActions.customizePanel(); await dashboardCustomizePanel.setCustomPanelTitle('Custom title'); await dashboardCustomizePanel.clickSaveButton(); - await dashboardPanelActions.legacyUnlinkFromLibrary('Custom title'); + await dashboardPanelActions.unlinkFromLibrary('Custom title'); const [newPanelTitle] = await dashboard.getPanelTitles(); expect(newPanelTitle).to.equal('Custom title'); }); @@ -151,7 +150,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardPanelActions.customizePanel(); await dashboardCustomizePanel.setCustomPanelTitle(''); await dashboardCustomizePanel.clickSaveButton(); - await dashboardPanelActions.legacySaveToLibrary(getVisTitle(true)); + await dashboardPanelActions.saveToLibrary(getVisTitle(true)); await retry.tryForTime(500, async () => { // need to surround in 'retry' due to delays in HTML updates causing the title read to be behind const [newPanelTitle] = await dashboard.getPanelTitles(); @@ -160,7 +159,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('unlinking a by reference panel without a custom title will keep the library title', async () => { - await dashboardPanelActions.legacyUnlinkFromLibrary(getVisTitle()); + await dashboardPanelActions.unlinkFromLibrary(getVisTitle()); const [newPanelTitle] = await dashboard.getPanelTitles(); expect(newPanelTitle).to.equal(getVisTitle()); }); diff --git a/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts b/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts index 60a7f754933d..42c933f8792a 100644 --- a/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts +++ b/x-pack/test/functional/apps/dashboard/group3/reporting/screenshots.ts @@ -221,7 +221,6 @@ export default function ({ }); it('downloads a PDF file with saved search given EuiDataGrid enabled', async function () { - await kibanaServer.uiSettings.update({ 'doc_table:legacy': false }); this.timeout(300000); await dashboard.navigateToApp(); await dashboard.loadSavedDashboard('Ecom Dashboard'); diff --git a/x-pack/test/functional/apps/dataset_quality/config.ts b/x-pack/test/functional/apps/dataset_quality/config.ts index c7e72325d6c0..2293af3face4 100644 --- a/x-pack/test/functional/apps/dataset_quality/config.ts +++ b/x-pack/test/functional/apps/dataset_quality/config.ts @@ -9,7 +9,33 @@ import { FtrConfigProviderContext, GenericFtrProviderContext } from '@kbn/test'; import { createLogger, LogLevel, LogsSynthtraceEsClient } from '@kbn/apm-synthtrace'; import { FtrProviderContext } from '../../ftr_provider_context'; -export default async function createTestConfig({ readConfigFile }: FtrConfigProviderContext) { +import { FtrProviderContext as InheritedFtrProviderContext } from '../../ftr_provider_context'; + +export type InheritedServices = InheritedFtrProviderContext extends GenericFtrProviderContext< + infer TServices, + {} +> + ? TServices + : {}; + +export type InheritedPageObjects = InheritedFtrProviderContext extends GenericFtrProviderContext< + infer TServices, + infer TPageObjects +> + ? TPageObjects + : {}; + +interface DatasetQualityConfig { + services: InheritedServices & { + logSynthtraceEsClient: ( + context: InheritedFtrProviderContext + ) => Promise; + }; +} + +export default async function createTestConfig({ + readConfigFile, +}: FtrConfigProviderContext): Promise { const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); const services = functionalConfig.get('services'); const pageObjects = functionalConfig.get('pageObjects'); @@ -34,7 +60,7 @@ export default async function createTestConfig({ readConfigFile }: FtrConfigProv export type CreateTestConfig = Awaited>; export type DatasetQualityServices = CreateTestConfig['services']; -export type DatasetQualityPageObject = CreateTestConfig['pageObjects']; +export type DatasetQualityPageObject = InheritedPageObjects; export type DatasetQualityFtrProviderContext = GenericFtrProviderContext< DatasetQualityServices, diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts index 3b93f0ceccfe..28a7cc9a9963 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_details.ts @@ -250,7 +250,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid ); }); - it('Should navigate to integration overview page on clicking integration overview action', async () => { + it('should navigate to integration overview page on clicking integration overview action', async () => { await PageObjects.datasetQuality.navigateToDetails({ dataStream: bitbucketAuditDataStreamName, }); @@ -359,7 +359,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid ); }); - it('should show the degraded fields table with data when present', async () => { + it('should show the degraded fields table with data and spark plots when present', async () => { await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDataStreamName, }); @@ -372,15 +372,6 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); expect(rows.length).to.eql(3); - }); - - it('should display Spark Plot for every row of degraded fields', async () => { - await PageObjects.datasetQuality.navigateToDetails({ - dataStream: degradedDataStreamName, - }); - - const rows = - await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); const sparkPlots = await testSubjects.findAll( PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot @@ -423,7 +414,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid ); }); - countColumn.sort('ascending'); + await countColumn.sort('ascending'); await retry.tryForTime(5000, async () => { const currentUrl = await browser.getCurrentUrl(); diff --git a/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts b/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts index 491a3b20c800..2c744279fcac 100644 --- a/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts +++ b/x-pack/test/functional/apps/dataset_quality/dataset_quality_summary.ts @@ -19,7 +19,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const synthtrace = getService('logSynthtraceEsClient'); const to = '2024-01-01T12:00:00.000Z'; - const ingestDataForSummary = async () => { + const ingestDataForSummary = () => { // Ingest documents for 3 type of datasets return synthtrace.index([ // Ingest good data to all 3 datasets @@ -48,16 +48,14 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid }; describe('Dataset quality summary', () => { - before(async () => { - await synthtrace.index(getInitialTestLogs({ to, count: 4 })); - await PageObjects.datasetQuality.navigateTo(); - }); - afterEach(async () => { await synthtrace.clean(); }); it('shows poor, degraded and good count as 0 and all dataset as healthy', async () => { + await synthtrace.index(getInitialTestLogs({ to, count: 4 })); + await PageObjects.datasetQuality.navigateTo(); + const summary = await PageObjects.datasetQuality.parseSummaryPanel(); expect(summary).to.eql({ datasetHealthPoor: '0', @@ -70,7 +68,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid it('shows updated count for poor, degraded and good datasets, estimated size and updates active datasets', async () => { await ingestDataForSummary(); - await PageObjects.datasetQuality.refreshTable(); + await PageObjects.datasetQuality.navigateTo(); const summary = await PageObjects.datasetQuality.parseSummaryPanel(); const { estimatedData, ...restOfSummary } = summary; diff --git a/x-pack/test/functional/apps/dataset_quality/degraded_field_flyout.ts b/x-pack/test/functional/apps/dataset_quality/degraded_field_flyout.ts index f5d695b8f165..19a200160392 100644 --- a/x-pack/test/functional/apps/dataset_quality/degraded_field_flyout.ts +++ b/x-pack/test/functional/apps/dataset_quality/degraded_field_flyout.ts @@ -42,13 +42,16 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid const customComponentTemplateName = 'logs-synth@mappings'; const nginxAccessDatasetName = 'nginx.access'; - const customComponentTemplateNameNginx = 'logs-nginx.access@custom'; + const customComponentTemplateNameNginx = `logs-${nginxAccessDatasetName}@custom`; const nginxAccessDataStreamName = `${type}-${nginxAccessDatasetName}-${defaultNamespace}`; const nginxPkg = { name: 'nginx', version: '1.23.0', }; + const apmAppDatasetName = 'apm.app.tug'; + const apmAppDataStreamName = `${type}-${apmAppDatasetName}-${defaultNamespace}`; + describe('Degraded fields flyout', () => { describe('degraded field flyout open-close', () => { before(async () => { @@ -131,7 +134,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid // Install Nginx Integration and ingest logs for it await PageObjects.observabilityLogsExplorer.installPackage(nginxPkg); - // Create custom component template to avoid issues with LogsDB + // Create custom component template for Nginx to avoid issues with LogsDB await synthtrace.createComponentTemplate( customComponentTemplateNameNginx, logsNginxMappings(nginxAccessDatasetName) @@ -184,6 +187,29 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid .timestamp(timestamp) ); }), + // Ingest Degraded Logs with 26 fields in Apm DataSet + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return Array(1) + .fill(0) + .flatMap(() => + log + .create() + .dataset(apmAppDatasetName) + .message('a log message') + .logLevel(MORE_THAN_1024_CHARS) + .service(serviceName) + .namespace(defaultNamespace) + .defaults({ + 'service.name': serviceName, + 'trace.id': generateShortId(), + test_field: [MORE_THAN_1024_CHARS, ANOTHER_1024_CHARS], + }) + .timestamp(timestamp) + ); + }), ]); // Set Limit of 25 @@ -199,6 +225,11 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid 'mapping.total_fields.limit': 42, }); + // Set Limit of 26 + await PageObjects.datasetQuality.setDataStreamSettings(apmAppDataStreamName, { + 'mapping.total_fields.limit': 25, + }); + await synthtrace.index([ // Ingest Degraded Logs with 26 field timerange(moment(to).subtract(count, 'minute'), moment(to)) @@ -248,11 +279,36 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid .timestamp(timestamp) ); }), + // Ingest Degraded Logs with 27 fields in Apm APP DataSet + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return Array(1) + .fill(0) + .flatMap(() => + log + .create() + .dataset(apmAppDatasetName) + .message('a log message') + .logLevel(MORE_THAN_1024_CHARS) + .service(serviceName) + .namespace(defaultNamespace) + .defaults({ + 'service.name': serviceName, + 'trace.id': generateShortId(), + test_field: [MORE_THAN_1024_CHARS, ANOTHER_1024_CHARS], + 'cloud.project.id': generateShortId(), + }) + .timestamp(timestamp) + ); + }), ]); // Rollover Datastream to reset the limit to default which is 1000 await PageObjects.datasetQuality.rolloverDataStream(degradedDatasetWithLimitDataStreamName); await PageObjects.datasetQuality.rolloverDataStream(nginxAccessDataStreamName); + await PageObjects.datasetQuality.rolloverDataStream(apmAppDataStreamName); // Set Limit of 26 await PageObjects.datasetQuality.setDataStreamSettings( @@ -274,6 +330,16 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid } ); + // Set Limit of 27 + await PageObjects.datasetQuality.setDataStreamSettings( + PageObjects.datasetQuality.generateBackingIndexNameWithoutVersion({ + dataset: apmAppDatasetName, + }) + '-000002', + { + 'mapping.total_fields.limit': 27, + } + ); + await synthtrace.index([ // Ingest Degraded Logs with 26 field timerange(moment(to).subtract(count, 'minute'), moment(to)) @@ -323,6 +389,30 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid .timestamp(timestamp) ); }), + // Ingest Degraded Logs with 27 fields in Apm APP DataSet + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return Array(1) + .fill(0) + .flatMap(() => + log + .create() + .dataset(apmAppDatasetName) + .message('a log message') + .logLevel(MORE_THAN_1024_CHARS) + .service(serviceName) + .namespace(defaultNamespace) + .defaults({ + 'service.name': serviceName, + 'trace.id': generateShortId(), + test_field: [MORE_THAN_1024_CHARS, ANOTHER_1024_CHARS], + 'cloud.project.id': generateShortId(), + }) + .timestamp(timestamp) + ); + }), ]); }); @@ -568,6 +658,8 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid expandedDegradedField: 'test_field', }); + await PageObjects.datasetQuality.waitUntilPossibleMitigationsLoaded(); + // Possible Mitigation Section should exist await testSubjects.existOrFail( 'datasetQualityDetailsDegradedFieldFlyoutPossibleMitigationTitle' @@ -703,6 +795,36 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid expect(linkURL?.endsWith('mapping-settings-limit.html')).to.be(true); }); + it('should display increase field limit as a possible mitigation for special packages like apm app', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apmAppDataStreamName, + expandedDegradedField: 'cloud.project', + }); + + // Field Limit Mitigation Section should exist + await testSubjects.existOrFail( + 'datasetQualityDetailsDegradedFieldFlyoutFieldLimitMitigationAccordion' + ); + + // Should display the panel to increase field limit + await testSubjects.existOrFail( + 'datasetQualityDetailsDegradedFieldFlyoutIncreaseFieldLimitPanel' + ); + + // Should display official online documentation link + await testSubjects.existOrFail( + 'datasetQualityManualMitigationsPipelineOfficialDocumentationLink' + ); + + const linkButton = await testSubjects.find( + 'datasetQualityManualMitigationsPipelineOfficialDocumentationLink' + ); + + const linkURL = await linkButton.getAttribute('href'); + + expect(linkURL?.endsWith('mapping-settings-limit.html')).to.be(true); + }); + it('should display increase field limit as a possible mitigation for non integration', async () => { await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDatasetWithLimitDataStreamName, @@ -764,10 +886,10 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid expect(newFieldLimit).to.be(newLimit); // Should display the apply button - await testSubjects.existOrFail('datasetQualityIncreaseFieldMappingLimitButtonButton'); + await testSubjects.existOrFail('datasetQualityIncreaseFieldMappingLimitButton'); const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); const applyButtonDisabledStatus = await applyButton.getAttribute('disabled'); @@ -792,7 +914,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid ); const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); const applyButtonDisabledStatus = await applyButton.getAttribute('disabled'); @@ -814,7 +936,7 @@ export default function ({ getService, getPageObjects }: DatasetQualityFtrProvid }); const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); await applyButton.click(); diff --git a/x-pack/test/functional/apps/discover/saved_searches.ts b/x-pack/test/functional/apps/discover/saved_searches.ts index 3b039c8da9ee..ee733b4c4c46 100644 --- a/x-pack/test/functional/apps/discover/saved_searches.ts +++ b/x-pack/test/functional/apps/discover/saved_searches.ts @@ -28,7 +28,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const ecommerceSOPath = 'x-pack/test/functional/fixtures/kbn_archiver/reporting/ecommerce.json'; const defaultSettings = { defaultIndex: 'logstash-*', - 'doc_table:legacy': false, }; const from = 'Apr 27, 2019 @ 23:56:51.374'; @@ -47,7 +46,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await esArchiver.unload('x-pack/test/functional/es_archives/reporting/ecommerce'); await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); await kibanaServer.importExport.unload(ecommerceSOPath); - await kibanaServer.uiSettings.unset('doc_table:legacy'); await common.unsetTime(); }); diff --git a/x-pack/test/functional/apps/discover/value_suggestions.ts b/x-pack/test/functional/apps/discover/value_suggestions.ts index f949a890d90c..21a577ece13b 100644 --- a/x-pack/test/functional/apps/discover/value_suggestions.ts +++ b/x-pack/test/functional/apps/discover/value_suggestions.ts @@ -35,14 +35,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.load( 'x-pack/test/functional/fixtures/kbn_archiver/dashboard_drilldowns/drilldowns' ); - await kibanaServer.uiSettings.update({ - 'doc_table:legacy': false, - }); await timePicker.setDefaultAbsoluteRangeViaUiSettings(); }); after(async () => { - await kibanaServer.uiSettings.unset('doc_table:legacy'); await common.unsetTime(); await kibanaServer.savedObjects.cleanStandardList(); }); diff --git a/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts b/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts index b40c74bf06e4..47cc04b5b60f 100644 --- a/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts +++ b/x-pack/test/functional/apps/discover/value_suggestions_non_timebased.ts @@ -23,9 +23,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); await kibanaServer.uiSettings.replace({ defaultIndex: 'without-timefield' }); - await kibanaServer.uiSettings.update({ - 'doc_table:legacy': false, - }); }); after(async () => { @@ -34,7 +31,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await kibanaServer.savedObjects.clean({ types: ['search', 'index-pattern'] }); await kibanaServer.uiSettings.unset('defaultIndex'); - await kibanaServer.uiSettings.unset('doc_table:legacy'); }); it('shows all autosuggest options for a filter in discover context app', async () => { diff --git a/x-pack/test/functional/apps/discover/visualize_field.ts b/x-pack/test/functional/apps/discover/visualize_field.ts index 3d8bdc9c7d78..7a9a5e3b1a8c 100644 --- a/x-pack/test/functional/apps/discover/visualize_field.ts +++ b/x-pack/test/functional/apps/discover/visualize_field.ts @@ -67,6 +67,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); after(async () => { + await timePicker.resetDefaultAbsoluteRangeViaUiSettings(); await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.importExport.unload( 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json' diff --git a/x-pack/test/functional/apps/index_management/config.ts b/x-pack/test/functional/apps/index_management/config.ts index d0d07ff20028..16999df37efd 100644 --- a/x-pack/test/functional/apps/index_management/config.ts +++ b/x-pack/test/functional/apps/index_management/config.ts @@ -10,8 +10,90 @@ import { FtrConfigProviderContext } from '@kbn/test'; export default async function ({ readConfigFile }: FtrConfigProviderContext) { const functionalConfig = await readConfigFile(require.resolve('../../config.base.js')); + const baseConfig = functionalConfig.getAll(); + + baseConfig.security.roles.index_management_manage_index_templates = { + elasticsearch: { + cluster: ['manage_index_templates'], + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + advancedSettings: ['read'], + }, + spaces: ['*'], + }, + ], + }; + + baseConfig.security.roles.index_management_monitor_only = { + elasticsearch: { + cluster: ['monitor'], + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + advancedSettings: ['read'], + }, + spaces: ['*'], + }, + ], + }; + + baseConfig.security.roles.index_management_manage_enrich_only = { + elasticsearch: { + cluster: ['manage_enrich'], + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + advancedSettings: ['read'], + }, + spaces: ['*'], + }, + ], + }; + + baseConfig.security.roles.index_management_monitor_enrich_only = { + elasticsearch: { + cluster: ['monitor_enrich'], + indices: [ + { + names: ['*'], + privileges: ['all'], + }, + ], + }, + kibana: [ + { + feature: { + advancedSettings: ['read'], + }, + spaces: ['*'], + }, + ], + }; + return { - ...functionalConfig.getAll(), + ...baseConfig, testFiles: [require.resolve('.')], }; } diff --git a/x-pack/test/functional/apps/index_management/enrich_policies_tab/enrich_policies_tab.ts b/x-pack/test/functional/apps/index_management/enrich_policies_tab/enrich_policies_tab.ts index a473a33d298c..e74a14fe4f26 100644 --- a/x-pack/test/functional/apps/index_management/enrich_policies_tab/enrich_policies_tab.ts +++ b/x-pack/test/functional/apps/index_management/enrich_policies_tab/enrich_policies_tab.ts @@ -23,6 +23,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Enrich policies tab', function () { before(async () => { await log.debug('Creating required index and enrich policy'); + + try { + await es.indices.delete({ index: ENRICH_INDEX_NAME }); + // eslint-disable-next-line no-empty + } catch (e) {} + try { await es.indices.create({ index: ENRICH_INDEX_NAME, @@ -94,7 +100,22 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { expect(await successToast.getVisibleText()).to.contain(`Executed ${ENRICH_POLICY_NAME}`); }); + it('read only access', async () => { + await security.testUser.setRoles(['index_management_monitor_enrich_only']); + await pageObjects.common.navigateToApp('indexManagement'); + await pageObjects.indexManagement.changeTabs('enrich_policiesTab'); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await testSubjects.missingOrFail('createPolicyButton'); + await testSubjects.missingOrFail('deletePolicyButton'); + }); + it('can delete a policy', async () => { + await security.testUser.setRoles(['index_management_user']); + await pageObjects.common.navigateToApp('indexManagement'); + // Navigate to the enrich policies tab + await pageObjects.indexManagement.changeTabs('enrich_policiesTab'); + await pageObjects.header.waitUntilLoadingHasFinished(); // Since we disabled wait_for_completion in the server request, we dont know when // a given policy will finish executing. Until that happens the policy cannot // be deleted. 2s seems to be plenty enough to guarantee that, at least for this @@ -104,8 +125,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.indexManagement.clickDeleteEnrichPolicyAt(0); await pageObjects.indexManagement.clickConfirmModalButton(); - const successToast = await toasts.getElementByIndex(2); + const successToast = await toasts.getElementByIndex(1); expect(await successToast.getVisibleText()).to.contain(`Deleted ${ENRICH_POLICY_NAME}`); }); + + it('no access', async () => { + await security.testUser.setRoles(['index_management_monitor_only']); + await pageObjects.common.navigateToApp('indexManagement'); + await testSubjects.missingOrFail('enrich_policiesTab'); + }); }); }; diff --git a/x-pack/test/functional/apps/index_management/index_template_wizard.ts b/x-pack/test/functional/apps/index_management/index_template_wizard.ts index d932b96d4f6a..8103dfc0776d 100644 --- a/x-pack/test/functional/apps/index_management/index_template_wizard.ts +++ b/x-pack/test/functional/apps/index_management/index_template_wizard.ts @@ -70,7 +70,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Verify that index mode callout is displayed const indexModeCalloutText = await testSubjects.getVisibleText('indexModeCallout'); expect(indexModeCalloutText).to.be( - 'The index.mode setting has been set to Standard within template Logistics. Any changes to index.mode set on this page will be overwritten by the Logistics selection.' + 'The index.mode setting has been set to Standard within the Logistics step. Any changes to index.mode set on this page will be overwritten by the Logistics selection.' ); // Click Next button diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index dd6a420d27fb..52b3484ed50e 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -341,7 +341,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const currentUrl = await browser.getCurrentUrl(); const parsedUrl = new URL(currentUrl); const baseUrl = `${parsedUrl.protocol}//${parsedUrl.host}`; - const expectedUrlPattern = `${baseUrl}/app/observabilityOnboarding/?category=logs`; + const expectedUrlPattern = `${baseUrl}/app/observabilityOnboarding/?category=host`; expect(currentUrl).to.equal(expectedUrlPattern); }); }); diff --git a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts index 46d20489e4d3..39c6b33d2f3e 100644 --- a/x-pack/test/functional/apps/infra/metrics_source_configuration.ts +++ b/x-pack/test/functional/apps/infra/metrics_source_configuration.ts @@ -7,13 +7,10 @@ import { cleanup, Dataset, generate, PartialConfig } from '@kbn/data-forge'; import expect from '@kbn/expect'; -import { - Aggregators, - InfraRuleType, - MetricThresholdParams, -} from '@kbn/infra-plugin/common/alerting/metrics'; +import { Aggregators, MetricThresholdParams } from '@kbn/infra-plugin/common/alerting/metrics'; import { COMPARATORS } from '@kbn/alerting-comparators'; +import { InfraRuleType } from '@kbn/rule-data-utils'; import { createRule } from '../../../alerting_api_integration/observability/helpers/alerting_api_helper'; import { waitForDocumentInIndex, diff --git a/x-pack/test/functional/apps/lens/group3/add_to_dashboard.ts b/x-pack/test/functional/apps/lens/group3/add_to_dashboard.ts index 433fc2dbc943..acf383fb946f 100644 --- a/x-pack/test/functional/apps/lens/group3/add_to_dashboard.ts +++ b/x-pack/test/functional/apps/lens/group3/add_to_dashboard.ts @@ -67,7 +67,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Average of bytes', '5,727.322'); - await dashboardPanelActions.expectNotLinkedToLibrary('New Lens from Modal', true); + await dashboardPanelActions.expectNotLinkedToLibrary('New Lens from Modal'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(1); @@ -82,10 +82,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Maximum of bytes', '19,986'); - await dashboardPanelActions.expectNotLinkedToLibrary( - 'Artistpreviouslyknownaslens Copy', - true - ); + await dashboardPanelActions.expectNotLinkedToLibrary('Artistpreviouslyknownaslens Copy'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(1); @@ -109,7 +106,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Average of bytes', '5,727.322'); - await dashboardPanelActions.expectNotLinkedToLibrary('New Lens from Modal', true); + await dashboardPanelActions.expectNotLinkedToLibrary('New Lens from Modal'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(2); @@ -131,10 +128,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Maximum of bytes', '19,986'); - await dashboardPanelActions.expectNotLinkedToLibrary( - 'Artistpreviouslyknownaslens Copy', - true - ); + await dashboardPanelActions.expectNotLinkedToLibrary('Artistpreviouslyknownaslens Copy'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(2); @@ -147,7 +141,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Average of bytes', '5,727.322'); - await dashboardPanelActions.expectLinkedToLibrary('New by ref Lens from Modal', true); + await dashboardPanelActions.expectLinkedToLibrary('New by ref Lens from Modal'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(1); @@ -162,7 +156,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Maximum of bytes', '19,986'); - await dashboardPanelActions.expectLinkedToLibrary('Artistpreviouslyknownaslens by ref', true); + await dashboardPanelActions.expectLinkedToLibrary('Artistpreviouslyknownaslens by ref'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(1); @@ -186,7 +180,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Average of bytes', '5,727.322'); - await dashboardPanelActions.expectLinkedToLibrary('New Lens by ref from Modal', true); + await dashboardPanelActions.expectLinkedToLibrary('New Lens by ref from Modal'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(2); @@ -208,10 +202,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await lens.assertLegacyMetric('Maximum of bytes', '19,986'); - await dashboardPanelActions.expectLinkedToLibrary( - 'Artistpreviouslyknownaslens by ref 2', - true - ); + await dashboardPanelActions.expectLinkedToLibrary('Artistpreviouslyknownaslens by ref 2'); const panelCount = await dashboard.getPanelCount(); expect(panelCount).to.eql(2); diff --git a/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts b/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts index 3790c22c377b..4ff6da617bbd 100644 --- a/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts +++ b/x-pack/test/functional/apps/lens/group3/dashboard_inline_editing.ts @@ -85,7 +85,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboard.waitForRenderComplete(); await elasticChart.setNewChartUiDebugFlag(true); - await dashboardPanelActions.legacySaveToLibrary('My by reference visualization'); + await dashboardPanelActions.saveToLibrary('My by reference visualization'); await dashboardPanelActions.clickInlineEdit(); @@ -138,6 +138,71 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await timeToVisualize.resetNewDashboard(); }); + it('should reset changes made to the previous chart with adHoc dataView created from dashboard', async () => { + await dashboard.navigateToApp(); + await dashboard.clickNewDashboard(); + + // it creates a XY histogram with a breakdown by ip + await lens.createAndAddLensFromDashboard({ useAdHocDataView: true }); + await elasticChart.setNewChartUiDebugFlag(true); + // now edit inline and remove the breakdown dimension + await dashboardPanelActions.clickInlineEdit(); + await lens.removeDimension('lnsXY_splitDimensionPanel'); + + log.debug('Cancels the changes'); + await testSubjects.click('cancelFlyoutButton'); + await dashboard.waitForRenderComplete(); + + const data = await lens.getCurrentChartDebugStateForVizType('xyVisChart'); + expect(data?.bars?.length).to.be.above(1); + // open the inline editor again and check that the breakdown is still there + await dashboardPanelActions.clickInlineEdit(); + expect(await testSubjects.exists('lnsXY_splitDimensionPanel')).to.be(true); + // exit via cancel again + await testSubjects.click('cancelFlyoutButton'); + }); + + it('should reset changes made to the previous chart created from dashboard', async () => { + await dashboardPanelActions.removePanel(); + + // it creates a XY histogram with a breakdown by ip + await lens.createAndAddLensFromDashboard({}); + + await dashboard.waitForRenderComplete(); + await elasticChart.setNewChartUiDebugFlag(true); + // now edit inline and remove the breakdown dimension + await dashboardPanelActions.clickInlineEdit(); + await lens.removeDimension('lnsXY_splitDimensionPanel'); + + log.debug('Cancels the changes'); + await testSubjects.click('cancelFlyoutButton'); + await dashboard.waitForRenderComplete(); + + const data = await lens.getCurrentChartDebugStateForVizType('xyVisChart'); + expect(data?.bars?.length).to.be.above(1); + // open the inline editor again and check that the breakdown is still there + await dashboardPanelActions.clickInlineEdit(); + expect(await testSubjects.exists('lnsXY_splitDimensionPanel')).to.be(true); + // exit via cancel again + await testSubjects.click('cancelFlyoutButton'); + }); + + it('should apply changes made in the inline editing panel', async () => { + // now delete the breakdown dimension and check that has been saved + await dashboardPanelActions.clickInlineEdit(); + await lens.removeDimension('lnsXY_splitDimensionPanel'); + + log.debug('Applies the changes'); + await testSubjects.click('applyFlyoutButton'); + await dashboard.waitForRenderComplete(); + + const data = await lens.getCurrentChartDebugStateForVizType('xyVisChart'); + expect(data?.bars?.length).to.eql(1); + // reset all things + await elasticChart.setNewChartUiDebugFlag(false); + await timeToVisualize.resetNewDashboard(); + }); + it('should allow adding an annotation', async () => { await loadExistingLens(); await lens.save('xyVisChart Copy', true, false, false, 'new'); diff --git a/x-pack/test/functional/apps/lens/group4/dashboard.ts b/x-pack/test/functional/apps/lens/group4/dashboard.ts index 670ee2cb22da..0efdd026e05f 100644 --- a/x-pack/test/functional/apps/lens/group4/dashboard.ts +++ b/x-pack/test/functional/apps/lens/group4/dashboard.ts @@ -27,6 +27,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const panelActions = getService('dashboardPanelActions'); const inspector = getService('inspector'); const queryBar = getService('queryBar'); + const dashboardDrilldownsManage = getService('dashboardDrilldownsManage'); + const dashboardDrilldownPanelActions = getService('dashboardDrilldownPanelActions'); async function clickInChart(x: number, y: number) { const el = await elasticChart.getCanvas(); @@ -228,11 +230,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await find.clickByButtonText('lnsPieVis'); await dashboardAddPanel.closeAddPanel(); - await panelActions.legacyUnlinkFromLibrary('lnsPieVis'); + await panelActions.unlinkFromLibrary('lnsPieVis'); }); it('save lens panel to embeddable library', async () => { - await panelActions.legacySaveToLibrary('lnsPieVis - copy', 'lnsPieVis'); + await panelActions.saveToLibrary('lnsPieVis - copy', 'lnsPieVis'); await dashboardAddPanel.clickOpenAddPanel(); await dashboardAddPanel.filterEmbeddableNames('lnsPieVis'); @@ -320,5 +322,40 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.switchToWindow(windowHandlers[0]); } }); + + it('should add a drilldown to a Lens by-value chart', async () => { + await dashboard.navigateToApp(); + await dashboard.clickNewDashboard(); + await dashboardAddPanel.clickOpenAddPanel(); + await dashboardAddPanel.filterEmbeddableNames('lnsPieVis'); + await find.clickByButtonText('lnsPieVis'); + await dashboardAddPanel.closeAddPanel(); + + // add a drilldown to the pie chart + await dashboardDrilldownPanelActions.clickCreateDrilldown(); + await testSubjects.click('actionFactoryItem-OPEN_IN_DISCOVER_DRILLDOWN'); + await dashboardDrilldownsManage.saveChanges(); + await dashboardDrilldownsManage.closeFlyout(); + await header.waitUntilLoadingHasFinished(); + + // check that the drilldown is working now + await clickInChart(5, 5); // hardcoded position of the slice, depends heavy on data and charts implementation + expect( + await find.existsByCssSelector('[data-test-subj^="embeddablePanelAction-D_ACTION"]') + ).to.be(true); + + // save the dashboard + await dashboard.saveDashboard('dashboardWithDrilldown'); + + // re-open the dashboard and check the drilldown is still there + await dashboard.navigateToApp(); + await dashboard.loadSavedDashboard('dashboardWithDrilldown'); + await header.waitUntilLoadingHasFinished(); + + await clickInChart(5, 5); // hardcoded position of the slice, depends heavy on data and charts implementation + expect( + await find.existsByCssSelector('[data-test-subj^="embeddablePanelAction-D_ACTION"]') + ).to.be(true); + }); }); } diff --git a/x-pack/test/functional/apps/lens/group4/index.ts b/x-pack/test/functional/apps/lens/group4/index.ts index 61074d6aa6d7..7caadad31c12 100644 --- a/x-pack/test/functional/apps/lens/group4/index.ts +++ b/x-pack/test/functional/apps/lens/group4/index.ts @@ -81,7 +81,6 @@ export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext loadTestFile(require.resolve('./show_underlying_data_dashboard')); // 2m 10s loadTestFile(require.resolve('./share')); // 1m 20s // keep it last in the group - loadTestFile(require.resolve('./tsdb')); // 1m - loadTestFile(require.resolve('./logsdb')); // 1m + loadTestFile(require.resolve('./tsdb')); // 3m 56s }); }; diff --git a/x-pack/test/functional/apps/lens/group4/show_underlying_data_dashboard.ts b/x-pack/test/functional/apps/lens/group4/show_underlying_data_dashboard.ts index 40169ef15ccf..4227835b2227 100644 --- a/x-pack/test/functional/apps/lens/group4/show_underlying_data_dashboard.ts +++ b/x-pack/test/functional/apps/lens/group4/show_underlying_data_dashboard.ts @@ -23,6 +23,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const listingTable = getService('listingTable'); const testSubjects = getService('testSubjects'); const dashboardPanelActions = getService('dashboardPanelActions'); + const monacoEditor = getService('monacoEditor'); + const dashboardAddPanel = getService('dashboardAddPanel'); const filterBarService = getService('filterBar'); const queryBar = getService('queryBar'); const savedQueryManagementComponent = getService('savedQueryManagementComponent'); @@ -58,7 +60,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should show the open button for a compatible saved visualization with annotations and reference line', async () => { await dashboard.switchToEditMode(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await header.waitUntilLoadingHasFinished(); await lens.createLayer('annotations'); await lens.waitForVisualization('xyVisChart'); @@ -88,7 +90,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should bring both dashboard context and visualization context to discover', async () => { await dashboard.switchToEditMode(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await savedQueryManagementComponent.openSavedQueryManagementComponent(); await queryBar.switchQueryLanguage('lucene'); await savedQueryManagementComponent.closeSavedQueryManagementComponent(); @@ -139,5 +141,53 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await browser.closeCurrentWindow(); await browser.switchToWindow(dashboardWindowHandle); }); + + it.skip('should bring visualization context to discover for Lens ES|QL panels', async () => { + // clear out the dashboard + await dashboard.switchToEditMode(); + await dashboardPanelActions.openContextMenu(); + await dashboardPanelActions.removePanel(); + await queryBar.setQuery(''); + await queryBar.submitQuery(); + await filterBarService.removeAllFilters(); + + // Create a new panel + await dashboardAddPanel.clickEditorMenuButton(); + await dashboardAddPanel.clickAddNewPanelFromUIActionLink('ES|QL'); + await dashboardAddPanel.expectEditorMenuClosed(); + + const ESQL_QUERY = 'from logs* | stats maxB = max(bytes)'; + // Configure the ES|QL chart + await monacoEditor.setCodeEditorValue(ESQL_QUERY); + await testSubjects.click('ESQLEditor-run-query-button'); + await header.waitUntilLoadingHasFinished(); + + const lensQuery = await monacoEditor.getCodeEditorValue(); + expect(lensQuery).to.equal(ESQL_QUERY); + await testSubjects.click('applyFlyoutButton'); + + // Save the dashboard + await dashboard.clickQuickSave(); + await dashboard.clickCancelOutOfEditMode(); + + // check if it works correctly + await dashboardPanelActions.clickPanelAction(OPEN_IN_DISCOVER_DATA_TEST_SUBJ); + + const [dashboardWindowHandle, discoverWindowHandle] = await browser.getAllWindowHandles(); + await browser.switchToWindow(discoverWindowHandle); + + // wait to discover to load + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + // now check that all queries and filters are correctly transferred + const discoverQuery = await monacoEditor.getCodeEditorValue(); + expect(discoverQuery).to.equal(ESQL_QUERY); + // Filters and queries should not be carried over. + // There's currently a bug but in this test will check only the right thing + + await browser.closeCurrentWindow(); + await browser.switchToWindow(dashboardWindowHandle); + }); }); } diff --git a/x-pack/test/functional/apps/lens/group4/tsdb.ts b/x-pack/test/functional/apps/lens/group4/tsdb.ts index 3a6aac5ffa39..3834fc837b9d 100644 --- a/x-pack/test/functional/apps/lens/group4/tsdb.ts +++ b/x-pack/test/functional/apps/lens/group4/tsdb.ts @@ -17,7 +17,7 @@ import { getDocsGenerator, setupScenarioRunner, sumFirstNValues, -} from './tsdb_logsdb_helpers'; +} from '../tsdb_logsdb_helpers'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const { common, lens, dashboard } = getPageObjects(['common', 'lens', 'dashboard']); diff --git a/x-pack/test/functional/apps/lens/group6/error_handling.ts b/x-pack/test/functional/apps/lens/group6/error_handling.ts index 1b035fab6397..9ac57287feb0 100644 --- a/x-pack/test/functional/apps/lens/group6/error_handling.ts +++ b/x-pack/test/functional/apps/lens/group6/error_handling.ts @@ -108,7 +108,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await testSubjects.find('emptyPlaceholder'); await dashboard.switchToEditMode(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await timePicker.waitForNoDataPopover(); await timePicker.ensureHiddenNoDataPopover(); diff --git a/x-pack/test/functional/apps/lens/group6/lens_tagging.ts b/x-pack/test/functional/apps/lens/group6/lens_tagging.ts index b6b441249f21..bb39217bd886 100644 --- a/x-pack/test/functional/apps/lens/group6/lens_tagging.ts +++ b/x-pack/test/functional/apps/lens/group6/lens_tagging.ts @@ -90,7 +90,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('retains its saved object tags after save and return', async () => { - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.saveAndReturn(); await header.waitUntilLoadingHasFinished(); diff --git a/x-pack/test/functional/apps/lens/group6/workspace_size.ts b/x-pack/test/functional/apps/lens/group6/workspace_size.ts index 9ae8f21cebf6..86f5c481fff6 100644 --- a/x-pack/test/functional/apps/lens/group6/workspace_size.ts +++ b/x-pack/test/functional/apps/lens/group6/workspace_size.ts @@ -267,15 +267,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await assertWorkspaceDimensions('600px', '375px'); }); - // Fails in chrome 128+: https://github.com/elastic/kibana-operations/issues/199 - it.skip('gauge size (absolute pixels) - major arc', async () => { + it('gauge size (absolute pixels) - major arc', async () => { await lens.openVisualOptions(); await lens.setGaugeShape('Major arc'); await assertWorkspaceDimensions('600px', '430px'); }); - // Fails in chrome 129+: https://github.com/elastic/kibana-operations/issues/199 - it.skip('gauge size (absolute pixels) - circle', async () => { + it('gauge size (absolute pixels) - circle', async () => { await lens.openVisualOptions(); await lens.setGaugeShape('Circle'); await assertWorkspaceDimensions('600px', '430px'); diff --git a/x-pack/test/functional/apps/lens/group7/config.ts b/x-pack/test/functional/apps/lens/group7/config.ts new file mode 100644 index 000000000000..d927f93adeff --- /dev/null +++ b/x-pack/test/functional/apps/lens/group7/config.ts @@ -0,0 +1,17 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const functionalConfig = await readConfigFile(require.resolve('../../../config.base.js')); + + return { + ...functionalConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/x-pack/test/functional/apps/lens/group7/index.ts b/x-pack/test/functional/apps/lens/group7/index.ts new file mode 100644 index 000000000000..0ef20e053081 --- /dev/null +++ b/x-pack/test/functional/apps/lens/group7/index.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { EsArchiver } from '@kbn/es-archiver'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext) => { + const browser = getService('browser'); + const log = getService('log'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const { timePicker } = getPageObjects(['timePicker']); + const config = getService('config'); + let remoteEsArchiver; + + describe('lens app - group 4', () => { + const esArchive = 'x-pack/test/functional/es_archives/logstash_functional'; + const localIndexPatternString = 'logstash-*'; + const remoteIndexPatternString = 'ftr-remote:logstash-*'; + const localFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/default', + }; + + const remoteFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/default', + }; + let esNode: EsArchiver; + let fixtureDirs: { + lensBasic: string; + lensDefault: string; + }; + let indexPatternString: string; + before(async () => { + await log.debug('Starting lens before method'); + await browser.setWindowSize(1280, 1200); + await kibanaServer.savedObjects.cleanStandardList(); + try { + config.get('esTestCluster.ccs'); + remoteEsArchiver = getService('remoteEsArchiver' as 'esArchiver'); + esNode = remoteEsArchiver; + fixtureDirs = remoteFixtures; + indexPatternString = remoteIndexPatternString; + } catch (error) { + esNode = esArchiver; + fixtureDirs = localFixtures; + indexPatternString = localIndexPatternString; + } + + await esNode.load(esArchive); + // changing the timepicker default here saves us from having to set it in Discover (~8s) + await timePicker.setDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.uiSettings.update({ + defaultIndex: indexPatternString, + 'dateFormat:tz': 'UTC', + }); + await kibanaServer.importExport.load(fixtureDirs.lensBasic); + await kibanaServer.importExport.load(fixtureDirs.lensDefault); + }); + + after(async () => { + await esArchiver.unload(esArchive); + await timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.importExport.unload(fixtureDirs.lensBasic); + await kibanaServer.importExport.unload(fixtureDirs.lensDefault); + await kibanaServer.savedObjects.cleanStandardList(); + }); + + // total run time ~30m + loadTestFile(require.resolve('./logsdb')); // 30m + }); +}; diff --git a/x-pack/test/functional/apps/lens/group4/logsdb.ts b/x-pack/test/functional/apps/lens/group7/logsdb.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group4/logsdb.ts rename to x-pack/test/functional/apps/lens/group7/logsdb.ts index 8071ad58ac09..5aeff039c488 100644 --- a/x-pack/test/functional/apps/lens/group4/logsdb.ts +++ b/x-pack/test/functional/apps/lens/group7/logsdb.ts @@ -14,7 +14,7 @@ import { getDocsGenerator, setupScenarioRunner, TIME_PICKER_FORMAT, -} from './tsdb_logsdb_helpers'; +} from '../tsdb_logsdb_helpers'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const { common, lens, discover, header, timePicker } = getPageObjects([ diff --git a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts index bf799673c249..6582fe21e62a 100644 --- a/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts +++ b/x-pack/test/functional/apps/lens/open_in_lens/tsvb/dashboard.ts @@ -27,7 +27,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const dashboardAddPanel = getService('dashboardAddPanel'); const filterBar = getService('filterBar'); - describe('Dashboard to TSVB to Lens', function describeIndexTests() { + // FLAKY: https://github.com/elastic/kibana/issues/179307 + describe.skip('Dashboard to TSVB to Lens', function describeIndexTests() { before(async () => { await visualize.initTests(); }); @@ -117,7 +118,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const titles = await dashboard.getPanelTitles(); expect(titles[0]).to.be(`${visTitle} (converted)`); - await panelActions.expectNotLinkedToLibrary(titles[0], true); + await panelActions.expectNotLinkedToLibrary(titles[0]); await dashboardBadgeActions.expectExistsTimeRangeBadgeAction(); await panelActions.removePanel(); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/tsdb_logsdb_helpers.ts b/x-pack/test/functional/apps/lens/tsdb_logsdb_helpers.ts similarity index 99% rename from x-pack/test_serverless/functional/test_suites/common/visualizations/group1/tsdb_logsdb_helpers.ts rename to x-pack/test/functional/apps/lens/tsdb_logsdb_helpers.ts index 23822aa1395a..d68040de27ae 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/tsdb_logsdb_helpers.ts +++ b/x-pack/test/functional/apps/lens/tsdb_logsdb_helpers.ts @@ -9,7 +9,7 @@ import { Client } from '@elastic/elasticsearch'; import { MappingProperty } from '@elastic/elasticsearch/lib/api/types'; import { ToolingLog } from '@kbn/tooling-log'; import moment from 'moment'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../ftr_provider_context'; export const TEST_DOC_COUNT = 100; export const TIME_PICKER_FORMAT = 'MMM D, YYYY [@] HH:mm:ss.SSS'; diff --git a/x-pack/test/functional/es_archives/observability/alerts/data.json.gz b/x-pack/test/functional/es_archives/observability/alerts/data.json.gz index 4017aaab1bdd..bcab15f41c44 100644 Binary files a/x-pack/test/functional/es_archives/observability/alerts/data.json.gz and b/x-pack/test/functional/es_archives/observability/alerts/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/security_solution/alerts/8.1.0/data.json.gz b/x-pack/test/functional/es_archives/security_solution/alerts/8.1.0/data.json.gz index 50d664aa24ce..bebcb0d90f83 100644 Binary files a/x-pack/test/functional/es_archives/security_solution/alerts/8.1.0/data.json.gz and b/x-pack/test/functional/es_archives/security_solution/alerts/8.1.0/data.json.gz differ diff --git a/x-pack/test/functional/es_archives/task_manager_removed_types/data.json b/x-pack/test/functional/es_archives/task_manager_removed_types/data.json index 3fc1a2cad2d2..29333b60b292 100644 --- a/x-pack/test/functional/es_archives/task_manager_removed_types/data.json +++ b/x-pack/test/functional/es_archives/task_manager_removed_types/data.json @@ -2,11 +2,9 @@ "type": "doc", "value": { "id": "task:ce7e1250-3322-11eb-94c1-db6995e83f6b", - "index": ".kibana_task_manager_1", + "index": ".kibana_task_manager", "source": { - "migrationVersion": { - "task": "7.6.0" - }, + "typeMigrationVersion": "7.6.0", "references": [ ], "task": { @@ -33,11 +31,9 @@ "type": "doc", "value": { "id": "task:be7e1250-3322-11eb-94c1-db6995e83f6a", - "index": ".kibana_task_manager_1", + "index": ".kibana_task_manager", "source": { - "migrationVersion": { - "task": "7.6.0" - }, + "typeMigrationVersion": "7.6.0", "references": [ ], "task": { diff --git a/x-pack/test/functional/es_archives/task_manager_removed_types/mappings.json b/x-pack/test/functional/es_archives/task_manager_removed_types/mappings.json deleted file mode 100644 index f35681efb089..000000000000 --- a/x-pack/test/functional/es_archives/task_manager_removed_types/mappings.json +++ /dev/null @@ -1,224 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana": { - } - }, - "index": ".kibana_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "action": "6e96ac5e648f57523879661ea72525b7", - "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", - "alert": "0359d7fcc04da9878ee9aadbda38ba55", - "api_key_pending_invalidation": "16f515278a295f6245149ad7c5ddedb7", - "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", - "apm-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "app_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", - "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", - "search-session": "721df406dbb7e35ac22e4df6c3ad2b2a", - "canvas-element": "7390014e1091044523666d97247392fc", - "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", - "canvas-workpad-template": "ae2673f678281e2c055d764b153e9715", - "cases": "477f214ff61acc3af26a7b7818e380c1", - "cases-comments": "8a50736330e953bca91747723a319593", - "cases-configure": "387c5f3a3bda7e0ae0dd4e106f914a69", - "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", - "config": "c63748b75f39d0c54de12d12c1ccbc20", - "dashboard": "40554caf09725935e2c02e02563a2d07", - "endpoint:user-artifact": "4a11183eee21e6fbad864f7a30b39ad0", - "endpoint:user-artifact-manifest": "a0d7b04ad405eed54d76e279c3727862", - "enterprise_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "epm-packages": "2b83397e3eaaaa8ef15e38813f3721c3", - "event_log_test": "bef808d4a9c27f204ffbda3359233931", - "exception-list": "67f055ab8c10abd7b2ebfd969b836788", - "exception-list-agnostic": "67f055ab8c10abd7b2ebfd969b836788", - "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", - "fleet-agent-actions": "9511b565b1cc6441a42033db3d5de8e9", - "fleet-agent-events": "e20a508b6e805189356be381dbfac8db", - "fleet-agents": "cb661e8ede2b640c42c8e5ef99db0683", - "fleet-enrollment-api-keys": "a69ef7ae661dab31561d6c6f052ef2a7", - "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", - "index-pattern": "45915a1ad866812242df474eb0479052", - "infrastructure-ui-source": "3d1b76c39bfb2cc8296b024d73854724", - "ingest-agent-policies": "8b0733cce189659593659dad8db426f0", - "ingest-outputs": "8854f34453a47e26f86a29f8f3b80b4e", - "ingest-package-policies": "c91ca97b1ff700f0fc64dc6b13d65a85", - "ingest_manager_settings": "02a03095f0e05b7a538fa801b88a217f", - "inventory-view": "3d1b76c39bfb2cc8296b024d73854724", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "lens": "52346cfec69ff7b47d5f0c12361a2797", - "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", - "map": "4a05b35c3a3a58fbc72dd0202dc3487f", - "maps-telemetry": "5ef305b18111b77789afefbd36b66171", - "metrics-explorer-view": "3d1b76c39bfb2cc8296b024d73854724", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "ml-job": "3bb64c31915acf93fc724af137a0891b", - "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", - "monitoring-telemetry": "2669d5ec15e82391cf58df4294ee9c68", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "43012c7ebc4cb57054e0a490e4b43023", - "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "siem-detection-engine-rule-actions": "6569b288c169539db10cb262bf79de18", - "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", - "siem-ui-timeline": "d12c5474364d737d17252acf1dc4585c", - "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", - "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", - "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", - "tag": "83d55da58f6530f7055415717ec06474", - "telemetry": "36a616f7026dfa617d6655df850fe16d", - "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "upgrade-assistant-reindex-operation": "215107c281839ea9b3ad5f6419819763", - "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", - "uptime-dynamic-settings": "3d1b76c39bfb2cc8296b024d73854724", - "url": "c7f66a0df8b1b52f17c28c4adb111105", - "visualization": "f819cf6636b75c9e76ba733a0c6ef355", - "workplace_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724" - } - }, - "dynamic": "strict", - "properties": { - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - ".kibana_task_manager": { - } - }, - "index": ".kibana_task_manager_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "task": "235412e52d09e7165fac8a67a43ad6b4", - "type": "2f4316de49999235636386fe51dc06c1", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0" - } - }, - "dynamic": "strict", - "properties": { - "migrationVersion": { - "dynamic": "true", - "properties": { - "task": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "task": { - "properties": { - "attempts": { - "type": "integer" - }, - "ownerId": { - "type": "keyword" - }, - "params": { - "type": "text" - }, - "retryAt": { - "type": "date" - }, - "runAt": { - "type": "date" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledAt": { - "type": "date" - }, - "scope": { - "type": "keyword" - }, - "startedAt": { - "type": "date" - }, - "state": { - "type": "text" - }, - "status": { - "type": "keyword" - }, - "taskType": { - "type": "keyword" - }, - "user": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/page_objects/dataset_quality.ts b/x-pack/test/functional/page_objects/dataset_quality.ts index cef881fe0797..47a9261c906f 100644 --- a/x-pack/test/functional/page_objects/dataset_quality.ts +++ b/x-pack/test/functional/page_objects/dataset_quality.ts @@ -205,7 +205,10 @@ export function DatasetQualityPageObject({ getPageObjects, getService }: FtrProv }, async waitUntilPossibleMitigationsLoaded() { - await find.waitForDeletedByCssSelector('.euiFlyoutBody .euiSkeletonRectangle', 20 * 1000); + await find.waitForDeletedByCssSelector( + '.euiFlyoutBody .datasetQualityDetailsFlyoutManualMitigationsLoading', + 20 * 1000 + ); }, async waitUntilDegradedFieldFlyoutLoaded() { diff --git a/x-pack/test/functional/page_objects/infra_saved_views.ts b/x-pack/test/functional/page_objects/infra_saved_views.ts index 2f19c959f355..5286808b40fe 100644 --- a/x-pack/test/functional/page_objects/infra_saved_views.ts +++ b/x-pack/test/functional/page_objects/infra_saved_views.ts @@ -13,6 +13,7 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) { const retry = getService('retry'); const testSubjects = getService('testSubjects'); const browser = getService('browser'); + const config = getService('config'); return { async clickSavedViewsButton() { @@ -25,13 +26,15 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) { return button.click(); }, - pressEsc() { + async pressEsc() { return browser.pressKeys([Key.ESCAPE]); }, async closeSavedViewsPopover() { - await testSubjects.find('savedViews-popover'); - return this.pressEsc(); + await retry.tryForTime(config.get('timeouts.try'), async () => { + await this.pressEsc(); + await testSubjects.missingOrFail('loadViewsFlyout'); + }); }, clickManageViewsButton() { @@ -55,7 +58,7 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) { await testSubjects.setValue('savedViewName', name); await testSubjects.click('createSavedViewButton'); await testSubjects.missingOrFail('createSavedViewButton', { timeout: 20000 }); - await retry.tryForTime(10 * 1000, async () => { + await retry.tryForTime(config.get('timeouts.try'), async () => { await testSubjects.missingOrFail('savedViews-upsertModal'); }); }, @@ -71,7 +74,7 @@ export function InfraSavedViewsProvider({ getService }: FtrProviderContext) { }, async ensureViewIsLoaded(name: string) { - await retry.tryForTime(5000, async () => { + await retry.tryForTime(config.get('timeouts.try'), async () => { const subject = await testSubjects.find('savedViews-openPopover'); expect(await subject.getVisibleText()).to.be(name); }); diff --git a/x-pack/test/functional/page_objects/lens_page.ts b/x-pack/test/functional/page_objects/lens_page.ts index f4db890b2695..47eacb260498 100644 --- a/x-pack/test/functional/page_objects/lens_page.ts +++ b/x-pack/test/functional/page_objects/lens_page.ts @@ -34,6 +34,7 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont const browser = getService('browser'); const dashboardAddPanel = getService('dashboardAddPanel'); const queryBar = getService('queryBar'); + const dataViews = getService('dataViews'); const { common, header, timePicker, dashboard, timeToVisualize, unifiedSearch, share } = getPageObjects([ @@ -1486,10 +1487,12 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont title, redirectToOrigin, ignoreTimeFilter, + useAdHocDataView, }: { title?: string; redirectToOrigin?: boolean; ignoreTimeFilter?: boolean; + useAdHocDataView?: boolean; }) { log.debug(`createAndAddLens${title}`); const inViewMode = await dashboard.getIsInViewMode(); @@ -1502,6 +1505,10 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont await this.goToTimeRange(); } + if (useAdHocDataView) { + await dataViews.createFromSearchBar({ name: '*stash*', adHoc: true }); + } + await this.configureDimension({ dimension: 'lnsXY_yDimensionPanel > lns-empty-dimension', operation: 'average', @@ -2044,5 +2051,9 @@ export function LensPageProvider({ getService, getPageObjects }: FtrProviderCont return { maxWidth, maxHeight, minWidth, minHeight, aspectRatio }; }, + + async toggleDebug(enable: boolean = true) { + await browser.execute(`window.ELASTIC_LENS_LOGGER = arguments[0];`, enable); + }, }); } diff --git a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts index 3da7659419f0..a0a243dad7d8 100644 --- a/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts +++ b/x-pack/test/functional/services/aiops/log_rate_analysis_page.ts @@ -13,6 +13,7 @@ import type { LogRateAnalysisType } from '@kbn/aiops-log-rate-analysis'; import type { FtrProviderContext } from '../../ftr_provider_context'; import type { LogRateAnalysisDataGenerator } from './log_rate_analysis_data_generator'; +import { CreateCaseParams } from '../cases/create'; export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrProviderContext) { const browser = getService('browser'); @@ -22,6 +23,7 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr const retry = getService('retry'); const header = getPageObject('header'); const dashboardPage = getPageObject('dashboard'); + const cases = getService('cases'); return { async assertTimeRangeSelectorSectionExists() { @@ -435,5 +437,22 @@ export function LogRateAnalysisPageProvider({ getService, getPageObject }: FtrPr await this.confirmAttachToDashboard(); await this.completeSaveToDashboardForm(true); }, + + async assertAttachToCaseButtonDisabled() { + const button = await testSubjects.find('aiopsLogRateAnalysisAttachToCaseButton'); + const isEnabled = await button.isEnabled(); + expect(isEnabled).to.be(false); + }, + + async clickAttachToCase() { + await testSubjects.click('aiopsLogRateAnalysisAttachToCaseButton'); + }, + + async attachToCase(params: CreateCaseParams) { + await this.openAttachmentsMenu(); + await this.clickAttachToCase(); + + await cases.create.createCaseFromModal(params); + }, }; } diff --git a/x-pack/test/functional/services/cases/create.ts b/x-pack/test/functional/services/cases/create.ts index 3f7b6e1e65f9..f1aec2c8a51b 100644 --- a/x-pack/test/functional/services/cases/create.ts +++ b/x-pack/test/functional/services/cases/create.ts @@ -129,9 +129,12 @@ export function CasesCreateViewServiceProvider( async createCaseFromModal(params: CreateCaseParams) { await casesCommon.assertCaseModalVisible(true); - await testSubjects.click('cases-table-add-case-filter-bar'); - await casesCommon.assertCaseModalVisible(false); + await retry.tryForTime(5000, async () => { + await testSubjects.click('cases-table-add-case-filter-bar'); + await casesCommon.assertCaseModalVisible(false); + }); + await this.creteCaseFromFlyout(params); }, }; diff --git a/x-pack/test/functional/services/ml/alerting.ts b/x-pack/test/functional/services/ml/alerting.ts index 74c6eb735ea3..9a42c09e8829 100644 --- a/x-pack/test/functional/services/ml/alerting.ts +++ b/x-pack/test/functional/services/ml/alerting.ts @@ -28,7 +28,7 @@ export function MachineLearningAlertingProvider( async selectAnomalyDetectionAlertType() { await retry.tryForTime(5000, async () => { await testSubjects.click('xpack.ml.anomaly_detection_alert-SelectOption'); - await testSubjects.existOrFail(`mlAnomalyAlertForm`, { timeout: 1000 }); + await testSubjects.existOrFail(`mlAnomalyAlertForm`); }); }, diff --git a/x-pack/test/functional/services/ml/api.ts b/x-pack/test/functional/services/ml/api.ts index 0a3d988fd750..3d2d1004528d 100644 --- a/x-pack/test/functional/services/ml/api.ts +++ b/x-pack/test/functional/services/ml/api.ts @@ -85,7 +85,6 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { const retry = getService('retry'); const esSupertest = getService('esSupertest'); const kbnSupertest = getService('supertest'); - const esDeleteAllIndices = getService('esDeleteAllIndices'); return { assertResponseStatusCode(expectedStatus: number, actualStatus: number, responseBody: object) { @@ -310,8 +309,37 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { log.debug('> Indices deleted.'); }, + async deleteExpiredAnomalyDetectionData() { + log.debug('Deleting expired data ...'); + const { body, status } = await esSupertest.delete('/_ml/_delete_expired_data'); + this.assertResponseStatusCode(200, status, body); + log.debug('> Expired data deleted.'); + }, + + async cleanAnomalyDetection() { + await this.deleteAllAnomalyDetectionJobs(); + await this.deleteAllCalendars(); + await this.deleteAllFilters(); + await this.deleteAllAnnotations(); + await this.deleteExpiredAnomalyDetectionData(); + await this.syncSavedObjects(); + }, + + async cleanDataFrameAnalytics() { + await this.deleteAllDataFrameAnalyticsJobs(); + await this.syncSavedObjects(); + }, + + async cleanTrainedModels() { + await this.deleteAllTrainedModelsIngestPipelines(); + await this.deleteAllTrainedModelsES(); + await this.syncSavedObjects(); + }, + async cleanMlIndices() { - await esDeleteAllIndices('.ml-*'); + await this.cleanAnomalyDetection(); + await this.cleanDataFrameAnalytics(); + await this.cleanTrainedModels(); }, async getJobState(jobId: string): Promise { @@ -537,6 +565,12 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { return response; }, + async getAllCalendars(expectedCode = 200) { + const response = await esSupertest.get('/_ml/calendars/_all'); + this.assertResponseStatusCode(expectedCode, response.status, response.body); + return response; + }, + async createCalendar( calendarId: string, requestBody: Partial = { description: '', job_ids: [] } @@ -559,6 +593,14 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { log.debug('> Calendar deleted.'); }, + async deleteAllCalendars() { + log.debug('Deleting all calendars'); + const getAllCalendarsRsp = await this.getAllCalendars(); + for (const calendar of getAllCalendarsRsp.body.calendars) { + await this.deleteCalendar(calendar.calendar_id); + } + }, + async waitForCalendarToExist(calendarId: string, errorMsg?: string) { await retry.waitForWithTimeout(`'${calendarId}' to exist`, 5 * 1000, async () => { if (await this.getCalendar(calendarId, 200)) { @@ -660,6 +702,12 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { return response; }, + async getAllAnomalyDetectionJobs() { + const response = await esSupertest.get('/_ml/anomaly_detectors/_all'); + this.assertResponseStatusCode(200, response.status, response.body); + return response; + }, + async getAnomalyDetectionJobsKibana(jobId?: string, space?: string) { const { body, status } = await kbnSupertest .get( @@ -831,6 +879,14 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { log.debug('> AD job deleted.'); }, + async deleteAllAnomalyDetectionJobs() { + log.debug('Deleting all anomaly detection jobs'); + const getAllAdJobsResp = await this.getAllAnomalyDetectionJobs(); + for (const job of getAllAdJobsResp.body.jobs) { + await this.deleteAnomalyDetectionJobES(job.job_id); + } + }, + async getDatafeed(datafeedId: string) { const response = await esSupertest.get(`/_ml/datafeeds/${datafeedId}`); this.assertResponseStatusCode(200, response.status, response.body); @@ -1034,6 +1090,12 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { log.debug('> DFA job created.'); }, + async getAllDataFrameAnalyticsJobs(expectedCode = 200) { + const response = await esSupertest.get('/_ml/data_frame/analytics/_all'); + this.assertResponseStatusCode(expectedCode, response.status, response.body); + return response; + }, + async createDataFrameAnalyticsJobES(jobConfig: DataFrameAnalyticsConfig) { const { id: analyticsId, ...analyticsConfig } = jobConfig; log.debug(`Creating data frame analytic job with id '${analyticsId}' via ES API...`); @@ -1064,6 +1126,14 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { log.debug('> DFA job deleted.'); }, + async deleteAllDataFrameAnalyticsJobs() { + log.debug('Deleting all data frame analytics jobs'); + const getAllDfaJobsResp = await this.getAllDataFrameAnalyticsJobs(); + for (const job of getAllDfaJobsResp.body.data_frame_analytics) { + await this.deleteDataFrameAnalyticsJobES(job.id); + } + }, + async getADJobRecordCount(jobId: string): Promise { const jobStats = await this.getADJobStats(jobId); @@ -1114,12 +1184,24 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { ); }, + async filterExists(filterId: string): Promise { + const { status } = await esSupertest.get(`/_ml/filters/${filterId}`); + if (status !== 200) return false; + return true; + }, + async getFilter(filterId: string, expectedCode = 200) { const response = await esSupertest.get(`/_ml/filters/${filterId}`); this.assertResponseStatusCode(expectedCode, response.status, response.body); return response; }, + async getAllFilters(expectedCode = 200) { + const response = await esSupertest.get(`/_ml/filters`); + this.assertResponseStatusCode(expectedCode, response.status, response.body); + return response; + }, + async createFilter(filterId: string, requestBody: object) { log.debug(`Creating filter with id '${filterId}'...`); const { body, status } = await esSupertest.put(`/_ml/filters/${filterId}`).send(requestBody); @@ -1131,12 +1213,27 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { async deleteFilter(filterId: string) { log.debug(`Deleting filter with id '${filterId}'...`); - await esSupertest.delete(`/_ml/filters/${filterId}`); + + if ((await this.filterExists(filterId)) === false) { + log.debug('> Filter does not exist, nothing to delete'); + return; + } + + const { body, status } = await esSupertest.delete(`/_ml/filters/${filterId}`); + this.assertResponseStatusCode(200, status, body); await this.waitForFilterToNotExist(filterId, `expected filter '${filterId}' to be deleted`); log.debug('> Filter deleted.'); }, + async deleteAllFilters() { + log.debug('Deleting all filters'); + const getAllFiltersRsp = await this.getAllFilters(); + for (const filter of getAllFiltersRsp.body.filters) { + await this.deleteFilter(filter.filter_id); + } + }, + async assertModelMemoryLimitForJob(jobId: string, expectedMml: string) { const { body: { @@ -1198,6 +1295,25 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { return body.hits.hits; }, + async getAllAnnotations() { + log.debug('Fetching all annotations ...'); + + if ( + (await es.indices.exists({ + index: ML_ANNOTATIONS_INDEX_ALIAS_READ, + allow_no_indices: false, + })) === false + ) { + return []; + } + + const body = await es.search({ index: ML_ANNOTATIONS_INDEX_ALIAS_READ }); + expect(body).to.not.be(undefined); + expect(body).to.have.property('hits'); + log.debug('> All annotations fetched.'); + return body.hits.hits; + }, + async getAnnotationById(annotationId: string): Promise { log.debug(`Fetching annotation '${annotationId}'...`); @@ -1264,6 +1380,24 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { ); }, + async deleteAnnotation(annotationId: string) { + log.debug(`Deleting annotation with id "${annotationId}"`); + const { body, status } = await kbnSupertest + .delete(`/internal/ml/annotations/delete/${annotationId}`) + .set(getCommonRequestHeader('1')); + this.assertResponseStatusCode(200, status, body); + + log.debug('> Annotation deleted'); + }, + + async deleteAllAnnotations() { + log.debug('Deleting all annotations.'); + const allAnnotations = await this.getAllAnnotations(); + for (const annotation of allAnnotations) { + await this.deleteAnnotation(annotation._id!); + } + }, + async runDFAJob(dfaId: string) { log.debug(`Starting data frame analytics job '${dfaId}'...`); const { body: startResponse, status } = await esSupertest @@ -1647,6 +1781,18 @@ export function MachineLearningAPIProvider({ getService }: FtrProviderContext) { log.debug('> Ingest pipeline deleted'); }, + async deleteAllTrainedModelsIngestPipelines() { + log.debug(`Deleting all trained models ingest pipelines`); + const getModelsRsp = await this.getTrainedModelsES(); + for (const model of getModelsRsp.trained_model_configs) { + if (this.isInternalModelId(model.model_id)) { + log.debug(`> Skipping internal ${model.model_id}`); + continue; + } + await this.deleteIngestPipeline(model.model_id); + } + }, + async assureMlStatsIndexExists(timeout: number = 60 * 1000) { const params = { index: '.ml-stats-000001', diff --git a/x-pack/test/functional/services/ml/cases.ts b/x-pack/test/functional/services/ml/cases.ts index 224541098559..3f31e6da65df 100644 --- a/x-pack/test/functional/services/ml/cases.ts +++ b/x-pack/test/functional/services/ml/cases.ts @@ -94,5 +94,13 @@ export function MachineLearningCasesProvider( await testSubjects.existOrFail('comment-persistableState-aiopsChangePointChart'); await testSubjects.existOrFail('aiopsEmbeddableChangePointChart'); }, + + async assertCaseWithLogRateAnalysisAttachment(params: CaseParams) { + await this.assertBasicCaseProps(params); + await testSubjects.existOrFail('comment-persistableState-aiopsLogRateAnalysisEmbeddable'); + await testSubjects.existOrFail('aiopsEmbeddableLogRateAnalysis'); + await testSubjects.existOrFail('aiopsDocumentCountChart'); + await testSubjects.existOrFail('aiopsLogRateAnalysisResults'); + }, }; } diff --git a/x-pack/test/functional/services/ml/supplied_configurations.ts b/x-pack/test/functional/services/ml/supplied_configurations.ts index 622d66299453..ff92877fcc4b 100644 --- a/x-pack/test/functional/services/ml/supplied_configurations.ts +++ b/x-pack/test/functional/services/ml/supplied_configurations.ts @@ -27,7 +27,7 @@ export function MachineLearningSuppliedConfigurationsProvider({ getService }: Ft ); }, async assertAllConfigurationsAreLoaded() { - const expectedLength = 18; + const expectedLength = 19; await retry.tryForTime(10 * 1000, async () => { const cards = await testSubjects.findAll('mlSuppliedConfigurationsCard'); expect(cards.length).to.eql( diff --git a/x-pack/test/functional/services/rules/common.ts b/x-pack/test/functional/services/rules/common.ts index 934fdefef10e..fcc1bf26099c 100644 --- a/x-pack/test/functional/services/rules/common.ts +++ b/x-pack/test/functional/services/rules/common.ts @@ -27,7 +27,7 @@ export function RulesCommonServiceProvider({ getService, getPageObject }: FtrPro }, async cancelRuleCreation() { - await testSubjects.click('cancelSaveRuleButton'); + await testSubjects.click('rulePageFooterCancelButton'); await testSubjects.existOrFail('confirmRuleCloseModal'); await testSubjects.click('confirmRuleCloseModal > confirmModalConfirmButton'); await testSubjects.missingOrFail('confirmRuleCloseModal'); @@ -43,8 +43,6 @@ export function RulesCommonServiceProvider({ getService, getPageObject }: FtrPro await browser.refresh(); await this.clickCreateAlertButton(); await testSubjects.click(`.index-threshold-SelectOption`); - await testSubjects.scrollIntoView('ruleNameInput'); - await testSubjects.setValue('ruleNameInput', alertName); await testSubjects.scrollIntoView('selectIndexExpression'); await testSubjects.click('selectIndexExpression'); await comboBox.set('thresholdIndexesComboBox', 'k'); @@ -55,9 +53,6 @@ export function RulesCommonServiceProvider({ getService, getPageObject }: FtrPro await fieldOptions[1].click(); }); await testSubjects.click('closePopover'); - // need this two out of popup clicks to close them - const nameInput = await testSubjects.find('ruleNameInput'); - await nameInput.click(); await testSubjects.click('whenExpression'); await testSubjects.click('whenExpressionSelect'); @@ -74,6 +69,9 @@ export function RulesCommonServiceProvider({ getService, getPageObject }: FtrPro const ofOptions = ofOptionsString.trim().split('\n'); expect(ofOptions.length > 0).to.be(true); await comboBox.set('availableFieldsOptionsComboBox', ofOptions[0]); + + await testSubjects.scrollIntoView('ruleDetailsNameInput'); + await testSubjects.setValue('ruleDetailsNameInput', alertName); }, }; } diff --git a/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts b/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts index 010bae3ba4bb..ab4dc572517c 100644 --- a/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts +++ b/x-pack/test/functional_basic/apps/ml/permissions/full_ml_access.ts @@ -32,8 +32,6 @@ export default function ({ getService }: FtrProviderContext) { const expectedUploadFileTitle = 'artificial_server_log'; before(async () => { - await ml.api.cleanMlIndices(); - await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); diff --git a/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts b/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts index 96aec074ec55..14a4be1ac8fd 100644 --- a/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts +++ b/x-pack/test/functional_basic/apps/ml/permissions/read_ml_access.ts @@ -32,8 +32,6 @@ export default function ({ getService }: FtrProviderContext) { const expectedUploadFileTitle = 'artificial_server_log'; before(async () => { - await ml.api.cleanMlIndices(); - await esArchiver.loadIfNeeded( 'x-pack/test/functional/es_archives/ml/module_sample_ecommerce' ); diff --git a/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts b/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts index 9f6d33d9ca16..78c79375f3e9 100644 --- a/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts +++ b/x-pack/test/functional_execution_context/plugins/alerts/server/plugin.ts @@ -7,7 +7,7 @@ import apmAgent from 'elastic-apm-node'; import type { Plugin, CoreSetup } from '@kbn/core/server'; -import { PluginSetupContract as AlertingPluginSetup } from '@kbn/alerting-plugin/server/plugin'; +import { AlertingServerSetup } from '@kbn/alerting-plugin/server/plugin'; import { EncryptedSavedObjectsPluginStart } from '@kbn/encrypted-saved-objects-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; import { SpacesPluginStart } from '@kbn/spaces-plugin/server'; @@ -16,7 +16,7 @@ import { KibanaFeatureScope } from '@kbn/features-plugin/common'; export interface FixtureSetupDeps { features: FeaturesPluginSetup; - alerting: AlertingPluginSetup; + alerting: AlertingServerSetup; } export interface FixtureStartDeps { @@ -34,8 +34,8 @@ export class FixturePlugin implements Plugin { - await testSubjects.setValue('ruleNameInput', newAlert); - const ruleName = await testSubjects.getAttribute('ruleNameInput', 'value'); + await testSubjects.setValue('ruleDetailsNameInput', newAlert); + const ruleName = await testSubjects.getAttribute('ruleDetailsNameInput', 'value'); return ruleName === newAlert; }); @@ -641,10 +641,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await sourceDataViewOption.click(); - await testSubjects.click('saveRuleButton'); + await testSubjects.click('rulePageFooterSaveButton'); await retry.waitFor('confirmation modal', async () => { - return await testSubjects.exists('confirmModalConfirmButton'); + return await testSubjects.exists('rulePageConfirmCreateRule'); }); await testSubjects.click('confirmModalConfirmButton'); diff --git a/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts index 58c72ef9d1a2..e76093c666ca 100644 --- a/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/discover_ml_uptime/ml/alert_flyout.ts @@ -134,6 +134,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.triggersActionsUI.setAlertName('ml-test-alert'); await pageObjects.triggersActionsUI.setAlertInterval(10, 's'); await pageObjects.triggersActionsUI.saveAlert(); + await ml.navigation.navigateToAlertsAndAction(); await pageObjects.triggersActionsUI.clickOnAlertInAlertsList('ml-test-alert'); }); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts index 121bb753e434..8be74bd57db6 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/alert_create_flyout.ts @@ -47,6 +47,30 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); } + async function createWebhookConnector(connectorName: string) { + await pageObjects.common.navigateToApp('triggersActionsConnectors'); + await testSubjects.click('connectorsTab'); + + await testSubjects.click('createConnectorButton'); + await testSubjects.scrollIntoView('.webhook-card'); + await testSubjects.click('.webhook-card'); + + await testSubjects.setValue('nameInput', connectorName); + await testSubjects.setValue('webhookUrlText', 'https://test.test'); + await testSubjects.setValue('webhookUserInput', 'fakeuser'); + await testSubjects.setValue('webhookPasswordInput', 'fakepassword'); + + await retry.try(async () => { + await find.clickByCssSelector( + '[data-test-subj="create-connector-flyout-save-btn"]:not(disabled)' + ); + await testSubjects.click('create-connector-flyout-save-btn'); + }); + + const toastTitle = await toasts.getTitleAndDismiss(); + expect(toastTitle).to.eql(`Created '${connectorName}'`); + } + async function deleteConnectorByName(connectorName: string) { const { body: connectors } = await supertest.get(`/api/actions/connectors`).expect(200); const connector = connectors?.find((c: { name: string }) => c.name === connectorName); @@ -62,7 +86,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { async function defineEsQueryAlert(alertName: string) { await pageObjects.triggersActionsUI.clickCreateAlertButton(); await testSubjects.click(`.es-query-SelectOption`); - await testSubjects.setValue('ruleNameInput', alertName); + await testSubjects.setValue('ruleDetailsNameInput', alertName); await testSubjects.click('queryFormType_esQuery'); await testSubjects.click('selectIndexExpression'); await comboBox.set('thresholdIndexesComboBox', 'k'); @@ -74,33 +98,39 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); await testSubjects.click('closePopover'); // need this two out of popup clicks to close them - const nameInput = await testSubjects.find('ruleNameInput'); + const nameInput = await testSubjects.find('ruleDetailsNameInput'); await nameInput.click(); } async function defineAPMErrorCountRule(ruleName: string) { await pageObjects.triggersActionsUI.clickCreateAlertButton(); await testSubjects.click(`apm.error_rate-SelectOption`); - await testSubjects.setValue('ruleNameInput', ruleName); + await testSubjects.setValue('ruleDetailsNameInput', ruleName); } async function defineAlwaysFiringAlert(alertName: string) { await pageObjects.triggersActionsUI.clickCreateAlertButton(); await testSubjects.click('test.always-firing-SelectOption'); - await testSubjects.setValue('ruleNameInput', alertName); + await testSubjects.scrollIntoView('ruleDetailsNameInput'); + await testSubjects.setValue('ruleDetailsNameInput', alertName); } async function discardNewRuleCreation() { await rules.common.cancelRuleCreation(); } + // Failing: See https://github.com/elastic/kibana/issues/196153 // Failing: See https://github.com/elastic/kibana/issues/196153 describe.skip('create alert', function () { let apmSynthtraceEsClient: ApmSynthtraceEsClient; + const webhookConnectorName = 'webhook-test'; before(async () => { await esArchiver.load( 'test/api_integration/fixtures/es_archiver/index_patterns/constant_keyword' ); + + await createWebhookConnector(webhookConnectorName); + const version = (await apmSynthtraceKibanaClient.installApmPackage()).version; apmSynthtraceEsClient = await getApmSynthtraceEsClient({ client: esClient, @@ -137,10 +167,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); after(async () => { - await apmSynthtraceEsClient.clean(); + await apmSynthtraceEsClient?.clean(); await esArchiver.unload( 'test/api_integration/fixtures/es_archiver/index_patterns/constant_keyword' ); + + await deleteConnectorByName(webhookConnectorName); }); beforeEach(async () => { @@ -153,24 +185,25 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const ruleName = generateUniqueKey(); await rules.common.defineIndexThresholdAlert(ruleName); - // create webhook connector - await testSubjects.click('.webhook-alerting-ActionTypeSelectOption'); - await testSubjects.click('createActionConnectorButton-0'); - await testSubjects.setValue('nameInput', 'webhook-test'); - await testSubjects.setValue('webhookUrlText', 'https://test.test'); - await testSubjects.setValue('webhookUserInput', 'fakeuser'); - await testSubjects.setValue('webhookPasswordInput', 'fakepassword'); - - // save rule - await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); + // add webhook connector 1 + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText(webhookConnectorName); await find.setValueByClass('kibanaCodeEditor', 'myUniqueKey'); - await testSubjects.click('saveRuleButton'); + + await testSubjects.click('rulePageFooterSaveButton'); // add new action and remove first one - await testSubjects.click('ruleSidebarEditAction'); - await testSubjects.click('.webhook-alerting-ActionTypeSelectOption'); + await testSubjects.click('openEditRuleFlyoutButton'); + + // add webhook connector 2 + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText(webhookConnectorName); + await find.setValueByClass('kibanaCodeEditor', 'myUniqueKey1'); + await find.clickByCssSelector( - '[data-test-subj="alertActionAccordion-0"] [aria-label="Delete"]' + '[data-test-subj="ruleActionsItem"] [data-test-subj="ruleActionsItemDeleteButton"]' ); // check that the removed action is the right one @@ -184,7 +217,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { // Additional cleanup step to prevent // FLAKY: https://github.com/elastic/kibana/issues/167443 // FLAKY: https://github.com/elastic/kibana/issues/167444 - await deleteConnectorByName('webhook-test'); }); it('should create an alert', async () => { @@ -198,29 +230,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.setValue('filterKuery', 'group: group-0'); expect(await filterKueryInput.elementHasClass('euiFieldSearch-isInvalid')).to.eql(false); - await testSubjects.click('.slack-alerting-ActionTypeSelectOption'); - await testSubjects.click('addNewActionConnectorButton-.slack'); - const slackConnectorName = generateUniqueKey(); - await testSubjects.setValue('nameInput', slackConnectorName); - await testSubjects.setValue('slackWebhookUrlInput', 'https://test.com'); - await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); - const createdConnectorToastTitle = await toasts.getTitleAndDismiss(); - expect(createdConnectorToastTitle).to.eql(`Created '${slackConnectorName}'`); - await testSubjects.click('notifyWhenSelect'); - await testSubjects.click('onThrottleInterval'); - await testSubjects.setValue('throttleInput', '10'); - - // Alerts search bar (conditional actions) - await testSubjects.click('alertsFilterQueryToggle'); - - await pageObjects.header.waitUntilLoadingHasFinished(); - await testSubjects.click('addFilter'); - await testSubjects.click('filterFieldSuggestionList'); - await comboBox.set('filterFieldSuggestionList', '_id'); - await comboBox.set('filterOperatorList', 'is not'); - await testSubjects.setValue('filterParams', 'fake-rule-id'); - await testSubjects.click('saveFilter'); - await testSubjects.setValue('queryInput', '_id: *'); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText('Slack#xyztest'); const messageTextArea = await find.byCssSelector('[data-test-subj="messageTextArea"]'); expect(await messageTextArea.getAttribute('value')).to.eql( @@ -246,9 +258,29 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { 'test message {{alert.actionGroup}} some additional text {{rule.id}}' ); - await testSubjects.click('saveRuleButton'); + await find.clickByButtonText('Settings'); + await testSubjects.click('notifyWhenSelect'); + await testSubjects.click('onThrottleInterval'); + await testSubjects.setValue('throttleInput', '10'); + + // Alerts search bar (conditional actions) + await testSubjects.click('alertsFilterQueryToggle'); + + await pageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.click('addFilter'); + await testSubjects.click('filterFieldSuggestionList'); + await comboBox.set('filterFieldSuggestionList', '_id'); + await comboBox.set('filterOperatorList', 'is not'); + await testSubjects.setValue('filterParams', 'fake-rule-id'); + await testSubjects.click('saveFilter'); + await testSubjects.setValue('queryInput', '_id: *'); + + await testSubjects.click('rulePageFooterSaveButton'); const toastTitle = await toasts.getTitleAndDismiss(); expect(toastTitle).to.eql(`Created rule "${alertName}"`); + + await pageObjects.common.navigateToApp('triggersActions'); + await testSubjects.click('rulesTab'); await pageObjects.triggersActionsUI.searchAlerts(alertName); const searchResultsAfterSave = await pageObjects.triggersActionsUI.getAlertsList(); const searchResultAfterSave = searchResultsAfterSave[0]; @@ -275,14 +307,35 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.setValue('filterKuery', 'group: group-0'); expect(await filterKueryInput.elementHasClass('euiFieldSearch-isInvalid')).to.eql(false); - await testSubjects.click('.slack-alerting-ActionTypeSelectOption'); - await testSubjects.click('addNewActionConnectorButton-.slack'); - const slackConnectorName = generateUniqueKey(); - await testSubjects.setValue('nameInput', slackConnectorName); - await testSubjects.setValue('slackWebhookUrlInput', 'https://test.com'); - await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); - const createdConnectorToastTitle = await toasts.getTitleAndDismiss(); - expect(createdConnectorToastTitle).to.eql(`Created '${slackConnectorName}'`); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText('Slack#xyztest'); + + const messageTextArea = await find.byCssSelector('[data-test-subj="messageTextArea"]'); + expect(await messageTextArea.getAttribute('value')).to.eql( + `Rule {{rule.name}} is active for group {{context.group}}: + +- Value: {{context.value}} +- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}} +- Timestamp: {{context.date}}` + ); + await testSubjects.setValue('messageTextArea', 'test message '); + await testSubjects.click('messageAddVariableButton'); + await testSubjects.click('variableMenuButton-alert.actionGroup'); + expect(await messageTextArea.getAttribute('value')).to.eql( + 'test message {{alert.actionGroup}}' + ); + await messageTextArea.type(' some additional text '); + + await testSubjects.click('messageAddVariableButton'); + await testSubjects.setValue('messageVariablesSelectableSearch', 'rule.id'); + await testSubjects.click('variableMenuButton-rule.id'); + + expect(await messageTextArea.getAttribute('value')).to.eql( + 'test message {{alert.actionGroup}} some additional text {{rule.id}}' + ); + + await find.clickByButtonText('Settings'); await testSubjects.click('notifyWhenSelect'); await testSubjects.click('onThrottleInterval'); await testSubjects.setValue('throttleInput', '10'); @@ -314,32 +367,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.click('saveFilter'); await testSubjects.setValue('queryInput', '_id: *'); - const messageTextArea = await find.byCssSelector('[data-test-subj="messageTextArea"]'); - expect(await messageTextArea.getAttribute('value')).to.eql( - `Rule {{rule.name}} is active for group {{context.group}}: - -- Value: {{context.value}} -- Conditions Met: {{context.conditions}} over {{rule.params.timeWindowSize}}{{rule.params.timeWindowUnit}} -- Timestamp: {{context.date}}` - ); - await testSubjects.setValue('messageTextArea', 'test message '); - await testSubjects.click('messageAddVariableButton'); - await testSubjects.click('variableMenuButton-alert.actionGroup'); - expect(await messageTextArea.getAttribute('value')).to.eql( - 'test message {{alert.actionGroup}}' - ); - await messageTextArea.type(' some additional text '); - - await testSubjects.click('messageAddVariableButton'); - await testSubjects.setValue('messageVariablesSelectableSearch', 'rule.id'); - await testSubjects.click('variableMenuButton-rule.id'); - - expect(await messageTextArea.getAttribute('value')).to.eql( - 'test message {{alert.actionGroup}} some additional text {{rule.id}}' - ); - await testSubjects.click('saveRuleButton'); + await testSubjects.click('rulePageFooterSaveButton'); const toastTitle = await toasts.getTitleAndDismiss(); expect(toastTitle).to.eql(`Created rule "${alertName}"`); + + await pageObjects.common.navigateToApp('triggersActions'); + await testSubjects.click('rulesTab'); await pageObjects.triggersActionsUI.searchAlerts(alertName); const searchResultsAfterSave = await pageObjects.triggersActionsUI.getAlertsList(); const searchResultAfterSave = searchResultsAfterSave[0]; @@ -366,14 +399,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.setValue('filterKuery', 'group: group-0'); expect(await filterKueryInput.elementHasClass('euiFieldSearch-isInvalid')).to.eql(false); - await testSubjects.click('.slack-alerting-ActionTypeSelectOption'); - await testSubjects.click('addNewActionConnectorButton-.slack'); - const slackConnectorName = generateUniqueKey(); - await testSubjects.setValue('nameInput', slackConnectorName); - await testSubjects.setValue('slackWebhookUrlInput', 'https://test.com'); - await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); - const createdConnectorToastTitle = await toasts.getTitleAndDismiss(); - expect(createdConnectorToastTitle).to.eql(`Created '${slackConnectorName}'`); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText('Slack#xyztest'); + + await find.clickByButtonText('Settings'); await testSubjects.click('notifyWhenSelect'); await testSubjects.click('onThrottleInterval'); await testSubjects.setValue('throttleInput', '10'); @@ -384,19 +414,19 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const filter = `{ "bool": { - "filter": [{ "term": { "kibana.alert.rule.consumer": "*" } }] + "filter": [{ "term": { "kibana.alert.rule.name": "${alertName}" } }] } }`; - await filterBar.addDslFilter(filter, true); - - await testSubjects.click('saveRuleButton'); + await filterBar.addDslFilter(filter); + await testSubjects.click('rulePageFooterSaveButton'); const toastTitle = await toasts.getTitleAndDismiss(); expect(toastTitle).to.eql(`Created rule "${alertName}"`); - await testSubjects.click('editActionHoverButton'); + await testSubjects.click('openEditRuleFlyoutButton'); await pageObjects.header.waitUntilLoadingHasFinished(); + await find.clickByButtonText('Settings'); await testSubjects.scrollIntoView('globalQueryBar'); await filterBar.hasFilter('query', filter, true); @@ -410,37 +440,36 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const alertName = generateUniqueKey(); await defineAlwaysFiringAlert(alertName); - // create Slack connector and attach an action using it - await testSubjects.click('.slack-alerting-ActionTypeSelectOption'); - await testSubjects.click('addNewActionConnectorButton-.slack'); - const slackConnectorName = generateUniqueKey(); - await testSubjects.setValue('nameInput', slackConnectorName); - await testSubjects.setValue('slackWebhookUrlInput', 'https://test.com'); - await find.clickByCssSelector('[data-test-subj="saveActionButtonModal"]:not(disabled)'); - const createdConnectorToastTitle = await toasts.getTitleAndDismiss(); - expect(createdConnectorToastTitle).to.eql(`Created '${slackConnectorName}'`); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText('Slack#xyztest'); + await testSubjects.setValue('messageTextArea', 'test message '); await ( await find.byCssSelector( - '[data-test-subj="alertActionAccordion-0"] [data-test-subj="messageTextArea"]' + '[data-test-subj="ruleActionsItem"] [data-test-subj="messageTextArea"]' ) ).type('some text '); + await find.clickByButtonText('Settings'); + await testSubjects.click('ruleActionsSettingsSelectActionGroup'); + await testSubjects.click('addNewActionConnectorActionGroup-recovered'); - await testSubjects.click('addAlertActionButton'); - await testSubjects.click('.slack-alerting-ActionTypeSelectOption'); - await testSubjects.setValue('messageTextArea', 'test message '); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText('Slack#xyztest'); + + const actionItems = await find.allByCssSelector('[data-test-subj="ruleActionsItem"]'); await ( - await find.byCssSelector( - '[data-test-subj="alertActionAccordion-1"] [data-test-subj="messageTextArea"]' - ) + await actionItems[1].findByCssSelector('[data-test-subj="messageTextArea"]') ).type('some text '); - await testSubjects.click('addNewActionConnectorActionGroup-1'); - await testSubjects.click('addNewActionConnectorActionGroup-1-option-other'); - - await testSubjects.click('saveRuleButton'); + await testSubjects.click('rulePageFooterSaveButton'); const toastTitle = await toasts.getTitleAndDismiss(); expect(toastTitle).to.eql(`Created rule "${alertName}"`); + + await pageObjects.common.navigateToApp('triggersActions'); + await testSubjects.click('rulesTab'); + await pageObjects.triggersActionsUI.searchAlerts(alertName); const searchResultsAfterSave = await pageObjects.triggersActionsUI.getAlertsList(); const searchResultAfterSave = searchResultsAfterSave[0]; @@ -459,20 +488,24 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const alertName = generateUniqueKey(); await defineAlwaysFiringAlert(alertName); - await testSubjects.click('saveRuleButton'); - await testSubjects.existOrFail('confirmRuleSaveModal'); - await testSubjects.click('confirmRuleSaveModal > confirmModalCancelButton'); + await testSubjects.click('rulePageFooterSaveButton'); + await testSubjects.existOrFail('rulePageConfirmCreateRule'); + await testSubjects.click('rulePageConfirmCreateRule > confirmModalCancelButton'); await testSubjects.missingOrFail('confirmRuleSaveModal'); - await find.existsByCssSelector('[data-test-subj="saveRuleButton"]:not(disabled)'); + await find.existsByCssSelector('[data-test-subj="rulePageFooterSaveButton"]:not(disabled)'); - await testSubjects.click('saveRuleButton'); - await testSubjects.existOrFail('confirmRuleSaveModal'); - await testSubjects.click('confirmRuleSaveModal > confirmModalConfirmButton'); - await testSubjects.missingOrFail('confirmRuleSaveModal'); + await testSubjects.click('rulePageFooterSaveButton'); + await testSubjects.existOrFail('rulePageConfirmCreateRule'); + await testSubjects.click('rulePageConfirmCreateRule > confirmModalConfirmButton'); + await testSubjects.missingOrFail('rulePageConfirmCreateRule'); const toastTitle = await toasts.getTitleAndDismiss(); expect(toastTitle).to.eql(`Created rule "${alertName}"`); await new Promise((resolve) => setTimeout(resolve, 1000)); + + await pageObjects.common.navigateToApp('triggersActions'); + await testSubjects.click('rulesTab'); + await pageObjects.triggersActionsUI.searchAlerts(alertName); const searchResultsAfterSave = await pageObjects.triggersActionsUI.getAlertsList(); const searchResultAfterSave = searchResultsAfterSave[0]; @@ -490,13 +523,13 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should show discard confirmation before closing flyout without saving', async () => { await pageObjects.triggersActionsUI.clickCreateAlertButton(); await testSubjects.click(`.es-query-SelectOption`); - await testSubjects.click('cancelSaveRuleButton'); + await testSubjects.click('rulePageFooterCancelButton'); await testSubjects.missingOrFail('confirmRuleCloseModal'); await pageObjects.triggersActionsUI.clickCreateAlertButton(); await testSubjects.click(`.es-query-SelectOption`); - await testSubjects.setValue('ruleNameInput', 'alertName'); - await testSubjects.click('cancelSaveRuleButton'); + await testSubjects.setValue('ruleDetailsNameInput', 'alertName'); + await testSubjects.click('rulePageFooterCancelButton'); await testSubjects.existOrFail('confirmRuleCloseModal'); await testSubjects.click('confirmRuleCloseModal > confirmModalCancelButton'); await testSubjects.missingOrFail('confirmRuleCloseModal'); @@ -521,7 +554,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.missingOrFail('testQuerySuccess'); await testSubjects.existOrFail('testQueryError'); await testSubjects.setValue('queryJsonEditor', ''); - await discardNewRuleCreation(); + + await testSubjects.click('rulePageFooterCancelButton'); + + const confirmRuleCloseModalExists = await testSubjects.exists('confirmRuleCloseModal'); + if (confirmRuleCloseModalExists) { + await testSubjects.click('confirmRuleCloseModal > confirmModalConfirmButton'); + await testSubjects.missingOrFail('confirmRuleCloseModal'); + } }); // Related issue that this test is trying to prevent: @@ -554,65 +594,23 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.existOrFail('testQuerySuccess'); await testSubjects.missingOrFail('testQueryError'); - await discardNewRuleCreation(); - }); - - it('should not do a type override when adding a second action', async () => { - // create a new rule - const ruleName = generateUniqueKey(); - await rules.common.defineIndexThresholdAlert(ruleName); - - // add server log action - await testSubjects.click('.server-log-alerting-ActionTypeSelectOption'); - expect( - await find.existsByCssSelector( - '[data-test-subj="comboBoxSearchInput"][value="Serverlog#xyz"]' - ) - ).to.eql(true); - expect( - await find.existsByCssSelector( - '[data-test-subj="comboBoxSearchInput"][value="webhook-test"]' - ) - ).to.eql(false); - - // click on add new action - await testSubjects.click('addAlertActionButton'); - await find.existsByCssSelector('[data-test-subj="Serverlog#xyz"]'); - - // create webhook connector - await testSubjects.click('.webhook-alerting-ActionTypeSelectOption'); - await testSubjects.click('createActionConnectorButton-1'); - await testSubjects.setValue('nameInput', 'webhook-test'); - await testSubjects.setValue('webhookUrlText', 'https://test.test'); - await testSubjects.setValue('webhookUserInput', 'fakeuser'); - await testSubjects.setValue('webhookPasswordInput', 'fakepassword'); - await testSubjects.click('saveActionButtonModal'); - - // checking the new one first to avoid flakiness. If the value is checked before the new one is added - // it might return a false positive - expect( - await find.existsByCssSelector( - '[data-test-subj="comboBoxSearchInput"][value="webhook-test"]' - ) - ).to.eql(true); - // If it was overridden, the value would change to be empty - expect( - await find.existsByCssSelector( - '[data-test-subj="comboBoxSearchInput"][value="Serverlog#xyz"]' - ) - ).to.eql(true); + await testSubjects.click('rulePageFooterCancelButton'); - await deleteConnectorByName('webhook-test'); + const confirmRuleCloseModalExists = await testSubjects.exists('confirmRuleCloseModal'); + if (confirmRuleCloseModalExists) { + await testSubjects.click('confirmRuleCloseModal > confirmModalConfirmButton'); + await testSubjects.missingOrFail('confirmRuleCloseModal'); + } }); it('should add filter', async () => { const ruleName = generateUniqueKey(); await defineAlwaysFiringAlert(ruleName); - await testSubjects.click('saveRuleButton'); - await testSubjects.existOrFail('confirmRuleSaveModal'); - await testSubjects.click('confirmRuleSaveModal > confirmModalConfirmButton'); - await testSubjects.missingOrFail('confirmRuleSaveModal'); + await testSubjects.click('rulePageFooterSaveButton'); + await testSubjects.existOrFail('rulePageConfirmCreateRule'); + await testSubjects.click('rulePageConfirmCreateRule > confirmModalConfirmButton'); + await testSubjects.missingOrFail('rulePageConfirmCreateRule'); const toastTitle = await toasts.getTitleAndDismiss(); expect(toastTitle).to.eql(`Created rule "${ruleName}"`); @@ -625,7 +623,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { } }`; - await filterBar.addDslFilter(filter, true); + await filterBar.addDslFilter(filter); await filterBar.hasFilter('query', filter, true); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts index 6656103b6a89..c4eb6a7dcd09 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/opsgenie.ts @@ -307,48 +307,58 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should default to the create alert action', async () => { + await find.clickByButtonText('Message'); await testSubjects.existOrFail('messageInput'); expect(await testSubjects.getAttribute('aliasInput', 'value')).to.eql(defaultAlias); }); it('should default to the close alert action when setting the run when to recovered', async () => { - await testSubjects.click('addNewActionConnectorActionGroup-0'); - await testSubjects.click('addNewActionConnectorActionGroup-0-option-recovered'); + await find.clickByButtonText('Settings'); + await testSubjects.click('ruleActionsSettingsSelectActionGroup'); + await testSubjects.click('addNewActionConnectorActionGroup-recovered'); + await find.clickByButtonText('Message'); expect(await testSubjects.getAttribute('aliasInput', 'value')).to.eql(defaultAlias); await testSubjects.existOrFail('noteTextArea'); await testSubjects.missingOrFail('messageInput'); }); it('should not preserve the alias when switching run when to recover', async () => { + await find.clickByButtonText('Message'); await testSubjects.setValue('aliasInput', 'an alias'); - await testSubjects.click('addNewActionConnectorActionGroup-0'); - await testSubjects.click('addNewActionConnectorActionGroup-0-option-recovered'); - await testSubjects.missingOrFail('messageInput'); + await find.clickByButtonText('Settings'); + await testSubjects.click('ruleActionsSettingsSelectActionGroup'); + await testSubjects.click('addNewActionConnectorActionGroup-recovered'); + await find.clickByButtonText('Message'); + await testSubjects.missingOrFail('messageInput'); expect(await testSubjects.getAttribute('aliasInput', 'value')).to.be(defaultAlias); }); it('should not preserve the alias when switching run when to threshold met', async () => { - await testSubjects.click('addNewActionConnectorActionGroup-0'); - await testSubjects.click('addNewActionConnectorActionGroup-0-option-recovered'); - await testSubjects.missingOrFail('messageInput'); + await find.clickByButtonText('Settings'); + await testSubjects.click('ruleActionsSettingsSelectActionGroup'); + await testSubjects.click('addNewActionConnectorActionGroup-recovered'); + await find.clickByButtonText('Message'); + await testSubjects.missingOrFail('messageInput'); await testSubjects.setValue('aliasInput', 'an alias'); - await testSubjects.click('addNewActionConnectorActionGroup-0'); - await testSubjects.click('addNewActionConnectorActionGroup-0-option-threshold met'); - await testSubjects.exists('messageInput'); + await find.clickByButtonText('Settings'); + await testSubjects.click('ruleActionsSettingsSelectActionGroup'); + await testSubjects.click('addNewActionConnectorActionGroup-threshold met'); + + await find.clickByButtonText('Message'); + await testSubjects.exists('messageInput'); expect(await testSubjects.getAttribute('aliasInput', 'value')).to.be(defaultAlias); }); it('should show the message is required error when clicking the save button', async () => { - await testSubjects.click('saveRuleButton'); - const messageError = await find.byClassName('euiFormErrorText'); - - expect(await messageError.getVisibleText()).to.eql('Message is required.'); + expect( + await (await testSubjects.find('rulePageFooterSaveButton')).getAttribute('disabled') + ).to.be('true'); }); }); @@ -360,8 +370,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; const selectOpsgenieConnectorInRuleAction = async (name: string) => { - await testSubjects.click('.opsgenie-alerting-ActionTypeSelectOption'); - await testSubjects.selectValue('comboBoxInput', name); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText(name); + + await find.clickByButtonText('Settings'); await rules.common.setNotifyThrottleInput(); }; diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/slack.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/slack.ts index 026608ecf0e0..a7ea6aef95c8 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/slack.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/connectors/slack.ts @@ -14,6 +14,7 @@ import { createSlackConnectorAndObjectRemover, getConnectorByName } from './util export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects(['common', 'triggersActionsUI', 'header']); + const find = getService('find'); const retry = getService('retry'); const supertest = getService('supertest'); const actions = getService('actions'); @@ -119,10 +120,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { return response.body.data[0].id; }; - const selectSlackConnectorInRuleAction = async ({ connectorId }: { connectorId: string }) => { - await testSubjects.click('.slack-alerting-ActionTypeSelectOption'); // "Slack" in connector list - await testSubjects.click('selectActionConnector-.slack-0'); - await testSubjects.click(`dropdown-connector-${connectorId}`); + const selectSlackConnectorInRuleAction = async ({ + connectorName, + }: { + connectorName: string; + }) => { + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); + await find.clickByButtonText(connectorName); }; before(async () => { @@ -149,9 +154,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const ruleName = await setupRule(); await selectSlackConnectorInRuleAction({ - connectorId: webhookAction.id, + connectorName: webhookConnectorName, }); - await testSubjects.click('saveRuleButton'); + await testSubjects.click('rulePageFooterSaveButton'); + const toastTitle = await toasts.getTitleAndDismiss(); + expect(toastTitle).to.eql(`Created rule "${ruleName}"`); + + await pageObjects.common.navigateToApp('triggersActions'); + await testSubjects.click('rulesTab'); await pageObjects.triggersActionsUI.searchAlerts(ruleName); const ruleId = await getRuleIdByName(ruleName); @@ -166,9 +176,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { tags: '', }, ]); - - const toastTitle = await toasts.getTitleAndDismiss(); - expect(toastTitle).to.eql(`Created rule "${ruleName}"`); }); /* FUTURE ENGINEER @@ -179,7 +186,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it.skip('should save webapi type slack connectors', async () => { await setupRule(); await selectSlackConnectorInRuleAction({ - connectorId: webApiAction.id, + connectorName: webhookConnectorName, }); await testSubjects.click('saveRuleButton'); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts index 04a5d9701712..56150e5693a3 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/details.ts @@ -23,7 +23,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const retry = getService('retry'); const find = getService('find'); const supertest = getService('supertest'); - const comboBox = getService('comboBox'); const objectRemover = new ObjectRemover(supertest); const toasts = getService('toasts'); @@ -187,7 +186,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const editButton = await testSubjects.find('ruleIntervalToastEditButton'); await editButton.click(); - await testSubjects.click('cancelSaveEditedRuleButton'); + await testSubjects.click('rulePageFooterCancelButton'); }); it('should disable the rule', async () => { @@ -375,14 +374,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await editButton.click(); expect(await testSubjects.exists('hasActionsDisabled')).to.eql(false); - await testSubjects.setValue('ruleNameInput', updatedRuleName, { + await testSubjects.setValue('ruleDetailsNameInput', updatedRuleName, { clearWithKeyboard: true, }); - await find.clickByCssSelector('[data-test-subj="saveEditedRuleButton"]:not(disabled)'); + await find.clickByCssSelector('[data-test-subj="rulePageFooterSaveButton"]:not(disabled)'); const toastTitle = await toasts.getTitleAndDismiss(); - expect(toastTitle).to.eql(`Updated '${updatedRuleName}'`); + expect(toastTitle).to.eql(`Updated "${updatedRuleName}"`); await retry.tryForTime(30 * 1000, async () => { const headingText = await pageObjects.ruleDetailsUI.getHeadingText(); @@ -407,18 +406,18 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const editButton = await testSubjects.find('openEditRuleFlyoutButton'); await editButton.click(); - await testSubjects.setValue('ruleNameInput', uuidv4(), { + await testSubjects.setValue('ruleDetailsNameInput', uuidv4(), { clearWithKeyboard: true, }); - await testSubjects.click('cancelSaveEditedRuleButton'); + await testSubjects.click('rulePageFooterCancelButton'); await testSubjects.existOrFail('confirmRuleCloseModal'); await testSubjects.click('confirmRuleCloseModal > confirmModalConfirmButton'); - await find.waitForDeletedByCssSelector('[data-test-subj="cancelSaveEditedRuleButton"]'); + await find.waitForDeletedByCssSelector('[data-test-subj="rulePageFooterCancelButton"]'); await editButton.click(); - const nameInputAfterCancel = await testSubjects.find('ruleNameInput'); + const nameInputAfterCancel = await testSubjects.find('ruleDetailsNameInput'); const textAfterCancel = await nameInputAfterCancel.getAttribute('value'); expect(textAfterCancel).to.eql(updatedRuleName); }); @@ -482,127 +481,26 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await editButton.click(); expect(await testSubjects.exists('hasActionsDisabled')).to.eql(false); - expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).to.eql(false); - expect(await testSubjects.exists('alertActionAccordion-0')).to.eql(true); + const headerText = await find.byCssSelector('[data-test-subj="ruleActionsItem"] h2'); - expect(await testSubjects.exists('selectActionConnector-.slack-0')).to.eql(true); - // click the super selector the reveal the options - await testSubjects.click('selectActionConnector-.slack-0'); - // click the available option (my-slack1 is a preconfigured connector created before this test runs) - await testSubjects.click('dropdown-connector-my-slack1'); - expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).to.eql(true); - }); - - it('should show and update deleted connectors when there are no existing connectors of the same type', async () => { - const connector = await createConnectorManualCleanup({ - name: `index-${testRunUuid}-${0}`, - connector_type_id: '.index', - config: { - index: `index-${testRunUuid}-${0}`, - }, - secrets: {}, - }); - - await pageObjects.common.navigateToApp('triggersActions'); - const alert = await createAlwaysFiringRule({ - name: testRunUuid, - actions: [ - { - group: 'default', - id: connector.id, - params: { level: 'info', message: ' {{context.message}}' }, - frequency: { - summary: false, - notify_when: RuleNotifyWhen.THROTTLE, - throttle: '1m', - }, - }, - { - group: 'other', - id: connector.id, - params: { level: 'info', message: ' {{context.message}}' }, - frequency: { - summary: false, - notify_when: RuleNotifyWhen.THROTTLE, - throttle: '1m', - }, - }, - ], - }); - - // refresh to see alert - await browser.refresh(); - await pageObjects.header.waitUntilLoadingHasFinished(); - - // verify content - await testSubjects.existOrFail('rulesList'); - - // delete connector - await pageObjects.common.navigateToApp('triggersActionsConnectors'); - await pageObjects.triggersActionsUI.searchConnectors(connector.name); - await testSubjects.click('deleteConnector'); - await testSubjects.existOrFail('deleteIdsConfirmation'); - await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton'); - await testSubjects.missingOrFail('deleteIdsConfirmation'); - - const toastTitle = await toasts.getTitleAndDismiss(); - expect(toastTitle).to.eql('Deleted 1 connector'); - - // Wait to ensure the table is finished loading - await pageObjects.triggersActionsUI.tableFinishedLoading(); - - // click on first rule - await pageObjects.common.navigateToApp('triggersActions'); - await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(alert.name); - - const editButton = await testSubjects.find('openEditRuleFlyoutButton'); - await editButton.click(); - expect(await testSubjects.exists('hasActionsDisabled')).to.eql(false); - - expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).to.eql(false); - expect(await testSubjects.exists('alertActionAccordion-0')).to.eql(true); - expect(await testSubjects.exists('addNewActionConnectorActionGroup-1')).to.eql(false); - expect(await testSubjects.exists('alertActionAccordion-1')).to.eql(true); - - await testSubjects.click('createActionConnectorButton-0'); - await testSubjects.existOrFail('connectorAddModal'); - await testSubjects.setValue('nameInput', 'new connector'); - await retry.try(async () => { - // At times we find the driver controlling the ComboBox in tests - // can select the wrong item, this ensures we always select the correct index - await comboBox.set('connectorIndexesComboBox', 'test-index'); - expect( - await comboBox.isOptionSelected( - await testSubjects.find('connectorIndexesComboBox'), - 'test-index' - ) - ).to.be(true); - }); - await testSubjects.click('connectorAddModal > saveActionButtonModal'); - await testSubjects.missingOrFail('deleteIdsConfirmation'); + expect(await headerText.getVisibleText()).to.eql('Unable to find connector'); - expect(await testSubjects.exists('addNewActionConnectorActionGroup-0')).to.eql(true); - expect(await testSubjects.exists('addNewActionConnectorActionGroup-1')).to.eql(true); + await testSubjects.click('ruleActionsAddActionButton'); + await testSubjects.existOrFail('ruleActionsConnectorsModal'); - // delete connector - await pageObjects.common.navigateToApp('triggersActions'); - // refresh to see alert - await browser.refresh(); - await pageObjects.header.waitUntilLoadingHasFinished(); + // click the available option (my-slack1 is a preconfigured connector created before this test runs) + await find.clickByButtonText('Slack#xyztest'); - // verify content - await testSubjects.existOrFail('rulesList'); + const ruleActionItems = await testSubjects.findAll('ruleActionsItem'); + expect(ruleActionItems.length).to.eql(2); - await pageObjects.common.navigateToApp('triggersActionsConnectors'); - await pageObjects.triggersActionsUI.searchConnectors('new connector'); - await testSubjects.click('deleteConnector'); - await testSubjects.existOrFail('deleteIdsConfirmation'); - await testSubjects.click('deleteIdsConfirmation > confirmModalConfirmButton'); - await testSubjects.missingOrFail('deleteIdsConfirmation'); + expect(await ruleActionItems[0].getVisibleText()).to.contain('Slack'); + expect(await ruleActionItems[1].getVisibleText()).to.contain('Slack'); }); }); - describe('Edit rule with legacy rule-level notify values', function () { + // bug with legacy notify_when values https://github.com/elastic/kibana/issues/199494 + describe.skip('Edit rule with legacy rule-level notify values', function () { const testRunUuid = uuidv4(); afterEach(async () => { @@ -643,20 +541,22 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { const editButton = await testSubjects.find('openEditRuleFlyoutButton'); await editButton.click(); + + await find.clickByButtonText('Settings'); const notifyWhenSelect = await testSubjects.find('notifyWhenSelect'); expect(await notifyWhenSelect.getVisibleText()).to.eql('On custom action intervals'); const throttleInput = await testSubjects.find('throttleInput'); const throttleUnitInput = await testSubjects.find('throttleUnitInput'); expect(await throttleInput.getAttribute('value')).to.be('2'); expect(await throttleUnitInput.getAttribute('value')).to.be('d'); - await testSubjects.setValue('ruleNameInput', updatedRuleName, { + await testSubjects.setValue('ruleDetailsNameInput', updatedRuleName, { clearWithKeyboard: true, }); - await find.clickByCssSelector('[data-test-subj="saveEditedRuleButton"]:not(disabled)'); + await find.clickByCssSelector('[data-test-subj="rulePageFooterSaveButton"]:not(disabled)'); const toastTitle = await toasts.getTitleAndDismiss(); - expect(toastTitle).to.eql(`Updated '${updatedRuleName}'`); + expect(toastTitle).to.eql(`Updated '${rule.name}'`); }); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts index c03d6dcf74a8..bffe63a97634 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/home_page.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; import { ObjectRemover } from '../../lib/object_remover'; -import { getTestAlertData, getTestConnectorData } from '../../lib/get_test_data'; +import { getTestAlertData } from '../../lib/get_test_data'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const testSubjects = getService('testSubjects'); @@ -24,6 +24,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { before(async () => { await security.testUser.setRoles(['alerts_and_actions_role']); }); + after(async () => { await security.testUser.restoreDefaults(); }); @@ -41,6 +42,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { before(async () => { await security.testUser.setRoles(['only_actions_role']); }); + after(async () => { await security.testUser.restoreDefaults(); }); @@ -57,19 +59,35 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await pageObjects.common.navigateToApp('triggersActions'); }); - after(async () => { - await objectRemover.removeAll(); - }); - it('Loads the Alerts page', async () => { - await log.debug('Checking for section heading to say Rules.'); + log.debug('Checking for section heading to say Rules.'); const headingText = await pageObjects.triggersActionsUI.getSectionHeadingText(); expect(headingText).to.be('Rules'); }); describe('Alerts tab', () => { + let createdRule: { name: string; id: string }; + + before(async () => { + const resRule = await supertest + .post(`/api/alerting/rule`) + .set('kbn-xsrf', 'foo') + .send(getTestAlertData()) + .expect(200); + + createdRule = resRule.body; + objectRemover.add(createdRule.id, 'rule', 'alerting'); + }); + + after(async () => { + await objectRemover.removeAll(); + }); + it('renders the alerts tab', async () => { + // refresh to see alert + await browser.refresh(); + // Navigate to the alerts tab await pageObjects.triggersActionsUI.changeTabs('rulesTab'); @@ -84,20 +102,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('navigates to an alert details page', async () => { - const { body: createdConnector } = await supertest - .post(`/api/actions/connector`) - .set('kbn-xsrf', 'foo') - .send(getTestConnectorData()) - .expect(200); - objectRemover.add(createdConnector.id, 'connector', 'actions'); - - const { body: createdAlert } = await supertest - .post(`/api/alerting/rule`) - .set('kbn-xsrf', 'foo') - .send(getTestAlertData()) - .expect(200); - objectRemover.add(createdAlert.id, 'alert', 'alerts'); - // refresh to see alert await browser.refresh(); @@ -107,10 +111,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await testSubjects.existOrFail('rulesList'); // click on first alert - await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(createdAlert.name); + await pageObjects.triggersActionsUI.clickOnAlertInAlertsList(createdRule.name); // Verify url - expect(await browser.getCurrentUrl()).to.contain(`/rule/${createdAlert.id}`); + expect(await browser.getCurrentUrl()).to.contain(`/rule/${createdRule.id}`); }); }); }); diff --git a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts index 70f9d672b94a..a9de637cd691 100644 --- a/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts +++ b/x-pack/test/functional_with_es_ssl/apps/triggers_actions_ui/rules_list/rules_list.ts @@ -449,7 +449,7 @@ export default ({ getPageObjects, getPageObject, getService }: FtrProviderContex const infoIcon = await testSubjects.find('ruleInterval-config-icon-0'); await infoIcon.click(); - await testSubjects.click('cancelSaveEditedRuleButton'); + await testSubjects.click('rulePageFooterCancelButton'); }); it('should delete all selection', async () => { diff --git a/x-pack/test/functional_with_es_ssl/config.base.ts b/x-pack/test/functional_with_es_ssl/config.base.ts index 2abf100f2823..bcc6e00b9a97 100644 --- a/x-pack/test/functional_with_es_ssl/config.base.ts +++ b/x-pack/test/functional_with_es_ssl/config.base.ts @@ -85,7 +85,6 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { 'stackAlertsPage', 'ruleTagFilter', 'ruleStatusFilter', - 'isUsingRuleCreateFlyout', ])}`, `--xpack.alerting.rules.minimumScheduleInterval.value="5s"`, `--xpack.actions.enabledActionTypes=${JSON.stringify(enabledActionTypes)}`, diff --git a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts index 1880400dc37c..e56b9f71f169 100644 --- a/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts +++ b/x-pack/test/functional_with_es_ssl/page_objects/triggers_actions_ui_page.ts @@ -166,31 +166,33 @@ export function TriggersActionsPageProvider({ getService }: FtrProviderContext) await rules.common.clickCreateAlertButton(); }, async setAlertName(value: string) { - await testSubjects.setValue('ruleNameInput', value); + await testSubjects.setValue('ruleDetailsNameInput', value); await this.assertAlertName(value); }, async assertAlertName(expectedValue: string) { - const actualValue = await testSubjects.getAttribute('ruleNameInput', 'value'); + const actualValue = await testSubjects.getAttribute('ruleDetailsNameInput', 'value'); expect(actualValue).to.eql(expectedValue); }, async setAlertInterval(value: number, unit?: 's' | 'm' | 'h' | 'd') { - await testSubjects.setValue('intervalInput', value.toString()); + await testSubjects.setValue('ruleScheduleNumberInput', value.toString()); if (unit) { - await testSubjects.selectValue('intervalInputUnit', unit); + await testSubjects.selectValue('ruleScheduleUnitInput', unit); } await this.assertAlertInterval(value, unit); }, async assertAlertInterval(expectedValue: number, expectedUnit?: 's' | 'm' | 'h' | 'd') { - const actualValue = await testSubjects.getAttribute('intervalInput', 'value'); + const actualValue = await testSubjects.getAttribute('ruleScheduleNumberInput', 'value'); expect(actualValue).to.eql(expectedValue); if (expectedUnit) { - const actualUnitValue = await testSubjects.getAttribute('intervalInputUnit', 'value'); + const actualUnitValue = await testSubjects.getAttribute('ruleScheduleUnitInput', 'value'); expect(actualUnitValue).to.eql(expectedUnit); } }, async saveAlert() { - await testSubjects.click('saveRuleButton'); - const isConfirmationModalVisible = await testSubjects.isDisplayed('confirmRuleSaveModal'); + await testSubjects.click('rulePageFooterSaveButton'); + const isConfirmationModalVisible = await testSubjects.isDisplayed( + 'rulePageConfirmCreateRule' + ); expect(isConfirmationModalVisible).to.eql(true, 'Expect confirmation modal to be visible'); await testSubjects.click('confirmModalConfirmButton'); }, diff --git a/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts b/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts index 972b9cf2b3af..b4a2ee84566c 100644 --- a/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts +++ b/x-pack/test/functional_with_es_ssl/plugins/alerts/server/plugin.ts @@ -6,17 +6,14 @@ */ import { Plugin, CoreSetup } from '@kbn/core/server'; -import { - PluginSetupContract as AlertingSetup, - RuleType, - RuleTypeParams, -} from '@kbn/alerting-plugin/server'; +import { AlertingServerSetup, RuleType, RuleTypeParams } from '@kbn/alerting-plugin/server'; import { FeaturesPluginSetup } from '@kbn/features-plugin/server'; +import { ALERTING_FEATURE_ID } from '@kbn/alerting-plugin/common'; import { KibanaFeatureScope } from '@kbn/features-plugin/common'; // this plugin's dependendencies export interface AlertingExampleDeps { - alerting: AlertingSetup; + alerting: AlertingServerSetup; features: FeaturesPluginSetup; } @@ -117,13 +114,27 @@ export class AlertingFixturePlugin implements Plugin) { await ml.api.stopTrainedModelDeploymentES(TINY_ELSER.id, true); await ml.api.deleteTrainedModelES(TINY_ELSER.id); - await ml.api.cleanMlIndices(); await ml.testResources.cleanMLSavedObjects(); } diff --git a/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts b/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts index 6ea2b279fd38..cde2c9e4b4a8 100644 --- a/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts +++ b/x-pack/test/observability_ai_assistant_api_integration/tests/knowledge_base/knowledge_base_user_instructions.spec.ts @@ -331,5 +331,36 @@ export default function ApiTest({ getService }: FtrProviderContext) { expect(conversation.messages.length).to.be(5); }); }); + + describe('Instructions can be saved and cleared again', () => { + async function updateInstruction(text: string) { + await observabilityAIAssistantAPIClient + .editor({ + endpoint: 'PUT /internal/observability_ai_assistant/kb/user_instructions', + params: { + body: { + id: 'my-instruction-that-will-be-cleared', + text, + public: false, + }, + }, + }) + .expect(200); + + const res = await observabilityAIAssistantAPIClient + .editor({ endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions' }) + .expect(200); + + return res.body.userInstructions[0].text; + } + + it('can clear the instruction', async () => { + const res1 = await updateInstruction('This is a user instruction that will be cleared'); + expect(res1).to.be('This is a user instruction that will be cleared'); + + const res2 = await updateInstruction(''); + expect(res2).to.be(''); + }); + }); }); } diff --git a/x-pack/test/observability_api_integration/trial/tests/obs_alert_details_context.ts b/x-pack/test/observability_api_integration/trial/tests/obs_alert_details_context.ts index 608f44e18b34..31f2bb5e3466 100644 --- a/x-pack/test/observability_api_integration/trial/tests/obs_alert_details_context.ts +++ b/x-pack/test/observability_api_integration/trial/tests/obs_alert_details_context.ts @@ -17,6 +17,8 @@ export default function ApiTest({ getService }: ObsFtrProviderContext) { const obsApiClient = getService('obsApiClient'); const apmSynthtraceClient = getService('apmSynthtraceEsClient'); const logSynthtraceClient = getService('logSynthtraceEsClient'); + const security = getService('security'); + const supertestWithoutAuth = getService('supertestWithoutAuth'); describe('fetching observability alerts details context for AI assistant contextual insights', () => { const start = moment().subtract(10, 'minutes').valueOf(); @@ -511,5 +513,39 @@ export default function ApiTest({ getService }: ObsFtrProviderContext) { await apmSynthtraceClient.clean(); await logSynthtraceClient.clean(); } + + describe('security roles and access privileges', () => { + it('is not available to unauthorized users', async () => { + const UNAUTHORIZED_USERNAME = 'UNAUTHORIZED_USER'; + const UNAUTHORIZED_USER_PASSWORD = 'UNAUTHORIZED_USER_PASSWORD'; + + // Create a user with no privileges + await security.user.create(UNAUTHORIZED_USERNAME, { + password: UNAUTHORIZED_USER_PASSWORD, + roles: [], + full_name: 'Unauthorized Test User', + }); + + try { + // Make a request to the target API with insufficient privileges + await supertestWithoutAuth + .get('/internal/observability/assistant/alert_details_contextual_insights') + .auth(UNAUTHORIZED_USERNAME, UNAUTHORIZED_USER_PASSWORD) + .query({ alertId: 'test-alert-id' }) + .set('kbn-xsrf', 'true') + .expect(403) + .then(({ body }: any) => { + expect(body).to.eql({ + statusCode: 403, + error: 'Forbidden', + message: + 'API [GET /internal/observability/assistant/alert_details_contextual_insights?alertId=test-alert-id] is unauthorized for user, this action is granted by the Kibana privileges [ai_assistant]', + }); + }); + } finally { + await security.user.delete(UNAUTHORIZED_USERNAME); + } + }); + }); }); } diff --git a/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts b/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts index 4ec0f412e1f0..f084c4ec2a0a 100644 --- a/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts +++ b/x-pack/test/observability_functional/apps/observability/pages/rules_page.ts @@ -36,6 +36,7 @@ export default ({ getService, getPageObjects }: FtrProviderContext) => { search_fields: ['name'], }) .expect(200); + return rules.find((rule: any) => rule.name === name); } diff --git a/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts b/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts index 201729b0bcc0..461b86deefc9 100644 --- a/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts +++ b/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts @@ -56,7 +56,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); // check Machine Learning section - await solutionNavigation.sidenav.openPanel('machine_learning-landing'); + await solutionNavigation.sidenav.openPanel('machine_learning-landing', { button: 'link' }); { const isOpen = await solutionNavigation.sidenav.isPanelOpen('machine_learning-landing'); expect(isOpen).to.be(true); diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts index a6bf7e7e9d5f..e8e24f53551e 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/check_registered_task_types.ts @@ -143,6 +143,7 @@ export default function ({ getService }: FtrProviderContext) { 'endpoint:metadata-check-transforms-task', 'endpoint:user-artifact-packager', 'entity_store:field_retention:enrichment', + 'fleet:bump_agent_policies', 'fleet:check-deleted-files-task', 'fleet:delete-unenrolled-agents-task', 'fleet:deploy_agent_policies', diff --git a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_removed_types.ts b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_removed_types.ts index 60d858206d68..a7447353e805 100644 --- a/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_removed_types.ts +++ b/x-pack/test/plugin_api_integration/test_suites/task_manager/task_management_removed_types.ts @@ -47,8 +47,7 @@ export default function ({ getService }: FtrProviderContext) { const UNREGISTERED_TASK_TYPE_ID = 'ce7e1250-3322-11eb-94c1-db6995e83f6b'; const REMOVED_TASK_TYPE_ID = 'be7e1250-3322-11eb-94c1-db6995e83f6a'; - // FLAKY: https://github.com/elastic/kibana/issues/200154 - describe.skip('not registered task types', () => { + describe('not registered task types', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/task_manager_removed_types'); }); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/bulk_update_alerts.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/bulk_update_alerts.ts index 68feb3713739..e54af674f657 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/bulk_update_alerts.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/bulk_update_alerts.ts @@ -102,7 +102,6 @@ export default ({ getService }: FtrProviderContext) => { function addTests({ space, authorizedUsers, unauthorizedUsers, alertId, index }: TestCase) { authorizedUsers.forEach(({ username, password }) => { it(`${username} should bulk update alert with given id ${alertId} in ${space}/${index}`, async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); // since this is a success case, reload the test data immediately beforehand const { body: updated } = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}/bulk_update`) .auth(username, password) @@ -119,7 +118,6 @@ export default ({ getService }: FtrProviderContext) => { }); it(`${username} should bulk update alerts which match KQL query string in ${space}/${index}`, async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); // since this is a success case, reload the test data immediately beforehand const { body: updated } = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}/bulk_update`) .auth(username, password) @@ -134,7 +132,6 @@ export default ({ getService }: FtrProviderContext) => { }); it(`${username} should bulk update alerts which match query in DSL in ${space}/${index}`, async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); // since this is a success case, reload the test data immediately beforehand const { body: updated } = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}/bulk_update`) .auth(username, password) diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/find_alerts.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/find_alerts.ts index 694c27060f19..404250a169e0 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/find_alerts.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/find_alerts.ts @@ -7,7 +7,7 @@ import expect from '@kbn/expect'; import { - ALERT_RULE_CONSUMER, + ALERT_RULE_TYPE_ID, ALERT_WORKFLOW_STATUS, } from '@kbn/rule-registry-plugin/common/technical_rule_data_field_names'; import { @@ -268,30 +268,30 @@ export default ({ getService }: FtrProviderContext) => { expect(found.body.aggregations.nbr_consumer.value).to.be.equal(2); }); - it(`${superUser.username} should handle 'siem' featureIds`, async () => { + it(`${superUser.username} should handle 'siem' rule type IDs`, async () => { const found = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}/find`) .auth(superUser.username, superUser.password) .set('kbn-xsrf', 'true') .send({ - feature_ids: ['siem'], + rule_type_ids: ['siem.queryRule'], }); - expect(found.body.hits.hits.every((hit: any) => hit[ALERT_RULE_CONSUMER] === 'siem')).equal( + expect(found.body.hits.hits.every((hit: any) => hit[ALERT_RULE_TYPE_ID] === 'siem')).equal( true ); }); - it(`${superUser.username} should handle 'apm' featureIds`, async () => { + it(`${superUser.username} should handle 'apm' rule type IDs`, async () => { const found = await supertestWithoutAuth .post(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}/find`) .auth(superUser.username, superUser.password) .set('kbn-xsrf', 'true') .send({ - feature_ids: ['apm'], + rule_type_ids: ['apm.error_rate'], }); - expect(found.body.hits.hits.every((hit: any) => hit[ALERT_RULE_CONSUMER] === 'apm')).equal( + expect(found.body.hits.hits.every((hit: any) => hit[ALERT_RULE_TYPE_ID] === 'apm')).equal( true ); }); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_aad_fields_by_rule_type.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_aad_fields_by_rule_type.ts index 4d8fed02a7c7..1e7759b06c30 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_aad_fields_by_rule_type.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_aad_fields_by_rule_type.ts @@ -38,8 +38,12 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); }); + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + describe('Users:', () => { - it(`${obsOnlySpacesAll.username} should be able to get browser fields for o11y featureIds`, async () => { + it(`${obsOnlySpacesAll.username} should be able to get browser fields for o11y rule type ids`, async () => { await retry.try(async () => { const aadFields = await getAADFieldsByRuleType( obsOnlySpacesAll, diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alert_summary.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alert_summary.ts index 5da72c7f6a76..abfc4c9d5aa7 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alert_summary.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alert_summary.ts @@ -39,7 +39,7 @@ export default ({ getService }: FtrProviderContext) => { .send({ gte: '2020-12-16T15:00:00.000Z', lte: '2020-12-16T16:00:00.000Z', - featureIds: ['logs'], + ruleTypeIds: ['logs.alert.document.count'], fixed_interval: '10m', }) .expect(200); @@ -83,7 +83,7 @@ export default ({ getService }: FtrProviderContext) => { }, }, ], - featureIds: ['logs'], + ruleTypeIds: ['logs.alert.document.count'], fixed_interval: '10m', }) .expect(200); @@ -127,7 +127,7 @@ export default ({ getService }: FtrProviderContext) => { }, }, ], - featureIds: ['logs'], + ruleTypeIds: ['logs.alert.document.count'], fixed_interval: '10m', }) .expect(200); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts_index.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts_index.ts index 530c0a57b02e..604cff34865d 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts_index.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_alerts_index.ts @@ -30,16 +30,18 @@ export default ({ getService }: FtrProviderContext) => { const STACK_ALERT_INDEX = '.alerts-stack.alerts-default'; const getIndexName = async ( - featureIds: string[], + ruleTypeIds: string[], user: User, space: string, expectedStatusCode: number = 200 ) => { const resp = await supertestWithoutAuth - .get(`${getSpaceUrlPrefix(space)}${ALERTS_INDEX_URL}?features=${featureIds.join(',')}`) + .get(`${getSpaceUrlPrefix(space)}${ALERTS_INDEX_URL}`) + .query({ ruleTypeIds }) .auth(user.username, user.password) .set('kbn-xsrf', 'true') .expect(expectedStatusCode); + return resp.body.index_name as string[]; }; @@ -47,33 +49,34 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); }); + + before(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + describe('Users:', () => { it(`${obsOnlySpacesAll.username} should be able to access the APM alert in ${SPACE1}`, async () => { - const indexNames = await getIndexName(['apm'], obsOnlySpacesAll, SPACE1); + const indexNames = await getIndexName(['apm.error_rate'], obsOnlySpacesAll, SPACE1); expect(indexNames.includes(APM_ALERT_INDEX)).to.eql(true); // assert this here so we can use constants in the dynamically-defined test cases below }); it(`${superUser.username} should be able to access the APM alert in ${SPACE1}`, async () => { - const indexNames = await getIndexName(['apm'], superUser, SPACE1); + const indexNames = await getIndexName(['apm.error_rate'], superUser, SPACE1); expect(indexNames.includes(APM_ALERT_INDEX)).to.eql(true); // assert this here so we can use constants in the dynamically-defined test cases below }); it(`${secOnlyRead.username} should NOT be able to access the APM alert in ${SPACE1}`, async () => { - const indexNames = await getIndexName(['apm'], secOnlyRead, SPACE1); + const indexNames = await getIndexName(['apm.error_rate'], secOnlyRead, SPACE1); expect(indexNames?.length).to.eql(0); }); it(`${secOnlyRead.username} should be able to access the security solution alert in ${SPACE1}`, async () => { - const indexNames = await getIndexName(['siem'], secOnlyRead, SPACE1); + const indexNames = await getIndexName(['siem.esqlRule'], secOnlyRead, SPACE1); expect(indexNames.includes(`${SECURITY_SOLUTION_ALERT_INDEX}-${SPACE1}`)).to.eql(true); // assert this here so we can use constants in the dynamically-defined test cases below }); it(`${stackAlertsOnlyReadSpacesAll.username} should be able to access the stack alert in ${SPACE1}`, async () => { - const indexNames = await getIndexName( - ['stackAlerts'], - stackAlertsOnlyReadSpacesAll, - SPACE1 - ); + const indexNames = await getIndexName(['.es-query'], stackAlertsOnlyReadSpacesAll, SPACE1); expect(indexNames.includes(STACK_ALERT_INDEX)).to.eql(true); }); }); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_rule_type_ids.ts similarity index 74% rename from x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts rename to x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_rule_type_ids.ts index 352ff0188b01..ac05dad573c6 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_feature_id.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_browser_fields_by_rule_type_ids.ts @@ -6,6 +6,7 @@ */ import expect from 'expect'; +import { OBSERVABILITY_RULE_TYPE_IDS } from '@kbn/rule-data-utils'; import { superUser, obsOnlySpacesAll, secOnlyRead } from '../../../common/lib/authentication/users'; import type { User } from '../../../common/lib/authentication/types'; import { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -20,31 +21,38 @@ export default ({ getService }: FtrProviderContext) => { const getBrowserFieldsByFeatureId = async ( user: User, - featureIds: string[], + ruleTypeIds: string[], expectedStatusCode: number = 200 ) => { const resp = await supertestWithoutAuth .get(`${getSpaceUrlPrefix(SPACE1)}${TEST_URL}`) - .query({ featureIds }) + .query({ ruleTypeIds }) .auth(user.username, user.password) .set('kbn-xsrf', 'true') .expect(expectedStatusCode); + return resp.body; }; - describe('Alert - Get browser fields by featureId', () => { + describe('Alert - Get browser fields by rule type IDs', () => { + const ruleTypeIds = [ + ...OBSERVABILITY_RULE_TYPE_IDS, + '.es-query', + 'xpack.ml.anomaly_detection_alert', + ]; + before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); }); + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + describe('Users:', () => { - it(`${obsOnlySpacesAll.username} should be able to get browser fields for o11y featureIds`, async () => { - const resp = await getBrowserFieldsByFeatureId(obsOnlySpacesAll, [ - 'apm', - 'infrastructure', - 'logs', - 'uptime', - ]); + it(`${obsOnlySpacesAll.username} should be able to get browser fields for o11y ruleTypeIds that has access to`, async () => { + const resp = await getBrowserFieldsByFeatureId(obsOnlySpacesAll, ruleTypeIds); + expect(Object.keys(resp.browserFields)).toEqual([ 'base', 'agent', @@ -61,13 +69,9 @@ export default ({ getService }: FtrProviderContext) => { ]); }); - it(`${superUser.username} should be able to get browser fields for o11y featureIds`, async () => { - const resp = await getBrowserFieldsByFeatureId(superUser, [ - 'apm', - 'infrastructure', - 'logs', - 'uptime', - ]); + it(`${superUser.username} should be able to get browser fields for all o11y ruleTypeIds`, async () => { + const resp = await getBrowserFieldsByFeatureId(superUser, ruleTypeIds); + expect(Object.keys(resp.browserFields)).toEqual([ 'base', 'agent', @@ -82,17 +86,18 @@ export default ({ getService }: FtrProviderContext) => { 'observer', 'orchestrator', 'service', + 'slo', 'tls', 'url', ]); }); - it(`${superUser.username} should NOT be able to get browser fields for siem featureId`, async () => { - await getBrowserFieldsByFeatureId(superUser, ['siem'], 404); + it(`${superUser.username} should NOT be able to get browser fields for siem rule types`, async () => { + await getBrowserFieldsByFeatureId(superUser, ['siem.queryRule'], 404); }); - it(`${secOnlyRead.username} should NOT be able to get browser fields for siem featureId`, async () => { - await getBrowserFieldsByFeatureId(secOnlyRead, ['siem'], 404); + it(`${secOnlyRead.username} should NOT be able to get browser fields for siem rule types`, async () => { + await getBrowserFieldsByFeatureId(secOnlyRead, ['siem.queryRule'], 404); }); }); }); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_feature_ids_by_registration_contexts.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_feature_ids_by_registration_contexts.ts deleted file mode 100644 index 5b4063cfe528..000000000000 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/get_feature_ids_by_registration_contexts.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import expect from '@kbn/expect'; - -import { superUser, obsOnlySpacesAll, secOnlyRead } from '../../../common/lib/authentication/users'; -import type { User } from '../../../common/lib/authentication/types'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; -import { getSpaceUrlPrefix } from '../../../common/lib/authentication/spaces'; - -// eslint-disable-next-line import/no-default-export -export default ({ getService }: FtrProviderContext) => { - const supertestWithoutAuth = getService('supertestWithoutAuth'); - const esArchiver = getService('esArchiver'); - - const TEST_URL = '/internal/rac/alerts'; - const ALERTS_FEATURE_IDS_URL = `${TEST_URL}/_feature_ids`; - const SPACE1 = 'space1'; - - const getApmFeatureIdByRegistrationContexts = async ( - user: User, - space: string, - expectedStatusCode: number = 200 - ) => { - const resp = await supertestWithoutAuth - .get( - `${getSpaceUrlPrefix(space)}${ALERTS_FEATURE_IDS_URL}?registrationContext=observability.apm` - ) - .auth(user.username, user.password) - .set('kbn-xsrf', 'true') - .expect(expectedStatusCode); - return resp.body as string[]; - }; - - const getSecurityFeatureIdByRegistrationContexts = async ( - user: User, - space: string, - expectedStatusCode: number = 200 - ) => { - const resp = await supertestWithoutAuth - .get(`${getSpaceUrlPrefix(space)}${ALERTS_FEATURE_IDS_URL}?registrationContext=security`) - .auth(user.username, user.password) - .set('kbn-xsrf', 'true') - .expect(expectedStatusCode); - - return resp.body as string[]; - }; - - describe('Alert - Get feature ids by registration context', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); - }); - describe('Users:', () => { - it(`${obsOnlySpacesAll.username} should be able to get feature id for registration context 'observability.apm' in ${SPACE1}`, async () => { - const featureIds = await getApmFeatureIdByRegistrationContexts(obsOnlySpacesAll, SPACE1); - expect(featureIds).to.eql(['apm']); - }); - - it(`${superUser.username} should be able to get feature id for registration context 'observability.apm' in ${SPACE1}`, async () => { - const featureIds = await getApmFeatureIdByRegistrationContexts(superUser, SPACE1); - expect(featureIds).to.eql(['apm']); - }); - - it(`${secOnlyRead.username} should NOT be able to get feature id for registration context 'observability.apm' in ${SPACE1}`, async () => { - const featureIds = await getApmFeatureIdByRegistrationContexts(secOnlyRead, SPACE1); - expect(featureIds).to.eql([]); - }); - - it(`${secOnlyRead.username} should be able to get feature id for registration context 'security' in ${SPACE1}`, async () => { - const featureIds = await getSecurityFeatureIdByRegistrationContexts(secOnlyRead, SPACE1); - expect(featureIds).to.eql(['siem']); - }); - }); - }); -}; diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/index.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/index.ts index 5237cd02c0c8..e7593121bc2d 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/index.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/index.ts @@ -25,11 +25,10 @@ export default ({ loadTestFile, getService }: FtrProviderContext): void => { // loadTestFile(require.resolve('./update_alert')); // loadTestFile(require.resolve('./bulk_update_alerts')); - loadTestFile(require.resolve('./get_feature_ids_by_registration_contexts')); loadTestFile(require.resolve('./get_alerts_index')); loadTestFile(require.resolve('./find_alerts')); loadTestFile(require.resolve('./search_strategy')); - loadTestFile(require.resolve('./get_browser_fields_by_feature_id')); + loadTestFile(require.resolve('./get_browser_fields_by_rule_type_ids')); loadTestFile(require.resolve('./get_alert_summary')); loadTestFile(require.resolve('./get_aad_fields_by_rule_type')); }); diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts index ffcd6fee5cf8..6462e2a1ec80 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/search_strategy.ts @@ -5,7 +5,6 @@ * 2.0. */ import expect from '@kbn/expect'; -import { AlertConsumers } from '@kbn/rule-data-utils'; import type { RuleRegistrySearchResponse } from '@kbn/rule-registry-plugin/common'; import type { FtrProviderContext } from '../../../common/ftr_provider_context'; @@ -39,6 +38,7 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); }); + after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); }); @@ -54,15 +54,14 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['logs.alert.document.count'], }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); + expect(result.rawResponse.hits.total).to.eql(5); - const consumers = result.rawResponse.hits.hits.map((hit) => { - return hit.fields?.['kibana.alert.rule.consumer']; - }); - expect(consumers.every((consumer) => consumer === AlertConsumers.LOGS)); + + validateRuleTypeIds(result, ['logs.alert.document.count']); }); it('should support pagination and sorting', async () => { @@ -76,7 +75,7 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.LOGS], + ruleTypeIds: ['logs.alert.document.count'], pagination: { pageSize: 2, pageIndex: 1, @@ -91,25 +90,35 @@ export default ({ getService }: FtrProviderContext) => { }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); + expect(result.rawResponse.hits.total).to.eql(5); expect(result.rawResponse.hits.hits.length).to.eql(2); + const first = result.rawResponse.hits.hits[0].fields?.['kibana.alert.evaluation.value']; const second = result.rawResponse.hits.hits[1].fields?.['kibana.alert.evaluation.value']; + expect(first > second).to.be(true); }); }); describe('siem', () => { + const siemRuleTypeIds = [ + 'siem.indicatorRule', + 'siem.thresholdRule', + 'siem.eqlRule', + 'siem.queryRule', + ]; + before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); await esArchiver.load('x-pack/test/functional/es_archives/security_solution/alerts/8.1.0'); }); after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); await esArchiver.unload( 'x-pack/test/functional/es_archives/security_solution/alerts/8.1.0' ); - await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); }); it('should return alerts from siem rules', async () => { @@ -123,15 +132,14 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: siemRuleTypeIds, }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); + expect(result.rawResponse.hits.total).to.eql(50); - const consumers = result.rawResponse.hits.hits.map( - (hit) => hit.fields?.['kibana.alert.rule.consumer'] - ); - expect(consumers.every((consumer) => consumer === AlertConsumers.SIEM)); + + validateRuleTypeIds(result, siemRuleTypeIds); }); it('should throw an error when trying to to search for more than just siem', async () => { @@ -145,13 +153,14 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.SIEM, AlertConsumers.LOGS], + ruleTypeIds: ['siem.indicatorRule', 'logs.alert.document.count'], }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); - expect(result.statusCode).to.be(500); + + expect(result.statusCode).to.be(400); expect(result.message).to.be( - `The privateRuleRegistryAlertsSearchStrategy search strategy is unable to accommodate requests containing multiple feature IDs and one of those IDs is SIEM.` + 'The privateRuleRegistryAlertsSearchStrategy search strategy is unable to accommodate requests containing multiple rule types with mixed authorization.' ); }); @@ -168,7 +177,7 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.SIEM], + ruleTypeIds: siemRuleTypeIds, runtimeMappings: { [runtimeFieldKey]: { type: 'keyword', @@ -180,18 +189,24 @@ export default ({ getService }: FtrProviderContext) => { }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); + expect(result.rawResponse.hits.total).to.eql(50); + const runtimeFields = result.rawResponse.hits.hits.map( (hit) => hit.fields?.[runtimeFieldKey] ); + expect(runtimeFields.every((field) => field === runtimeFieldValue)); }); }); describe('apm', () => { + const apmRuleTypeIds = ['apm.transaction_error_rate', 'apm.error_rate']; + before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); }); + after(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); }); @@ -207,19 +222,20 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.APM], + ruleTypeIds: apmRuleTypeIds, }, strategy: 'privateRuleRegistryAlertsSearchStrategy', space: 'default', }); + expect(result.rawResponse.hits.total).to.eql(9); - const consumers = result.rawResponse.hits.hits.map( - (hit) => hit.fields?.['kibana.alert.rule.consumer'] - ); - expect(consumers.every((consumer) => consumer === AlertConsumers.APM)); + + validateRuleTypeIds(result, apmRuleTypeIds); }); - it('should not by pass our RBAC authz filter with a should filter', async () => { + it('should return alerts from different rules', async () => { + const ruleTypeIds = [...apmRuleTypeIds, 'logs.alert.document.count']; + const result = await secureSearch.send({ supertestWithoutAuth, auth: { @@ -230,7 +246,83 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.APM], + ruleTypeIds, + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(14); + + validateRuleTypeIds(result, ruleTypeIds); + }); + + it('should filter alerts by rule type IDs with consumers', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: apmRuleTypeIds, + consumers: ['alerts', 'logs'], + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(9); + + validateRuleTypeIds(result, apmRuleTypeIds); + }); + + it('should filter alerts by consumers with rule type IDs', async () => { + const ruleTypeIds = [...apmRuleTypeIds, 'logs.alert.document.count']; + + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds, + consumers: ['alerts'], + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + /** + *There are five documents of rule type logs.alert.document.count + * The four have the consumer set to alerts + * and the one has the consumer set to logs. + * All apm rule types (nine in total) have consumer set to alerts. + */ + expect(result.rawResponse.hits.total).to.eql(13); + + validateRuleTypeIds(result, ruleTypeIds); + }); + + it('should not by pass our RBAC authz filter with a should filter for rule type ids', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: apmRuleTypeIds, query: { bool: { filter: [], @@ -240,7 +332,7 @@ export default ({ getService }: FtrProviderContext) => { should: [ { match: { - 'kibana.alert.rule.consumer': 'logs', + 'kibana.alert.rule.rule_type_id': 'metrics.alert.inventory.threshold', }, }, ], @@ -256,14 +348,56 @@ export default ({ getService }: FtrProviderContext) => { strategy: 'privateRuleRegistryAlertsSearchStrategy', space: 'default', }); + expect(result.rawResponse.hits.total).to.eql(9); - const consumers = result.rawResponse.hits.hits.map( - (hit) => hit.fields?.['kibana.alert.rule.consumer'] - ); - expect(consumers.every((consumer) => consumer === AlertConsumers.APM)); + + validateRuleTypeIds(result, apmRuleTypeIds); + }); + + it('should not by pass our RBAC authz filter with a should filter for consumers', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: apmRuleTypeIds, + query: { + bool: { + filter: [], + should: [ + { + bool: { + should: [ + { + match: { + 'kibana.alert.rule.consumer': 'infrastructure', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + must: [], + must_not: [], + }, + }, + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(9); + + validateRuleTypeIds(result, apmRuleTypeIds); }); - it('should return an empty response with must filter and our RBAC authz filter', async () => { + it('should return an empty response with must filter and our RBAC authz filter for rule type ids', async () => { const result = await secureSearch.send({ supertestWithoutAuth, auth: { @@ -274,7 +408,7 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.APM], + ruleTypeIds: apmRuleTypeIds, query: { bool: { filter: [], @@ -284,7 +418,7 @@ export default ({ getService }: FtrProviderContext) => { should: [ { match: { - 'kibana.alert.rule.consumer': 'logs', + 'kibana.alert.rule.rule_type_id': 'metrics.alert.inventory.threshold', }, }, ], @@ -300,10 +434,11 @@ export default ({ getService }: FtrProviderContext) => { strategy: 'privateRuleRegistryAlertsSearchStrategy', space: 'default', }); + expect(result.rawResponse.hits.total).to.eql(0); }); - it('should not by pass our RBAC authz filter with must_not filter', async () => { + it('should return an empty response with must filter and our RBAC authz filter for consumers', async () => { const result = await secureSearch.send({ supertestWithoutAuth, auth: { @@ -314,7 +449,91 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [AlertConsumers.APM], + ruleTypeIds: apmRuleTypeIds, + query: { + bool: { + filter: [], + must: [ + { + bool: { + should: [ + { + match: { + 'kibana.alert.rule.consumer': 'infrastructure', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + should: [], + must_not: [], + }, + }, + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(0); + }); + + it('should not by pass our RBAC authz filter with must_not filter for rule type ids', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: apmRuleTypeIds, + query: { + bool: { + filter: [], + must: [], + must_not: [ + { + bool: { + should: [ + ...apmRuleTypeIds.map((apmRuleTypeId) => ({ + match: { + 'kibana.alert.rule.rule_type_id': apmRuleTypeId, + }, + })), + ], + minimum_should_match: apmRuleTypeIds.length, + }, + }, + ], + should: [], + }, + }, + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(9); + + validateRuleTypeIds(result, apmRuleTypeIds); + }); + + it('should not by pass our RBAC authz filter with must_not filter for consumers', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: apmRuleTypeIds, query: { bool: { filter: [], @@ -340,11 +559,136 @@ export default ({ getService }: FtrProviderContext) => { strategy: 'privateRuleRegistryAlertsSearchStrategy', space: 'default', }); + expect(result.rawResponse.hits.total).to.eql(9); - const consumers = result.rawResponse.hits.hits.map( - (hit) => hit.fields?.['kibana.alert.rule.consumer'] - ); - expect(consumers.every((consumer) => consumer === AlertConsumers.APM)); + + validateRuleTypeIds(result, apmRuleTypeIds); + }); + + it('should not by pass our RBAC authz filter with the ruleTypeIds and consumers parameter', async () => { + const ruleTypeIds = [ + ...apmRuleTypeIds, + 'metrics.alert.inventory.threshold', + 'metrics.alert.threshold', + '.es-query', + ]; + + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + /** + * obsOnlySpacesAll does not have access to the following pairs: + * + * Rule type ID: metrics.alert.inventory.threshold + * Consumer: alerts + * + * Rule type ID: metrics.alert.threshold + * Consumer: alerts + * + * Rule type ID: .es-query + * Consumer: discover + */ + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds, + consumers: ['alerts', 'discover'], + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(9); + + validateRuleTypeIds(result, apmRuleTypeIds); + }); + + it('should not return any alerts if the user does not have access to any alerts', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: ['metrics.alert.threshold', 'metrics.alert.inventory.threshold'], + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(0); + }); + + it('should not return alerts that the user does not have access to', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: ['metrics.alert.threshold', 'logs.alert.document.count'], + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(5); + validateRuleTypeIds(result, ['logs.alert.document.count']); + }); + + it('should not return alerts if the user does not have access to using a filter', async () => { + const result = await secureSearch.send({ + supertestWithoutAuth, + auth: { + username: obsOnlySpacesAll.username, + password: obsOnlySpacesAll.password, + }, + referer: 'test', + kibanaVersion, + internalOrigin: 'Kibana', + options: { + ruleTypeIds: apmRuleTypeIds, + query: { + bool: { + filter: [], + should: [ + { + bool: { + should: [ + { + match: { + 'kibana.alert.rule.rule_type_id': 'metrics.alert.inventory.threshold', + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + must: [], + must_not: [], + }, + }, + }, + strategy: 'privateRuleRegistryAlertsSearchStrategy', + space: 'default', + }); + + expect(result.rawResponse.hits.total).to.eql(9); + + validateRuleTypeIds(result, apmRuleTypeIds); }); }); @@ -367,11 +711,13 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: ['discover'], + ruleTypeIds: ['.es-query'], }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); + validateRuleTypeIds(result, ['.es-query']); + expect(result.rawResponse.hits.total).to.eql(1); const consumers = result.rawResponse.hits.hits.map((hit) => { @@ -392,11 +738,13 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: ['discover'], + ruleTypeIds: ['.es-query'], }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); + validateRuleTypeIds(result, ['.es-query']); + expect(result.rawResponse.hits.total).to.eql(1); const consumers = result.rawResponse.hits.hits.map((hit) => { @@ -417,13 +765,12 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: ['discover'], + ruleTypeIds: ['.es-query'], }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); - expect(result.statusCode).to.be(500); - expect(result.message).to.be('Unauthorized to find alerts for any rule types'); + expect(result.rawResponse.hits.total).to.eql(0); }); }); @@ -439,12 +786,29 @@ export default ({ getService }: FtrProviderContext) => { kibanaVersion, internalOrigin: 'Kibana', options: { - featureIds: [], + ruleTypeIds: [], }, strategy: 'privateRuleRegistryAlertsSearchStrategy', }); - expect(result.rawResponse).to.eql({}); + + expect(result.rawResponse.hits.total).to.eql(0); }); }); }); }; + +const validateRuleTypeIds = (result: RuleRegistrySearchResponse, ruleTypeIdsToVerify: string[]) => { + expect(result.rawResponse.hits.total).to.greaterThan(0); + + const ruleTypeIds = result.rawResponse.hits.hits + .map((hit) => { + return hit.fields?.['kibana.alert.rule.rule_type_id']; + }) + .flat(); + + expect( + ruleTypeIds.every((ruleTypeId) => + ruleTypeIdsToVerify.some((ruleTypeIdToVerify) => ruleTypeIdToVerify === ruleTypeId) + ) + ).to.eql(true); +}; diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/basic/update_alert.ts b/x-pack/test/rule_registry/security_and_spaces/tests/basic/update_alert.ts index 4d7607442fbc..237f492ebf36 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/basic/update_alert.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/basic/update_alert.ts @@ -101,7 +101,6 @@ export default ({ getService }: FtrProviderContext) => { function addTests({ space, authorizedUsers, unauthorizedUsers, alertId, index }: TestCase) { authorizedUsers.forEach(({ username, password }) => { it(`${username} should be able to update alert ${alertId} in ${space}/${index}`, async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); // since this is a success case, reload the test data immediately beforehand await supertestWithoutAuth .post(`${getSpaceUrlPrefix(space)}${TEST_URL}`) .auth(username, password) diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts b/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts index f4aa5c503bc1..f3c4a4e6146a 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/trial/get_alerts.ts @@ -47,6 +47,11 @@ export default ({ getService }: FtrProviderContext) => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); + }); + describe('Users:', () => { // user with minimal_read and alerts_read privileges should be able to access apm alert it(`${obsMinReadAlertsRead.username} should be able to access the APM alert in ${SPACE1}`, async () => { diff --git a/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts b/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts index 9b4e4b70d59c..0de2adbf0f57 100644 --- a/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts +++ b/x-pack/test/rule_registry/security_and_spaces/tests/trial/update_alert.ts @@ -46,9 +46,11 @@ export default ({ getService }: FtrProviderContext) => { beforeEach(async () => { await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); }); + afterEach(async () => { await esArchiver.unload('x-pack/test/functional/es_archives/rule_registry/alerts'); }); + it(`${superUser.username} should be able to update the APM alert in ${SPACE1}`, async () => { const apmIndex = await getAPMIndexName(superUser); await supertestWithoutAuth diff --git a/x-pack/test/rule_registry/spaces_only/tests/trial/update_alert.ts b/x-pack/test/rule_registry/spaces_only/tests/trial/update_alert.ts index 31c3cfdecb9e..2fe7ff9dac0c 100644 --- a/x-pack/test/rule_registry/spaces_only/tests/trial/update_alert.ts +++ b/x-pack/test/rule_registry/spaces_only/tests/trial/update_alert.ts @@ -90,7 +90,6 @@ export default ({ getService }: FtrProviderContext) => { }); it(`${superUser.username} should be able to update alert ${APM_ALERT_ID} in ${SPACE2}/${APM_ALERT_INDEX}`, async () => { - await esArchiver.load('x-pack/test/functional/es_archives/rule_registry/alerts'); // since this is a success case, reload the test data immediately beforehand await supertestWithoutAuth .post(`${getSpaceUrlPrefix(SPACE2)}${TEST_URL}`) .set('kbn-xsrf', 'true') diff --git a/x-pack/test/saved_object_tagging/functional/tests/discover_integration.ts b/x-pack/test/saved_object_tagging/functional/tests/discover_integration.ts index 365ce9a71581..f4b917abf5d7 100644 --- a/x-pack/test/saved_object_tagging/functional/tests/discover_integration.ts +++ b/x-pack/test/saved_object_tagging/functional/tests/discover_integration.ts @@ -82,22 +82,25 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('allows to manually type tag filter query', async () => { await PageObjects.discover.openLoadSavedSearchPanel(); await testSubjects.setValue('savedObjectFinderSearchInput', 'tag:(tag-1)'); - await expectSavedSearches('A Saved Search'); + await expectSavedSearches('A Saved Search\nA Saved Search Description'); }); it('allows to filter by selecting a tag in the filter menu', async () => { await PageObjects.discover.openLoadSavedSearchPanel(); await selectFilterTags('tag-2'); - await expectSavedSearches('A Saved Search', 'A Different Saved Search'); + await expectSavedSearches( + 'A Saved Search\nA Saved Search Description', + 'A Different Saved Search\nA Different Saved Search Description' + ); }); it('allows to filter by multiple tags', async () => { await PageObjects.discover.openLoadSavedSearchPanel(); await selectFilterTags('tag-2', 'tag-3'); await expectSavedSearches( - 'A Saved Search', - 'A Different Saved Search', - 'A Third Saved Search' + 'A Different Saved Search\nA Different Saved Search Description', + 'A Saved Search\nA Saved Search Description', + 'A Third Saved Search\nAn Untagged Saved Search Description' ); }); }); @@ -116,7 +119,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); await PageObjects.discover.openLoadSavedSearchPanel(); await selectFilterTags('tag-1', 'tag-2'); - await expectSavedSearches('A Saved Search', 'A Different Saved Search', 'My New Search'); + await expectSavedSearches( + 'A Different Saved Search\nA Different Saved Search Description', + 'A Saved Search\nA Saved Search Description', + 'My New Search' + ); }); it('allows to create a tag from the tag selector', async () => { @@ -172,9 +179,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await PageObjects.discover.openLoadSavedSearchPanel(); await selectFilterTags('tag-3'); await expectSavedSearches( - 'A Different Saved Search', - 'A Third Saved Search', - 'A Saved Search' + 'A Different Saved Search\nA Different Saved Search Description', + 'A Saved Search\nA Saved Search Description', + 'A Third Saved Search\nAn Untagged Saved Search Description' ); }); }); diff --git a/x-pack/test/search_sessions_integration/tests/apps/dashboard/session_sharing/lens.ts b/x-pack/test/search_sessions_integration/tests/apps/dashboard/session_sharing/lens.ts index b32eafc8c689..0ce8303a291b 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/dashboard/session_sharing/lens.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/dashboard/session_sharing/lens.ts @@ -48,7 +48,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // Navigating to lens and back should create a new session const byRefSessionId = await dashboardPanelActions.getSearchSessionIdByTitle(lensTitle); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.saveAndReturn(); await dashboard.waitForRenderComplete(); const newByRefSessionId = await dashboardPanelActions.getSearchSessionIdByTitle(lensTitle); @@ -56,12 +56,12 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(byRefSessionId).not.to.eql(newByRefSessionId); // Convert to by-value - await dashboardPanelActions.legacyUnlinkFromLibrary(lensTitle); + await dashboardPanelActions.unlinkFromLibrary(lensTitle); await dashboard.waitForRenderComplete(); const byValueSessionId = await dashboardPanelActions.getSearchSessionIdByTitle(lensTitle); // Navigating to lens and back should keep the session - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await lens.saveAndReturn(); await dashboard.waitForRenderComplete(); const newByValueSessionId = await dashboardPanelActions.getSearchSessionIdByTitle(lensTitle); diff --git a/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts b/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts index d4c87209c64c..eadd2b544953 100644 --- a/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts +++ b/x-pack/test/search_sessions_integration/tests/apps/discover/async_search.ts @@ -28,6 +28,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const retry = getService('retry'); const kibanaServer = getService('kibanaServer'); const toasts = getService('toasts'); + const dataGrid = getService('dataGrid'); // FLAKY: https://github.com/elastic/kibana/issues/195955 describe.skip('discover async search', () => { @@ -95,16 +96,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); it('navigation to context cleans the session', async () => { - const table = await discover.getDocTable(); - const isLegacy = await discover.useLegacyTable(); - await table.clickRowToggle({ rowIndex: 0 }); + await dataGrid.clickRowToggle({ rowIndex: 0 }); await retry.try(async () => { - const rowActions = await table.getRowActions({ rowIndex: 0 }); + const rowActions = await dataGrid.getRowActions({ rowIndex: 0 }); if (!rowActions.length) { throw new Error('row actions empty, trying again'); } - const idxToClick = isLegacy ? 0 : 1; + const idxToClick = 1; await rowActions[idxToClick].click(); }); diff --git a/x-pack/test/security_api_integration/plugins/features_provider/server/index.ts b/x-pack/test/security_api_integration/plugins/features_provider/server/index.ts index 61100babefea..9b7158aca7b3 100644 --- a/x-pack/test/security_api_integration/plugins/features_provider/server/index.ts +++ b/x-pack/test/security_api_integration/plugins/features_provider/server/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PluginSetupContract as AlertingPluginsSetup } from '@kbn/alerting-plugin/server/plugin'; +import type { AlertingServerSetup } from '@kbn/alerting-plugin/server/plugin'; import { schema } from '@kbn/config-schema'; import type { CoreSetup, Plugin, PluginInitializer } from '@kbn/core/server'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server'; @@ -16,7 +16,7 @@ import { initRoutes } from './init_routes'; export interface PluginSetupDependencies { features: FeaturesPluginSetup; - alerting: AlertingPluginsSetup; + alerting: AlertingServerSetup; } export interface PluginStartDependencies { @@ -110,7 +110,10 @@ function case2FeatureSplit(deps: PluginSetupDependencies) { category: DEFAULT_APP_CATEGORIES.kibana, id: 'case_2_feature_a', name: 'Case #2 feature A (DEPRECATED)', - alerting: ['alerting_rule_type_one', 'alerting_rule_type_two'], + alerting: [ + { ruleTypeId: 'alerting_rule_type_one', consumers: ['case_2_feature_a'] }, + { ruleTypeId: 'alerting_rule_type_two', consumers: ['case_2_feature_a'] }, + ], cases: ['cases_owner_one', 'cases_owner_two'], privileges: { all: { @@ -122,12 +125,18 @@ function case2FeatureSplit(deps: PluginSetupDependencies) { management: { kibana: ['management_one', 'management_two'] }, alerting: { rule: { - all: ['alerting_rule_type_one', 'alerting_rule_type_two'], - read: ['alerting_rule_type_one', 'alerting_rule_type_two'], + all: [ + { ruleTypeId: 'alerting_rule_type_one', consumers: ['case_2_feature_a'] }, + { ruleTypeId: 'alerting_rule_type_two', consumers: ['case_2_feature_a'] }, + ], + read: [ + { ruleTypeId: 'alerting_rule_type_one', consumers: ['case_2_feature_a'] }, + { ruleTypeId: 'alerting_rule_type_two', consumers: ['case_2_feature_a'] }, + ], }, alert: { - all: ['alerting_rule_type_one', 'alerting_rule_type_two'], - read: ['alerting_rule_type_one', 'alerting_rule_type_two'], + all: [{ ruleTypeId: 'alerting_rule_type_one', consumers: ['case_2_feature_a'] }], + read: [{ ruleTypeId: 'alerting_rule_type_two', consumers: ['case_2_feature_a'] }], }, }, cases: { @@ -167,7 +176,12 @@ function case2FeatureSplit(deps: PluginSetupDependencies) { app: ['app_one'], catalogue: ['cat_one'], management: { kibana: ['management_one'] }, - alerting: ['alerting_rule_type_one'], + // In addition to registering the `case_2_feature_b` consumer, we also need to register + // `case_2_feature_a` as an additional consumer to ensure that users with either deprecated or + // replacement privileges can access the rules, regardless of which one created them. + alerting: [ + { ruleTypeId: 'alerting_rule_type_one', consumers: ['case_2_feature_a', 'case_2_feature_b'] }, + ], cases: ['cases_owner_one'], privileges: { all: { @@ -178,8 +192,34 @@ function case2FeatureSplit(deps: PluginSetupDependencies) { catalogue: ['cat_one'], management: { kibana: ['management_one'] }, alerting: { - rule: { all: ['alerting_rule_type_one'], read: ['alerting_rule_type_one'] }, - alert: { all: ['alerting_rule_type_one'], read: ['alerting_rule_type_one'] }, + rule: { + all: [ + { + ruleTypeId: 'alerting_rule_type_one', + consumers: ['case_2_feature_a', 'case_2_feature_b'], + }, + ], + read: [ + { + ruleTypeId: 'alerting_rule_type_one', + consumers: ['case_2_feature_a', 'case_2_feature_b'], + }, + ], + }, + alert: { + all: [ + { + ruleTypeId: 'alerting_rule_type_one', + consumers: ['case_2_feature_a', 'case_2_feature_b'], + }, + ], + read: [ + { + ruleTypeId: 'alerting_rule_type_one', + consumers: ['case_2_feature_a', 'case_2_feature_b'], + }, + ], + }, }, cases: { all: ['cases_owner_one'], @@ -208,7 +248,12 @@ function case2FeatureSplit(deps: PluginSetupDependencies) { app: ['app_two'], catalogue: ['cat_two'], management: { kibana: ['management_two'] }, - alerting: ['alerting_rule_type_two'], + // In addition to registering the `case_2_feature_c` consumer, we also need to register + // `case_2_feature_a` as an additional consumer to ensure that users with either deprecated or + // replacement privileges can access the rules, regardless of which one created them. + alerting: [ + { ruleTypeId: 'alerting_rule_type_two', consumers: ['case_2_feature_a', 'case_2_feature_c'] }, + ], cases: ['cases_owner_two'], privileges: { all: { @@ -219,8 +264,34 @@ function case2FeatureSplit(deps: PluginSetupDependencies) { catalogue: ['cat_two'], management: { kibana: ['management_two'] }, alerting: { - rule: { all: ['alerting_rule_type_two'], read: ['alerting_rule_type_two'] }, - alert: { all: ['alerting_rule_type_two'], read: ['alerting_rule_type_two'] }, + rule: { + all: [ + { + ruleTypeId: 'alerting_rule_type_two', + consumers: ['case_2_feature_a', 'case_2_feature_c'], + }, + ], + read: [ + { + ruleTypeId: 'alerting_rule_type_two', + consumers: ['case_2_feature_a', 'case_2_feature_c'], + }, + ], + }, + alert: { + all: [ + { + ruleTypeId: 'alerting_rule_type_two', + consumers: ['case_2_feature_a', 'case_2_feature_c'], + }, + ], + read: [ + { + ruleTypeId: 'alerting_rule_type_two', + consumers: ['case_2_feature_a', 'case_2_feature_c'], + }, + ], + }, }, cases: { all: ['cases_owner_two'], diff --git a/x-pack/test/security_api_integration/tests/features/deprecated_features.ts b/x-pack/test/security_api_integration/tests/features/deprecated_features.ts index 29135ff2440b..7887cd6a23dc 100644 --- a/x-pack/test/security_api_integration/tests/features/deprecated_features.ts +++ b/x-pack/test/security_api_integration/tests/features/deprecated_features.ts @@ -492,56 +492,88 @@ export default function ({ getService }: FtrProviderContext) { const ruleOneTransformed = await createRule( transformedUser, 'case_2_a_transform_one', - 'case_2_feature_b', + 'case_2_feature_a', 'alerting_rule_type_one' ); const ruleTwoTransformed = await createRule( transformedUser, 'case_2_a_transform_two', + 'case_2_feature_a', + 'alerting_rule_type_two' + ); + + // Create rules as user with new privileges (B). + const newUserB = getUserCredentials('case_2_b_new'); + const ruleOneNewBConsumerA = await createRule( + newUserB, + 'case_2_b_new_one', + 'case_2_feature_a', + 'alerting_rule_type_one' + ); + const ruleOneNewBConsumerB = await createRule( + newUserB, + 'case_2_b_new_one', + 'case_2_feature_b', + 'alerting_rule_type_one' + ); + + // Create cases as user with new privileges (C). + const newUserC = getUserCredentials('case_2_c_new'); + const ruleTwoNewCConsumerA = await createRule( + newUserC, + 'case_2_c_new_two', + 'case_2_feature_a', + 'alerting_rule_type_two' + ); + const ruleTwoNewCConsumerC = await createRule( + newUserC, + 'case_2_c_new_two', 'case_2_feature_c', 'alerting_rule_type_two' ); // Users with deprecated privileges should be able to access rules created by themselves and - // users with new privileges. + // users with new privileges assuming the consumer is the same. for (const ruleToCheck of [ ruleOneDeprecated, ruleTwoDeprecated, ruleOneTransformed, ruleTwoTransformed, + ruleOneNewBConsumerA, + ruleTwoNewCConsumerA, ]) { expect(await getRule(deprecatedUser, ruleToCheck.id)).toBeDefined(); + expect(await getRule(transformedUser, ruleToCheck.id)).toBeDefined(); } - // NOTE: Scenarios below require SO migrations for both alerting rules and alerts to switch to - // a new producer that is tied to feature ID. Presumably we won't have this requirement once - // https://github.com/elastic/kibana/pull/183756 is resolved. - - // Create rules as user with new privileges (B). - // const newUserB = getUserCredentials('case_2_b_new'); - // const caseOneNewB = await createRule(newUserB, { - // title: 'case_2_b_new_one', - // owner: 'cases_owner_one', - // }); - // - // // Create cases as user with new privileges (C). - // const newUserC = getUserCredentials('case_2_c_new'); - // const caseTwoNewC = await createRule(newUserC, { - // title: 'case_2_c_new_two', - // owner: 'cases_owner_two', - // }); - // + // Any new consumer that is not known to the deprecated feature shouldn't be available to the + // users with the deprecated privileges unless deprecated features are update to explicitly + // support new consumers. + for (const ruleToCheck of [ruleOneNewBConsumerB, ruleTwoNewCConsumerC]) { + expect(await getRule(deprecatedUser, ruleToCheck.id)).toBeUndefined(); + expect(await getRule(transformedUser, ruleToCheck.id)).toBeDefined(); + } - // User B and User C should be able to access cases created by themselves and users with - // deprecated and transformed privileges, but only for the specific owner. - // for (const caseToCheck of [ruleOneDeprecated, ruleOneTransformed, caseOneNewB]) { - // expect(await getRule(newUserB, caseToCheck.id)).toBeDefined(); - // expect(await getRule(newUserC, caseToCheck.id)).toBeUndefined(); - // } - // for (const caseToCheck of [ruleTwoDeprecated, ruleTwoTransformed, caseTwoNewC]) { - // expect(await getRule(newUserC, caseToCheck.id)).toBeDefined(); - // expect(await getRule(newUserB, caseToCheck.id)).toBeUndefined(); - // } + // User B and User C should be able to access rule types created by themselves and users with + // deprecated and transformed privileges, but only for the specific consumer. + for (const ruleToCheck of [ + ruleOneDeprecated, + ruleOneTransformed, + ruleOneNewBConsumerA, + ruleOneNewBConsumerB, + ]) { + expect(await getRule(newUserB, ruleToCheck.id)).toBeDefined(); + expect(await getRule(newUserC, ruleToCheck.id)).toBeUndefined(); + } + for (const ruleToCheck of [ + ruleTwoDeprecated, + ruleTwoTransformed, + ruleTwoNewCConsumerA, + ruleTwoNewCConsumerC, + ]) { + expect(await getRule(newUserC, ruleToCheck.id)).toBeDefined(); + expect(await getRule(newUserB, ruleToCheck.id)).toBeUndefined(); + } }); }); } diff --git a/x-pack/test/security_solution_api_integration/README.md b/x-pack/test/security_solution_api_integration/README.md index 8f5aafdf15f9..e2ffcb8ac79d 100644 --- a/x-pack/test/security_solution_api_integration/README.md +++ b/x-pack/test/security_solution_api_integration/README.md @@ -3,42 +3,39 @@ This directory serves as a centralized location to place the security solution tests that run in Serverless and ESS environments. ## Subdirectories - -1. `config` stores base configurations specific to both the Serverless and ESS environments, These configurations build upon the base configuration provided by `xpack/test_serverless` and `x-pack-api_integrations`, incorporating additional settings such as environment variables and tagging options. - - -2. `test_suites` directory now houses all the tests along with their utility functions. As an initial step, -we have introduced the `detection_response` directory to consolidate all the integration tests related to detection and response APIs. - +- `config` stores base configurations specific to both the Serverless and ESS environments, These configurations build upon the base configuration provided by `xpack/test_serverless` and `x-pack-api_integrations`, incorporating additional settings such as environment variables and tagging options. +- `es_archive` and `es_archive_path_builder` directories contain the data that can be used by the tests +- `scripts` directory contains various scripts used to run the tests +- `test_suites` directory houses all the tests along with their utility functions. As an initial step, we have introduced the `detection_response` directory to consolidate all the integration tests related to detection and response APIs. ## Overview -- In this directory, Mocha tagging is utilized to assign tags to specific test suites and individual test cases. This tagging system enables the ability to selectively apply tags to test suites and test cases, facilitating the exclusion of specific test cases within a test suite as needed. - -- Test suites and cases are prefixed with specific tags to determine their execution in particular environments or to exclude them from specific environments. - -- We are using the following tags: - * `@ess`: Runs in an ESS environment (on-prem installation) as part of the CI validation on PRs. - - * `@serverless`: Runs in the first quality gate and in the periodic pipeline. +Test suites and cases are prefixed with specific tags to determine their execution in particular environments or to exclude them from specific environments: +* `@ess`: Runs in an ESS environment (on-prem installation) as part of the CI validation on PRs. - * `@serverlessQA`: Runs in the Kibana QA quality gate. +* `@serverless`: Runs in an simulated serverless environment as part of the CI validation on PRs and in the periodic pipeline. - * `@skipInEss`: Skipped for ESS environment. +* `@serverlessQA`: Runs in the Kibana QA quality gate. - * `@skipInServerless`: Skipped for all quality gates, CI and periodic pipeline. +* `@skipInEss`: Skipped for ESS environment. +* `@skipInServerless`: Skipped for all quality gates and periodic pipeline. +* `@skipInServerlessMKI`: Skipped from being executed in any MKI environment (periodic pipeline and Kibana QA quality gate), but executed as part of the first quality gate if the `@serverless` tag is present. - * `@skipInServerlessMKI`: Skipped for all the MKI environments. +For example: +```typescript +// tests in this suite will run in both Ess and Serverless on every PRs as well as on the first quality gate and the periodic pipeline +describe('@serverless @ess create_rules', () => { + describe('creating rules', () => { + it('my first test', async () => { ... }); + it('my second test', async () => { ... }); + }); -ex: -``` - describe('@serverless @ess create_rules', () => { ==> tests in this suite will run in both Ess and Serverless - describe('creating rules', () => {}); - - // This test is skipped due to flakiness in serverless environments: https://github.com/elastic/kibana/issues/497777 - describe('@skipInServerless missing timestamps', () => {}); ==> tests in this suite will be excluded in Serverless - - ``` + // tests in this suite will be excluded in Serverless on every PRs as well as on the first quality gate and the periodic pipeline + describe('@skipInServerless missing timestamps', () => { + it('another test', async () => { ... }); + }); +}); +``` # Adding new security area's tests @@ -53,7 +50,8 @@ The default project type configuration in Serverless is complete. If for the nee There are already configurations in the `./scripts/api_configs.json` which you can follow in order to add yours when it is needed. The currently supported configuration, allows **ONLY** the PLIs to be configured. Thus, experimental feature flags **are not yet supported** and the test should be skipped until further notice. -**NOTE**: If a target script living in `package.json` file, does not require any further configuration, then the entry in `./scripts/api_configs.json` file, **can be omitted!** +> **Note:** +>If a target script living in `package.json` file, does not require any further configuration, then the entry in `./scripts/api_configs.json` file, **can be omitted!** # Testing locally @@ -80,41 +78,39 @@ In this project, you can run various commands to execute tests and workflows, ea - Description: Runs the tests for the Detections Response area with the default license. - - 2. Executes particular sets of test suites linked to the designated environment and license: - - The command structure follows this pattern: - - - ``: The test folder or workflow you want to run. - - ``: The type of project to pick the relevant configurations, either "serverless" or "ess." - - "serverless" and "ess" help determine the configuration specific to the chosen test. - - ``: The testing environment, such as "serverlessEnv," "essEnv," or "qaEnv." - - When using "serverlessEnv,.." in the script, it appends the correct grep command for filtering tests in the serverless testing environment. - - "serverlessEnv,..." is used to customize the test execution based on the serverless environment. - - - Here are some command examples for "exceptions" which defined under the "detection_engine" area using the default license: - - 1. **Run the server for "exception_workflows" in the "serverlessEnv" environment:** - ```shell - npm run initialize-server:dr:default exceptions/workflows serverless - ``` - 2. **To run tests for the "exception_workflows" using the serverless runner in the "serverlessEnv" environment, you can use the following command:** - ```shell - npm run run-tests:dr:default exceptions/workflows serverless serverlessEnv - ``` - 3. **Run tests for "exception_workflows" using the serverless runner in the "qaEnv" environment:** - ```shell - npm run run-tests:dr:default exceptions/workflows serverless qaPeriodicEnv - ``` - 4. **Run the server for "exception_workflows" in the "essEnv" environment:** - ```shell - npm run initialize-server:dr:default exceptions/workflows ess - ``` - 5. **Run tests for "exception_workflows" using the ess runner in the "essEnv" environment:** - ```shell - npm run run-tests:dr:default exceptions/workflows ess essEnv - ``` +2. Executes particular sets of test suites linked to the designated environment and license: + + The command structure follows this pattern: + + - ``: The test folder or workflow you want to run. + - ``: The type of project to pick the relevant configurations, either "serverless" or "ess." + - "serverless" and "ess" help determine the configuration specific to the chosen test. + - ``: The testing environment, such as "serverlessEnv," "essEnv," or "qaEnv." + - When using "serverlessEnv,.." in the script, it appends the correct grep command for filtering tests in the serverless testing environment. + - "serverlessEnv,..." is used to customize the test execution based on the serverless environment. + + Here are some command examples for "exceptions" which defined under the "detection_engine" area using the default license: + +- Run the server for "exception_workflows" in the "serverlessEnv" environment: + ```shell + npm run initialize-server:dr:default exceptions/workflows serverless + ``` +- To run tests for the "exception_workflows" using the serverless runner in the "serverlessEnv" environment, you can use the following command: + ```shell + npm run run-tests:dr:default exceptions/workflows serverless serverlessEnv + ``` +- Run tests for "exception_workflows" using the serverless runner in the "qaEnv" environment: + ```shell + npm run run-tests:dr:default exceptions/workflows serverless qaPeriodicEnv + ``` +- Run the server for "exception_workflows" in the "essEnv" environment: + ```shell + npm run initialize-server:dr:default exceptions/workflows ess + ``` +- Run tests for "exception_workflows" using the ess runner in the "essEnv" environment: + ```shell + npm run run-tests:dr:default exceptions/workflows ess essEnv + ``` ## Testing with serverless roles @@ -126,28 +122,29 @@ All API calls using the returned instance will inject the required auth headers. **On ESS, `createSuperTest` returns a basic `supertest` instance without headers.* -```js +```typescript import TestAgent from 'supertest/lib/agent'; export default ({ getService }: FtrProviderContext) => { - const utils = getService('securitySolutionUtils'); + const utils = getService('securitySolutionUtils'); - describe('@ess @serverless my_test', () => { - let supertest: TestAgent; + describe('@ess @serverless my_test', () => { + let supertest: TestAgent; - before(async () => { - supertest = await utils.createSuperTest('admin'); - }); - ... + before(async () => { + supertest = await utils.createSuperTest('admin'); + }); + ... + }); +}); ``` If you need to use multiple roles in a single test, you can instantiate multiple `supertest` versions. -```js +```typescript before(async () => { adminSupertest = await utils.createSuperTest('admin'); viewerSupertest = await utils.createSuperTest('viewer'); }); -... ``` -The helper keeps track of only one active session per role. So, if you instantiate `supertest` twice for the same role, the first instance will have an invalid API key. +The helper keeps track of only one active session per role. So, if you instantiate `supertest` twice for the same role, the first instance will have an invalid API key. \ No newline at end of file diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.data_source_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.data_source_fields.ts index f3b009a8ade4..b95208856a27 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.data_source_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.data_source_fields.ts @@ -897,11 +897,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(fieldDiffObject.data_source).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -958,7 +958,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + tags + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // tags expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.eql_query_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.eql_query_fields.ts index f500f8691485..eef3e4b6b7ce 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.eql_query_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.eql_query_fields.ts @@ -382,11 +382,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(fieldDiffObject.eql_query).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // `version` is considered an updated field - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // `version` is considered conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -451,7 +451,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); // version + query - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + query + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // query expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.esql_query_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.esql_query_fields.ts index f77f59b16a3e..9561393e8454 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.esql_query_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.esql_query_fields.ts @@ -356,11 +356,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(fieldDiffObject.esql_query).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -420,7 +420,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + query + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // query expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts index 3afb63a4c797..e8f9d2f48b9e 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.kql_query_fields.ts @@ -1042,11 +1042,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(fieldDiffObject.kql_query).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); // `version` is considered an updated field - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // `version` is considered conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -1114,7 +1114,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + query + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // query expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts index d9c20fc28b43..23bfd08f5b52 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.multi_line_string_fields.ts @@ -386,7 +386,7 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.rules[0].diff.fields.description).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); }); }); @@ -430,7 +430,7 @@ export default ({ getService }: FtrProviderContext): void => { has_base_version: false, }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts index 51ab509d1690..bd059ec137a9 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.number_fields.ts @@ -274,11 +274,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.rules[0].diff.fields.risk_score).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -322,7 +322,7 @@ export default ({ getService }: FtrProviderContext): void => { has_base_version: false, }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts index 0764bac554bf..3f6784108487 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.rule_type_fields.ts @@ -298,11 +298,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.rules[0].diff.fields.type).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -348,7 +348,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(3); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(3); // type + version + query are all considered conflicts + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // type + query are all considered conflicts expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(1); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts index 503a51f84f81..881e8e612217 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.scalar_array_fields.ts @@ -423,11 +423,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.rules[0].diff.fields.tags).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -472,7 +472,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // version + tags + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // tags expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts index b887e18813ec..6fe10b9fa601 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/rules_management/prebuilt_rules/management/trial_license_complete_tier/upgrade_review_prebuilt_rules.single_line_string_fields.ts @@ -277,11 +277,11 @@ export default ({ getService }: FtrProviderContext): void => { expect(reviewResponse.rules[0].diff.fields.name).toBeUndefined(); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(1); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // version is considered a conflict + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(0); expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); - expect(reviewResponse.stats.num_rules_with_conflicts).toBe(1); + expect(reviewResponse.stats.num_rules_with_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_with_non_solvable_conflicts).toBe(0); }); }); @@ -326,7 +326,7 @@ export default ({ getService }: FtrProviderContext): void => { }); expect(reviewResponse.rules[0].diff.num_fields_with_updates).toBe(2); - expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(2); // name + version are both considered conflicts + expect(reviewResponse.rules[0].diff.num_fields_with_conflicts).toBe(1); // name is considered as a conflict expect(reviewResponse.rules[0].diff.num_fields_with_non_solvable_conflicts).toBe(0); expect(reviewResponse.stats.num_rules_to_upgrade_total).toBe(1); diff --git a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts index 5d0dcec11d9b..104fbf05b515 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/entity_analytics/entity_store/trial_license_complete_tier/entity_store.ts @@ -5,7 +5,7 @@ * 2.0. */ -import expect from '@kbn/expect'; +import expect from 'expect'; import { FtrProviderContext } from '../../../../ftr_provider_context'; import { EntityStoreUtils } from '../../utils'; import { dataViewRouteHelpersFactory } from '../../utils/data_view'; @@ -14,8 +14,7 @@ export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const utils = EntityStoreUtils(getService); - // Failing: See https://github.com/elastic/kibana/issues/200758 - describe.skip('@ess @skipInServerlessMKI Entity Store APIs', () => { + describe('@ess @skipInServerlessMKI Entity Store APIs', () => { const dataView = dataViewRouteHelpersFactory(supertest); before(async () => { @@ -85,7 +84,7 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); - expect(getResponse.body).to.eql({ + expect(getResponse.body).toEqual({ status: 'started', type: 'host', indexPattern: '', @@ -101,7 +100,7 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); - expect(getResponse.body).to.eql({ + expect(getResponse.body).toEqual({ status: 'started', type: 'user', indexPattern: '', @@ -118,7 +117,7 @@ export default ({ getService }: FtrProviderContext) => { // @ts-expect-error body is any const sortedEngines = body.engines.sort((a, b) => a.type.localeCompare(b.type)); - expect(sortedEngines).to.eql([ + expect(sortedEngines).toEqual([ { status: 'started', type: 'host', @@ -160,7 +159,7 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); - expect(body.status).to.eql('stopped'); + expect(body.status).toEqual('stopped'); }); it('should start the entity engine', async () => { @@ -176,7 +175,7 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(200); - expect(body.status).to.eql('started'); + expect(body.status).toEqual('started'); }); }); @@ -213,10 +212,11 @@ export default ({ getService }: FtrProviderContext) => { afterEach(async () => { await utils.cleanEngines(); }); + it('should return "not_installed" when no engines have been initialized', async () => { - const { body } = await api.getEntityStoreStatus().expect(200); + const { body } = await api.getEntityStoreStatus({ query: {} }).expect(200); - expect(body).to.eql({ + expect(body).toEqual({ engines: [], status: 'not_installed', }); @@ -225,23 +225,56 @@ export default ({ getService }: FtrProviderContext) => { it('should return "installing" when at least one engine is being initialized', async () => { await utils.enableEntityStore(); - const { body } = await api.getEntityStoreStatus().expect(200); + const { body } = await api.getEntityStoreStatus({ query: {} }).expect(200); - expect(body.status).to.eql('installing'); - expect(body.engines.length).to.eql(2); - expect(body.engines[0].status).to.eql('installing'); - expect(body.engines[1].status).to.eql('installing'); + expect(body.status).toEqual('installing'); + expect(body.engines.length).toEqual(2); + expect(body.engines[0].status).toEqual('installing'); + expect(body.engines[1].status).toEqual('installing'); }); it('should return "started" when all engines are started', async () => { await utils.initEntityEngineForEntityTypesAndWait(['host', 'user']); - const { body } = await api.getEntityStoreStatus().expect(200); + const { body } = await api.getEntityStoreStatus({ query: {} }).expect(200); + + expect(body.status).toEqual('running'); + expect(body.engines.length).toEqual(2); + expect(body.engines[0].status).toEqual('started'); + expect(body.engines[1].status).toEqual('started'); + }); - expect(body.status).to.eql('running'); - expect(body.engines.length).to.eql(2); - expect(body.engines[0].status).to.eql('started'); - expect(body.engines[1].status).to.eql('started'); + describe('status with components', () => { + it('should return empty list when when no engines have been initialized', async () => { + const { body } = await api + .getEntityStoreStatus({ query: { include_components: true } }) + .expect(200); + + expect(body).toEqual({ + engines: [], + status: 'not_installed', + }); + }); + + it('should return components status when engines are installed', async () => { + await utils.initEntityEngineForEntityTypesAndWait(['host']); + + const { body } = await api + .getEntityStoreStatus({ query: { include_components: true } }) + .expect(200); + + expect(body.engines[0].components).toEqual([ + expect.objectContaining({ resource: 'entity_definition' }), + expect.objectContaining({ resource: 'transform' }), + expect.objectContaining({ resource: 'ingest_pipeline' }), + expect.objectContaining({ resource: 'index_template' }), + expect.objectContaining({ resource: 'task' }), + expect.objectContaining({ resource: 'ingest_pipeline' }), + expect.objectContaining({ resource: 'enrich_policy' }), + expect.objectContaining({ resource: 'index' }), + expect.objectContaining({ resource: 'component_template' }), + ]); + }); }); }); @@ -262,14 +295,14 @@ export default ({ getService }: FtrProviderContext) => { it("should not update the index patten when it didn't change", async () => { const response = await api.applyEntityEngineDataviewIndices(); - expect(response.body).to.eql({ success: true, result: [{ type: 'host', changes: {} }] }); + expect(response.body).toEqual({ success: true, result: [{ type: 'host', changes: {} }] }); }); it('should update the index pattern when the data view changes', async () => { await dataView.updateIndexPattern('security-solution', 'test-*'); const response = await api.applyEntityEngineDataviewIndices(); - expect(response.body).to.eql({ + expect(response.body).toEqual({ success: true, result: [ { diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/eql_query_rule.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/eql_query_rule.cy.ts index 994dbb2eb8ce..d7bd6d8ebce7 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/eql_query_rule.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/detection_engine/rule_edit/eql_query_rule.cy.ts @@ -15,7 +15,8 @@ import { } from '../../../../tasks/edit_rule'; import { login } from '../../../../tasks/login'; -describe('EQL query rules', { tags: ['@ess', '@serverless'] }, () => { +// Failing: See https://github.com/elastic/kibana/issues/201334 +describe.skip('EQL query rules', { tags: ['@ess', '@serverless'] }, () => { context('Editing rule with non-blocking query validation errors', () => { beforeEach(() => { login(); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts index 86291d4eb9c7..72bb79302537 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/detection_response/rule_management/prebuilt_rules/prebuilt_rules_preview.cy.ts @@ -544,7 +544,7 @@ describe( const { threshold } = THRESHOLD_RULE_INDEX_PATTERN['security-rule'] as { threshold: Threshold; }; - assertThresholdPropertyShown(threshold.value); + assertThresholdPropertyShown(threshold); const { index } = THRESHOLD_RULE_INDEX_PATTERN['security-rule'] as { index: string[] }; assertIndexPropertyShown(index); @@ -952,7 +952,7 @@ describe( const { threshold } = UPDATED_THRESHOLD_RULE_INDEX_PATTERN['security-rule'] as { threshold: Threshold; }; - assertThresholdPropertyShown(threshold.value); + assertThresholdPropertyShown(threshold); const { index } = UPDATED_THRESHOLD_RULE_INDEX_PATTERN['security-rule'] as { index: string[]; diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboard.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboard.cy.ts new file mode 100644 index 000000000000..272207aaf7f8 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics/dashboard.cy.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 { login } from '../../tasks/login'; +import { visit } from '../../tasks/navigation'; +import { ENTITY_ANALYTICS_DASHBOARD_URL } from '../../urls/navigation'; + +import { deleteRiskEngineConfiguration } from '../../tasks/api_calls/risk_engine'; + +import { + PAGE_TITLE, + ENTITY_STORE_ENABLEMENT_PANEL, + ENABLEMENT_MODAL_RISK_SCORE_SWITCH, + ENABLEMENT_MODAL_ENTITY_STORE_SWITCH, +} from '../../screens/entity_analytics/dashboard'; +import { + openEntityStoreEnablementModal, + confirmEntityStoreEnablement, + waitForEntitiesListToAppear, +} from '../../tasks/entity_analytics'; + +describe( + 'Entity analytics dashboard page', + { + tags: ['@ess'], + }, + () => { + before(() => { + cy.task('esArchiverLoad', { archiveName: 'all_users' }); + }); + + beforeEach(() => { + login(); + deleteRiskEngineConfiguration(); + visit(ENTITY_ANALYTICS_DASHBOARD_URL); + }); + + after(() => { + cy.task('esArchiverUnload', { archiveName: 'all_users' }); + }); + + it('renders page as expected', () => { + cy.get(PAGE_TITLE).should('have.text', 'Entity Analytics'); + }); + + describe('Entity Store enablement', () => { + it('renders enablement panel', () => { + cy.get(ENTITY_STORE_ENABLEMENT_PANEL).contains('Enable entity store and risk score'); + }); + + it('enables risk score followed by the store', () => { + openEntityStoreEnablementModal(); + + cy.get(ENABLEMENT_MODAL_RISK_SCORE_SWITCH).should('be.visible'); + cy.get(ENABLEMENT_MODAL_ENTITY_STORE_SWITCH).should('be.visible'); + + confirmEntityStoreEnablement(); + + waitForEntitiesListToAppear(); + }); + }); + } +); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts index 1920bd01668f..eba2dbe770e4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts @@ -21,7 +21,6 @@ import { DETECTION_RESPONSE, DASHBOARDS, CSP_DASHBOARD, - KUBERNETES, INDICATORS, BLOCKLIST, CSP_BENCHMARKS, @@ -54,7 +53,6 @@ import { EXPLORE_URL, MANAGE_URL, CSP_DASHBOARD_URL, - KUBERNETES_URL, BLOCKLIST_URL, CSP_BENCHMARKS_URL, CSP_FINDINGS_URL, @@ -114,11 +112,6 @@ describe('top-level navigation common to all pages in the Security app', { tags: cy.url().should('include', ENTITY_ANALYTICS_URL); }); - it('navigates to the Kubernetes page', () => { - navigateFromHeaderTo(KUBERNETES); - cy.url().should('include', KUBERNETES_URL); - }); - it('navigates to the CSP dashboard page', () => { navigateFromHeaderTo(CSP_DASHBOARD); cy.url().should('include', CSP_DASHBOARD_URL); @@ -289,11 +282,6 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => { cy.url().should('include', ENTITY_ANALYTICS_URL); }); - it('navigates to the Kubernetes page', () => { - navigateFromHeaderTo(ServerlessHeaders.KUBERNETES, true); - cy.url().should('include', KUBERNETES_URL); - }); - it('navigates to the CSP dashboard page', () => { navigateFromHeaderTo(ServerlessHeaders.CSP_DASHBOARD, true); cy.url().should('include', CSP_DASHBOARD_URL); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts index 509ba40e57fc..53db62751ebd 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/alerts_charts.cy.ts @@ -103,7 +103,8 @@ describe('KPI visualizations in Alerts Page', { tags: ['@ess', '@serverless'] }, }); }); - context('Histogram legend hover actions', () => { + // For some reason this suite is failing in CI while I cannot reproduce it locally + context.skip('Histogram legend hover actions', () => { it('should should add a filter in to KQL bar', () => { selectAlertsHistogram(); const expectedNumberOfAlerts = 1; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts index 315e89564aae..903b463d6f58 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/create_new_rule.ts @@ -268,10 +268,9 @@ export const NEW_TERMS_TYPE = '[data-test-subj="newTermsRuleType"]'; export const ESQL_TYPE = '[data-test-subj="esqlRuleType"]'; -export const ESQL_QUERY_BAR_INPUT_AREA = - '[data-test-subj="detectionEngineStepDefineRuleEsqlQueryBar"] textarea'; +export const ESQL_QUERY_BAR_INPUT_AREA = '[data-test-subj="ruleEsqlQueryBar"] textarea'; -export const ESQL_QUERY_BAR = '[data-test-subj="detectionEngineStepDefineRuleEsqlQueryBar"]'; +export const ESQL_QUERY_BAR = '[data-test-subj="ruleEsqlQueryBar"]'; export const NEW_TERMS_INPUT_AREA = '[data-test-subj="newTermsInput"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics/dashboard.ts b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics/dashboard.ts new file mode 100644 index 000000000000..78b619979e96 --- /dev/null +++ b/x-pack/test/security_solution_cypress/cypress/screens/entity_analytics/dashboard.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PAGE_TITLE = '[data-test-subj="entityAnalyticsPage"]'; + +export const ENTITY_STORE_ENABLEMENT_PANEL = '[data-test-subj="entityStoreEnablementPanel"]'; +export const ENTITY_STORE_ENABLEMENT_BUTTON = '[data-test-subj="entityStoreEnablementButton"]'; + +export const ENTITY_STORE_ENABLEMENT_MODAL = '[data-test-subj="entityStoreEnablementModal"]'; + +export const ENABLEMENT_MODAL_RISK_SCORE_SWITCH = '[data-test-subj="enablementRiskScoreSwitch"]'; +export const ENABLEMENT_MODAL_ENTITY_STORE_SWITCH = + '[data-test-subj="enablementEntityStoreSwitch"]'; + +export const ENABLEMENT_MODAL_CONFIRM_BUTTON = + '[data-test-subj="entityStoreEnablementModalButton"]'; + +export const ENABLEMENT_RISK_ENGINE_INITIALIZING_PANEL = + '[data-test-subj="riskEngineInitializingPanel"]'; + +export const ENABLEMENT_ENTITY_STORE_INITIALIZING_PANEL = + '[data-test-subj="entityStoreInitializingPanel"]'; + +export const ENTITIES_LIST_PANEL = '[data-test-subj="entitiesListPanel"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts index b70adbefa185..8602064af92a 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/alerts.ts @@ -81,6 +81,7 @@ import { FIELDS_BROWSER_BTN } from '../screens/rule_details'; import { openFilterGroupContextMenu } from './common/filter_group'; import { visitWithTimeRange } from './navigation'; import { GET_DATA_GRID_HEADER_ACTION_BUTTON } from '../screens/common/data_grid'; +import { getDataTestSubjectSelector } from '../helpers/common'; export const addExceptionFromFirstAlert = () => { expandFirstAlertActions(); @@ -195,9 +196,19 @@ export const closePageFilterPopover = (filterIndex: number) => { cy.get(OPTION_LIST_VALUES(filterIndex)).should('not.have.class', 'euiFilterButton-isSelected'); }; +export const hasSelection = (filterIndex: number) => { + return cy.get(OPTION_LIST_VALUES(filterIndex)).then(($el) => { + return $el.find(getDataTestSubjectSelector('optionsListSelections')).length > 0; + }); +}; + export const clearAllSelections = (filterIndex: number) => { - cy.get(OPTION_LIST_VALUES(filterIndex)).realHover(); - cy.get(OPTION_LIST_CLEAR_BTN).eq(filterIndex).click(); + hasSelection(filterIndex).then(($el) => { + if ($el) { + cy.get(OPTION_LIST_VALUES(filterIndex)).realHover(); + cy.get(OPTION_LIST_CLEAR_BTN).eq(filterIndex).click(); + } + }); }; export const selectPageFilterValue = (filterIndex: number, ...values: string[]) => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts index 2265f228c2ce..91a5c36a5192 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/entity_analytics.ts @@ -27,6 +27,12 @@ import { import { visitWithTimeRange } from './navigation'; import { GET_DATE_PICKER_APPLY_BUTTON, GLOBAL_FILTERS_CONTAINER } from '../screens/date_picker'; import { REFRESH_BUTTON } from '../screens/security_header'; +import { + ENABLEMENT_MODAL_CONFIRM_BUTTON, + ENTITIES_LIST_PANEL, + ENTITY_STORE_ENABLEMENT_BUTTON, + ENTITY_STORE_ENABLEMENT_MODAL, +} from '../screens/entity_analytics/dashboard'; export const updateDashboardTimeRange = () => { // eslint-disable-next-line cypress/no-force @@ -113,3 +119,17 @@ export const upgradeRiskEngine = () => { updateRiskEngineConfirm(); cy.get(RISK_SCORE_STATUS).should('have.text', 'On'); }; + +export const openEntityStoreEnablementModal = () => { + cy.get(ENTITY_STORE_ENABLEMENT_BUTTON).click(); + cy.get(ENTITY_STORE_ENABLEMENT_MODAL).contains('Entity Analytics Enablement'); +}; + +export const confirmEntityStoreEnablement = () => { + cy.get(ENABLEMENT_MODAL_CONFIRM_BUTTON).click(); +}; + +export const waitForEntitiesListToAppear = () => { + cy.get(ENTITIES_LIST_PANEL, { timeout: 30000 }).scrollIntoView(); + cy.get(ENTITIES_LIST_PANEL).contains('Entities'); +}; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules_preview.ts b/x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules_preview.ts index 6617b10ccc21..c67ab2983107 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules_preview.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/prebuilt_rules_preview.ts @@ -8,7 +8,10 @@ import { capitalize } from 'lodash'; import type { ThreatMapping } from '@kbn/securitysolution-io-ts-alerting-types'; import type { Module } from '@kbn/ml-plugin/common/types/modules'; -import { AlertSuppression } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema'; +import { + AlertSuppression, + Threshold, +} from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema'; import type { Filter } from '@kbn/es-query'; import type { PrebuiltRuleAsset } from '@kbn/security-solution-plugin/server/lib/detection_engine/prebuilt_rules'; import { @@ -312,9 +315,15 @@ export const assertMachineLearningPropertiesShown = ( }); }; -export const assertThresholdPropertyShown = (thresholdValue: number) => { +export const assertThresholdPropertyShown = (threshold: Threshold) => { cy.get(THRESHOLD_TITLE).should('have.text', 'Threshold'); - cy.get(THRESHOLD_VALUE).should('contain', thresholdValue); + cy.get(THRESHOLD_VALUE).should('contain', threshold.value); + if (threshold.cardinality) { + cy.get(THRESHOLD_VALUE).should( + 'contain', + `when unique values count of ${threshold.cardinality[0].field} >= ${threshold.cardinality[0].value}` + ); + } }; export const assertEqlQueryPropertyShown = (query: string) => { diff --git a/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts b/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts index b5855192d18e..6f6f4dc1a108 100644 --- a/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts +++ b/x-pack/test/security_solution_cypress/cypress/urls/navigation.ts @@ -79,3 +79,6 @@ export const exceptionsListDetailsUrl = (listId: string) => export const DISCOVER_URL = '/app/discover'; export const OSQUERY_URL = '/app/osquery'; export const FLEET_URL = '/app/fleet'; + +// Entity Analytics +export const ENTITY_ANALYTICS_DASHBOARD_URL = '/app/security/entity_analytics'; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/data_usage/tests/data_streams.ts b/x-pack/test_serverless/api_integration/test_suites/common/data_usage/tests/data_streams.ts index b6559c3efc9b..b4dd8d51c331 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/data_usage/tests/data_streams.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/data_usage/tests/data_streams.ts @@ -14,10 +14,10 @@ import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const svlDatastreamsHelpers = getService('svlDatastreamsHelpers'); const roleScopedSupertest = getService('roleScopedSupertest'); + const retry = getService('retry'); let supertestAdminWithCookieCredentials: SupertestWithRoleScope; const testDataStreamName = 'test-data-stream'; describe(`GET ${DATA_USAGE_DATA_STREAMS_API_ROUTE}`, function () { - // due to the plugin depending on yml config (xpack.dataUsage.enabled), we cannot test in MKI until it is on by default this.tags(['skipMKI']); before(async () => { await svlDatastreamsHelpers.createDataStream(testDataStreamName); @@ -34,14 +34,30 @@ export default function ({ getService }: FtrProviderContext) { }); it('returns created data streams', async () => { + await retry.tryForTime(10000, async () => { + const res = await supertestAdminWithCookieCredentials + .get(DATA_USAGE_DATA_STREAMS_API_ROUTE) + .query({ includeZeroStorage: true }) + .set('elastic-api-version', '1'); + const dataStreams: DataStreamsResponseBodySchemaBody = res.body; + const foundStream = dataStreams.find((stream) => stream.name === testDataStreamName); + if (!foundStream) { + throw new Error(`Data stream "${testDataStreamName}" not found. Retrying...`); + } + expect(res.statusCode).to.be(200); + expect(foundStream?.name).to.be(testDataStreamName); + expect(foundStream?.storageSizeBytes).to.be(0); + return true; + }); + }); + it('does not return created data streams without size', async () => { const res = await supertestAdminWithCookieCredentials .get(DATA_USAGE_DATA_STREAMS_API_ROUTE) .set('elastic-api-version', '1'); const dataStreams: DataStreamsResponseBodySchemaBody = res.body; const foundStream = dataStreams.find((stream) => stream.name === testDataStreamName); - expect(foundStream?.name).to.be(testDataStreamName); - expect(foundStream?.storageSizeBytes).to.be(0); expect(res.statusCode).to.be(200); + expect(foundStream).to.be(undefined); }); }); } diff --git a/x-pack/test_serverless/api_integration/test_suites/common/favorites/dashboard.ts b/x-pack/test_serverless/api_integration/test_suites/common/favorites/dashboard.ts new file mode 100644 index 000000000000..05ad57aadbf1 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/favorites/dashboard.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const roleScopedSupertest = getService('roleScopedSupertest'); + const kibanaServer = getService('kibanaServer'); + + describe('Favorites dashboard api', function () { + before(async () => { + await kibanaServer.savedObjects.clean({ + types: ['favorites'], + }); + }); + + it('can favorite a dashboard', async () => { + const supertest = await roleScopedSupertest.getSupertestWithRoleScope('viewer', { + useCookieHeader: true, // favorite only works with Cookie header + withInternalHeaders: true, + }); + + let response = await supertest + .get('/internal/content_management/favorites/dashboard') + .expect(200); + expect(response.body.favoriteIds).to.eql([]); + + const favoriteId = '1'; + + response = await supertest + .post(`/internal/content_management/favorites/dashboard/${favoriteId}/favorite`) + .expect(200); + + expect(response.body.favoriteIds).to.eql([favoriteId]); + + response = await supertest + .post(`/internal/content_management/favorites/dashboard/${favoriteId}/unfavorite`) + .expect(200); + expect(response.body.favoriteIds).to.eql([]); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/favorites/esql.ts b/x-pack/test_serverless/api_integration/test_suites/common/favorites/esql.ts new file mode 100644 index 000000000000..4dfb92273a41 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/favorites/esql.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const roleScopedSupertest = getService('roleScopedSupertest'); + const kibanaServer = getService('kibanaServer'); + + describe('Favorites esql query api', function () { + before(async () => { + await kibanaServer.savedObjects.clean({ + types: ['favorites'], + }); + }); + + it('can favorite an esql_query', async () => { + const supertest = await roleScopedSupertest.getSupertestWithRoleScope('viewer', { + useCookieHeader: true, // favorite only works with Cookie header + withInternalHeaders: true, + }); + + const list = () => + supertest.get('/internal/content_management/favorites/esql_query').expect(200); + + let response = await list(); + expect(response.body.favoriteIds).to.eql([]); + + const favoriteId = '1'; + const metadata = { + queryString: 'SELECT * FROM test1', + createdAt: '2021-09-01T00:00:00Z', + status: 'success', + }; + + response = await supertest + .post(`/internal/content_management/favorites/esql_query/${favoriteId}/favorite`) + .send({ metadata }) + .expect(200); + + expect(response.body.favoriteIds).to.eql([favoriteId]); + + response = await list(); + expect(response.body.favoriteIds).to.eql([favoriteId]); + expect(response.body.favoriteMetadata).to.eql({ [favoriteId]: metadata }); + + response = await supertest + .post(`/internal/content_management/favorites/esql_query/${favoriteId}/unfavorite`) + .expect(200); + expect(response.body.favoriteIds).to.eql([]); + + response = await list(); + expect(response.body.favoriteIds).to.eql([]); + expect(response.body.favoriteMetadata).to.eql({}); + }); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/favorites/index.ts b/x-pack/test_serverless/api_integration/test_suites/common/favorites/index.ts new file mode 100644 index 000000000000..684f88f6ac97 --- /dev/null +++ b/x-pack/test_serverless/api_integration/test_suites/common/favorites/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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('Favorites API', function () { + loadTestFile(require.resolve('./dashboard')); + loadTestFile(require.resolve('./esql')); + }); +} diff --git a/x-pack/test_serverless/api_integration/test_suites/common/telemetry/snapshot_telemetry.ts b/x-pack/test_serverless/api_integration/test_suites/common/telemetry/snapshot_telemetry.ts index b3d7f812de3e..fa3ff28fa2f1 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/telemetry/snapshot_telemetry.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/telemetry/snapshot_telemetry.ts @@ -11,7 +11,12 @@ import ossRootTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_root.json'; import xpackRootTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_root.json'; import ossPluginsTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_plugins.json'; import ossPackagesTelemetrySchema from '@kbn/telemetry-plugin/schema/kbn_packages.json'; +import ossPlatformTelemetrySchema from '@kbn/telemetry-plugin/schema/oss_platform.json'; import xpackPluginsTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_plugins.json'; +import xpackPlatformTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_platform.json'; +import xpackObservabilityTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_observability.json'; +import xpackSearchTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_search.json'; +import xpackSecurityTelemetrySchema from '@kbn/telemetry-collection-xpack-plugin/schema/xpack_security.json'; import { assertTelemetryPayload } from '@kbn/telemetry-tools'; import type { UsageStatsPayloadTestFriendly } from '@kbn/test-suites-xpack/api_integration/services/usage_api'; import type { RoleCredentials } from '../../../../shared/services'; @@ -42,10 +47,16 @@ export default function ({ getService }: FtrProviderContext) { it('should pass the schema validation (ensures BWC with Classic offering)', () => { const root = deepmerge(ossRootTelemetrySchema, xpackRootTelemetrySchema); - const plugins = deepmerge( - deepmerge(ossPluginsTelemetrySchema, ossPackagesTelemetrySchema), - xpackPluginsTelemetrySchema - ); + const plugins = [ + ossPluginsTelemetrySchema, + ossPackagesTelemetrySchema, + ossPlatformTelemetrySchema, + xpackPluginsTelemetrySchema, + xpackPlatformTelemetrySchema, + xpackObservabilityTelemetrySchema, + xpackSearchTelemetrySchema, + xpackSecurityTelemetrySchema, + ].reduce((acc, schema) => deepmerge(acc, schema)); try { assertTelemetryPayload({ root, plugins }, stats); diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts index 68202b5adf3a..c3feabb61e1d 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/common_configs/config.group1.ts @@ -33,6 +33,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/saved_objects_management'), require.resolve('../../common/telemetry'), require.resolve('../../common/data_usage'), + require.resolve('../../common/favorites'), ], junit: { reportName: 'Serverless Observability API Integration Tests - Common Group 1', diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/config.ts b/x-pack/test_serverless/api_integration/test_suites/observability/config.ts index fa0714aa6154..e92609cc66dd 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/config.ts @@ -27,6 +27,7 @@ export default createTestConfig({ // useful for testing (also enabled in MKI QA) '--coreApp.allowDynamicConfigOverrides=true', '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', // dataUsage.autoops* config is set in kibana controller '--xpack.dataUsage.autoops.enabled=true', '--xpack.dataUsage.autoops.api.url=http://localhost:9000', diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts b/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts index e49a9ed45871..b6dbceedfe65 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/platform_security/authorization.ts @@ -44,6 +44,7 @@ export default function ({ getService }: FtrProviderContext) { const features = Object.fromEntries( Object.entries(body.features).filter(([key]) => compositeFeatureIds.includes(key)) ); + expectSnapshot(features).toMatchInline(` Object { "apm": Object { @@ -126,6 +127,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/apm/rule/runSoon", "alerting:apm.error_rate/apm/rule/scheduleBackfill", "alerting:apm.error_rate/apm/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/apm/rule/get", "alerting:apm.transaction_error_rate/apm/rule/getRuleState", "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", @@ -154,6 +183,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/apm/rule/runSoon", "alerting:apm.transaction_error_rate/apm/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/apm/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/apm/rule/get", "alerting:apm.transaction_duration/apm/rule/getRuleState", "alerting:apm.transaction_duration/apm/rule/getAlertSummary", @@ -182,6 +239,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/apm/rule/runSoon", "alerting:apm.transaction_duration/apm/rule/scheduleBackfill", "alerting:apm.transaction_duration/apm/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/apm/rule/get", "alerting:apm.anomaly/apm/rule/getRuleState", "alerting:apm.anomaly/apm/rule/getAlertSummary", @@ -210,26 +295,74 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/apm/rule/runSoon", "alerting:apm.anomaly/apm/rule/scheduleBackfill", "alerting:apm.anomaly/apm/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:apm.error_rate/apm/alert/get", "alerting:apm.error_rate/apm/alert/find", "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/apm/alert/getAlertSummary", "alerting:apm.error_rate/apm/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/apm/alert/get", "alerting:apm.transaction_error_rate/apm/alert/find", "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", "alerting:apm.transaction_error_rate/apm/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/apm/alert/get", "alerting:apm.transaction_duration/apm/alert/find", "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/apm/alert/getAlertSummary", "alerting:apm.transaction_duration/apm/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/apm/alert/get", "alerting:apm.anomaly/apm/alert/find", "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/apm/alert/getAlertSummary", "alerting:apm.anomaly/apm/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "api:infra", "app:infra", "app:logs", @@ -294,6 +427,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/runSoon", "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -322,6 +483,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/runSoon", "alerting:.es-query/logs/rule/scheduleBackfill", "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -350,6 +539,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/runSoon", "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -378,171 +595,79 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", "alerting:logs.alert.document.count/logs/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", "alerting:.es-query/logs/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", "app:observability", "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -683,6 +808,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -711,121 +864,728 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", - "alerting:apm.error_rate/observability/alert/get", - "alerting:apm.error_rate/observability/alert/find", - "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.error_rate/observability/alert/getAlertSummary", - "alerting:apm.error_rate/observability/alert/update", - "alerting:apm.transaction_error_rate/observability/alert/get", - "alerting:apm.transaction_error_rate/observability/alert/find", - "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", - "alerting:apm.transaction_error_rate/observability/alert/update", - "alerting:apm.transaction_duration/observability/alert/get", - "alerting:apm.transaction_duration/observability/alert/find", - "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.transaction_duration/observability/alert/getAlertSummary", - "alerting:apm.transaction_duration/observability/alert/update", - "alerting:apm.anomaly/observability/alert/get", - "alerting:apm.anomaly/observability/alert/find", - "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.anomaly/observability/alert/getAlertSummary", - "alerting:apm.anomaly/observability/alert/update", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", - "alerting:xpack.synthetics.alerts.tls/observability/alert/get", - "alerting:xpack.synthetics.alerts.tls/observability/alert/find", - "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/observability/alert/update", - ], - "minimal_all": Array [ - "login:", - "api:apm", - "api:apm_write", - "api:rac", - "app:apm", - "app:ux", - "app:kibana", - "ui:catalogue/apm", - "ui:management/insightsAndAlerting/triggersActions", - "ui:navLinks/apm", - "ui:navLinks/ux", - "ui:navLinks/kibana", - "saved_object:telemetry/bulk_get", - "saved_object:telemetry/get", - "saved_object:telemetry/find", - "saved_object:telemetry/open_point_in_time", - "saved_object:telemetry/close_point_in_time", - "saved_object:telemetry/create", - "saved_object:telemetry/bulk_create", - "saved_object:telemetry/update", - "saved_object:telemetry/bulk_update", - "saved_object:telemetry/delete", - "saved_object:telemetry/bulk_delete", - "saved_object:telemetry/share_to_space", - "saved_object:apm-indices/bulk_get", - "saved_object:apm-indices/get", - "saved_object:apm-indices/find", - "saved_object:apm-indices/open_point_in_time", - "saved_object:apm-indices/close_point_in_time", - "saved_object:config/bulk_get", - "saved_object:config/get", - "saved_object:config/find", - "saved_object:config/open_point_in_time", - "saved_object:config/close_point_in_time", - "saved_object:config-global/bulk_get", - "saved_object:config-global/get", - "saved_object:config-global/find", - "saved_object:config-global/open_point_in_time", - "saved_object:config-global/close_point_in_time", - "saved_object:url/bulk_get", - "saved_object:url/get", - "saved_object:url/find", - "saved_object:url/open_point_in_time", - "saved_object:url/close_point_in_time", - "ui:apm/show", - "ui:apm/save", - "ui:apm/alerting:show", - "ui:apm/alerting:save", - "alerting:apm.error_rate/apm/rule/get", - "alerting:apm.error_rate/apm/rule/getRuleState", - "alerting:apm.error_rate/apm/rule/getAlertSummary", - "alerting:apm.error_rate/apm/rule/getExecutionLog", - "alerting:apm.error_rate/apm/rule/getActionErrorLog", - "alerting:apm.error_rate/apm/rule/find", - "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", - "alerting:apm.error_rate/apm/rule/getBackfill", - "alerting:apm.error_rate/apm/rule/findBackfill", - "alerting:apm.error_rate/apm/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.synthetics.alerts.tls/observability/alert/get", + "alerting:xpack.synthetics.alerts.tls/observability/alert/find", + "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + ], + "minimal_all": Array [ + "login:", + "api:apm", + "api:apm_write", + "api:rac", + "app:apm", + "app:ux", + "app:kibana", + "ui:catalogue/apm", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/apm", + "ui:navLinks/ux", + "ui:navLinks/kibana", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:apm-indices/bulk_get", + "saved_object:apm-indices/get", + "saved_object:apm-indices/find", + "saved_object:apm-indices/open_point_in_time", + "saved_object:apm-indices/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:apm/show", + "ui:apm/save", + "ui:apm/alerting:show", + "ui:apm/alerting:save", + "alerting:apm.error_rate/apm/rule/get", + "alerting:apm.error_rate/apm/rule/getRuleState", + "alerting:apm.error_rate/apm/rule/getAlertSummary", + "alerting:apm.error_rate/apm/rule/getExecutionLog", + "alerting:apm.error_rate/apm/rule/getActionErrorLog", + "alerting:apm.error_rate/apm/rule/find", + "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/apm/rule/getBackfill", + "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.error_rate/apm/rule/create", "alerting:apm.error_rate/apm/rule/delete", "alerting:apm.error_rate/apm/rule/update", "alerting:apm.error_rate/apm/rule/updateApiKey", @@ -844,6 +1604,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/apm/rule/runSoon", "alerting:apm.error_rate/apm/rule/scheduleBackfill", "alerting:apm.error_rate/apm/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/apm/rule/get", "alerting:apm.transaction_error_rate/apm/rule/getRuleState", "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", @@ -872,6 +1660,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/apm/rule/runSoon", "alerting:apm.transaction_error_rate/apm/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/apm/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/apm/rule/get", "alerting:apm.transaction_duration/apm/rule/getRuleState", "alerting:apm.transaction_duration/apm/rule/getAlertSummary", @@ -900,6 +1716,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/apm/rule/runSoon", "alerting:apm.transaction_duration/apm/rule/scheduleBackfill", "alerting:apm.transaction_duration/apm/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/apm/rule/get", "alerting:apm.anomaly/apm/rule/getRuleState", "alerting:apm.anomaly/apm/rule/getAlertSummary", @@ -928,26 +1772,74 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/apm/rule/runSoon", "alerting:apm.anomaly/apm/rule/scheduleBackfill", "alerting:apm.anomaly/apm/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:apm.error_rate/apm/alert/get", "alerting:apm.error_rate/apm/alert/find", "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/apm/alert/getAlertSummary", "alerting:apm.error_rate/apm/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/apm/alert/get", "alerting:apm.transaction_error_rate/apm/alert/find", "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", "alerting:apm.transaction_error_rate/apm/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/apm/alert/get", "alerting:apm.transaction_duration/apm/alert/find", "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/apm/alert/getAlertSummary", "alerting:apm.transaction_duration/apm/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/apm/alert/get", "alerting:apm.anomaly/apm/alert/find", "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/apm/alert/getAlertSummary", "alerting:apm.anomaly/apm/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "api:infra", "app:infra", "app:logs", @@ -1012,6 +1904,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/runSoon", "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -1040,6 +1960,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/runSoon", "alerting:.es-query/logs/rule/scheduleBackfill", "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -1068,6 +2016,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/runSoon", "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -1096,171 +2072,79 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", "alerting:logs.alert.document.count/logs/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", "alerting:.es-query/logs/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", "app:observability", "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -1401,6 +2285,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -1429,128 +2341,762 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", - "alerting:apm.error_rate/observability/alert/get", - "alerting:apm.error_rate/observability/alert/find", - "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.error_rate/observability/alert/getAlertSummary", - "alerting:apm.error_rate/observability/alert/update", - "alerting:apm.transaction_error_rate/observability/alert/get", - "alerting:apm.transaction_error_rate/observability/alert/find", - "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", - "alerting:apm.transaction_error_rate/observability/alert/update", - "alerting:apm.transaction_duration/observability/alert/get", - "alerting:apm.transaction_duration/observability/alert/find", - "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.transaction_duration/observability/alert/getAlertSummary", - "alerting:apm.transaction_duration/observability/alert/update", - "alerting:apm.anomaly/observability/alert/get", - "alerting:apm.anomaly/observability/alert/find", - "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.anomaly/observability/alert/getAlertSummary", - "alerting:apm.anomaly/observability/alert/update", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", - "alerting:xpack.synthetics.alerts.tls/observability/alert/get", - "alerting:xpack.synthetics.alerts.tls/observability/alert/find", - "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/observability/alert/update", - ], - "minimal_read": Array [ - "login:", - "api:apm", - "api:rac", - "app:apm", - "app:ux", - "app:kibana", - "ui:catalogue/apm", - "ui:management/insightsAndAlerting/triggersActions", - "ui:navLinks/apm", - "ui:navLinks/ux", - "ui:navLinks/kibana", - "saved_object:apm-indices/bulk_get", - "saved_object:apm-indices/get", - "saved_object:apm-indices/find", - "saved_object:apm-indices/open_point_in_time", - "saved_object:apm-indices/close_point_in_time", - "saved_object:config/bulk_get", - "saved_object:config/get", - "saved_object:config/find", - "saved_object:config/open_point_in_time", - "saved_object:config/close_point_in_time", - "saved_object:config-global/bulk_get", - "saved_object:config-global/get", - "saved_object:config-global/find", - "saved_object:config-global/open_point_in_time", - "saved_object:config-global/close_point_in_time", - "saved_object:telemetry/bulk_get", - "saved_object:telemetry/get", - "saved_object:telemetry/find", - "saved_object:telemetry/open_point_in_time", - "saved_object:telemetry/close_point_in_time", - "saved_object:url/bulk_get", - "saved_object:url/get", - "saved_object:url/find", - "saved_object:url/open_point_in_time", - "saved_object:url/close_point_in_time", - "ui:apm/show", - "ui:apm/alerting:show", - "alerting:apm.error_rate/apm/rule/get", - "alerting:apm.error_rate/apm/rule/getRuleState", - "alerting:apm.error_rate/apm/rule/getAlertSummary", - "alerting:apm.error_rate/apm/rule/getExecutionLog", - "alerting:apm.error_rate/apm/rule/getActionErrorLog", - "alerting:apm.error_rate/apm/rule/find", - "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", - "alerting:apm.error_rate/apm/rule/getBackfill", - "alerting:apm.error_rate/apm/rule/findBackfill", - "alerting:apm.transaction_error_rate/apm/rule/get", - "alerting:apm.transaction_error_rate/apm/rule/getRuleState", - "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", - "alerting:apm.transaction_error_rate/apm/rule/getExecutionLog", - "alerting:apm.transaction_error_rate/apm/rule/getActionErrorLog", - "alerting:apm.transaction_error_rate/apm/rule/find", - "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", - "alerting:apm.transaction_error_rate/apm/rule/getBackfill", - "alerting:apm.transaction_error_rate/apm/rule/findBackfill", - "alerting:apm.transaction_duration/apm/rule/get", - "alerting:apm.transaction_duration/apm/rule/getRuleState", - "alerting:apm.transaction_duration/apm/rule/getAlertSummary", - "alerting:apm.transaction_duration/apm/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.synthetics.alerts.tls/observability/alert/get", + "alerting:xpack.synthetics.alerts.tls/observability/alert/find", + "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + ], + "minimal_read": Array [ + "login:", + "api:apm", + "api:rac", + "app:apm", + "app:ux", + "app:kibana", + "ui:catalogue/apm", + "ui:management/insightsAndAlerting/triggersActions", + "ui:navLinks/apm", + "ui:navLinks/ux", + "ui:navLinks/kibana", + "saved_object:apm-indices/bulk_get", + "saved_object:apm-indices/get", + "saved_object:apm-indices/find", + "saved_object:apm-indices/open_point_in_time", + "saved_object:apm-indices/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:apm/show", + "ui:apm/alerting:show", + "alerting:apm.error_rate/apm/rule/get", + "alerting:apm.error_rate/apm/rule/getRuleState", + "alerting:apm.error_rate/apm/rule/getAlertSummary", + "alerting:apm.error_rate/apm/rule/getExecutionLog", + "alerting:apm.error_rate/apm/rule/getActionErrorLog", + "alerting:apm.error_rate/apm/rule/find", + "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/apm/rule/getBackfill", + "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/apm/rule/get", + "alerting:apm.transaction_error_rate/apm/rule/getRuleState", + "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/apm/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/apm/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/apm/rule/find", + "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/apm/rule/getBackfill", + "alerting:apm.transaction_error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/apm/rule/get", + "alerting:apm.transaction_duration/apm/rule/getRuleState", + "alerting:apm.transaction_duration/apm/rule/getAlertSummary", + "alerting:apm.transaction_duration/apm/rule/getExecutionLog", "alerting:apm.transaction_duration/apm/rule/getActionErrorLog", "alerting:apm.transaction_duration/apm/rule/find", "alerting:apm.transaction_duration/apm/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/apm/rule/getBackfill", "alerting:apm.transaction_duration/apm/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/apm/rule/get", "alerting:apm.anomaly/apm/rule/getRuleState", "alerting:apm.anomaly/apm/rule/getAlertSummary", @@ -1560,22 +3106,47 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/apm/rule/getRuleExecutionKPI", "alerting:apm.anomaly/apm/rule/getBackfill", "alerting:apm.anomaly/apm/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:apm.error_rate/apm/alert/get", "alerting:apm.error_rate/apm/alert/find", "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/apm/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/apm/alert/get", "alerting:apm.transaction_error_rate/apm/alert/find", "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/apm/alert/get", "alerting:apm.transaction_duration/apm/alert/find", "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/apm/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/apm/alert/get", "alerting:apm.anomaly/apm/alert/find", "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/apm/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "api:infra", "app:infra", "app:logs", @@ -1605,6 +3176,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", "alerting:logs.alert.document.count/logs/rule/getBackfill", "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -1614,6 +3194,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/getRuleExecutionKPI", "alerting:.es-query/logs/rule/getBackfill", "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -1623,6 +3212,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -1632,71 +3230,51 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", "app:observability", "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -1742,6 +3320,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -1751,26 +3338,177 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", @@ -1791,10 +3529,90 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", ], "read": Array [ "login:", @@ -1844,6 +3662,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/apm/rule/getRuleExecutionKPI", "alerting:apm.error_rate/apm/rule/getBackfill", "alerting:apm.error_rate/apm/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/apm/rule/get", "alerting:apm.transaction_error_rate/apm/rule/getRuleState", "alerting:apm.transaction_error_rate/apm/rule/getAlertSummary", @@ -1853,6 +3680,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/apm/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/apm/rule/getBackfill", "alerting:apm.transaction_error_rate/apm/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/apm/rule/get", "alerting:apm.transaction_duration/apm/rule/getRuleState", "alerting:apm.transaction_duration/apm/rule/getAlertSummary", @@ -1862,6 +3698,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/apm/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/apm/rule/getBackfill", "alerting:apm.transaction_duration/apm/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/apm/rule/get", "alerting:apm.anomaly/apm/rule/getRuleState", "alerting:apm.anomaly/apm/rule/getAlertSummary", @@ -1871,22 +3716,47 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/apm/rule/getRuleExecutionKPI", "alerting:apm.anomaly/apm/rule/getBackfill", "alerting:apm.anomaly/apm/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:apm.error_rate/apm/alert/get", "alerting:apm.error_rate/apm/alert/find", "alerting:apm.error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/apm/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/apm/alert/get", "alerting:apm.transaction_error_rate/apm/alert/find", "alerting:apm.transaction_error_rate/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/apm/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/apm/alert/get", "alerting:apm.transaction_duration/apm/alert/find", "alerting:apm.transaction_duration/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/apm/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/apm/alert/get", "alerting:apm.anomaly/apm/alert/find", "alerting:apm.anomaly/apm/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/apm/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "api:infra", "app:infra", "app:logs", @@ -1916,6 +3786,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", "alerting:logs.alert.document.count/logs/rule/getBackfill", "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -1925,6 +3804,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/getRuleExecutionKPI", "alerting:.es-query/logs/rule/getBackfill", "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -1934,6 +3822,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -1943,71 +3840,51 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -2053,6 +3930,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -2062,26 +3948,177 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", @@ -2102,10 +4139,90 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", ], "settings_save": Array [ "login:", @@ -2757,172 +4874,32 @@ export default function ({ getService }: FtrProviderContext) { "saved_object:search-session/bulk_delete", "saved_object:search-session/share_to_space", "saved_object:index-pattern/bulk_get", - "saved_object:index-pattern/get", - "saved_object:index-pattern/find", - "saved_object:index-pattern/open_point_in_time", - "saved_object:index-pattern/close_point_in_time", - "saved_object:config/bulk_get", - "saved_object:config/get", - "saved_object:config/find", - "saved_object:config/open_point_in_time", - "saved_object:config/close_point_in_time", - "saved_object:config-global/bulk_get", - "saved_object:config-global/get", - "saved_object:config-global/find", - "saved_object:config-global/open_point_in_time", - "saved_object:config-global/close_point_in_time", - "ui:discover/show", - "ui:discover/save", - "ui:discover/saveQuery", - "ui:discover/createShortUrl", - "ui:discover/storeSearchSession", - "ui:discover/generateCsv", - "api:rac", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "ui:discover/createShortUrl", + "ui:discover/storeSearchSession", + "ui:discover/generateCsv", + "api:rac", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -2951,6 +4928,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -2979,6 +4984,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -3007,6 +5040,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -3035,6 +5096,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -3063,6 +5152,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -3091,141 +5208,426 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", - "alerting:apm.error_rate/observability/alert/get", - "alerting:apm.error_rate/observability/alert/find", - "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.error_rate/observability/alert/getAlertSummary", - "alerting:apm.error_rate/observability/alert/update", - "alerting:apm.transaction_error_rate/observability/alert/get", - "alerting:apm.transaction_error_rate/observability/alert/find", - "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", - "alerting:apm.transaction_error_rate/observability/alert/update", - "alerting:apm.transaction_duration/observability/alert/get", - "alerting:apm.transaction_duration/observability/alert/find", - "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.transaction_duration/observability/alert/getAlertSummary", - "alerting:apm.transaction_duration/observability/alert/update", - "alerting:apm.anomaly/observability/alert/get", - "alerting:apm.anomaly/observability/alert/find", - "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", - "alerting:apm.anomaly/observability/alert/getAlertSummary", - "alerting:apm.anomaly/observability/alert/update", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", - "alerting:xpack.synthetics.alerts.tls/observability/alert/get", - "alerting:xpack.synthetics.alerts.tls/observability/alert/find", - "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/observability/alert/update", - ], - "generate_report": Array [ - "login:", - "api:generateReport", - "ui:management/insightsAndAlerting/reporting", - "ui:discover/generateCsv", - ], - "minimal_all": Array [ - "login:", - "api:fileUpload:analyzeFile", - "app:discover", - "app:kibana", - "ui:catalogue/discover", - "ui:navLinks/discover", - "ui:navLinks/kibana", - "saved_object:search/bulk_get", - "saved_object:search/get", - "saved_object:search/find", - "saved_object:search/open_point_in_time", - "saved_object:search/close_point_in_time", - "saved_object:search/create", - "saved_object:search/bulk_create", - "saved_object:search/update", - "saved_object:search/bulk_update", - "saved_object:search/delete", - "saved_object:search/bulk_delete", - "saved_object:search/share_to_space", - "saved_object:query/bulk_get", - "saved_object:query/get", - "saved_object:query/find", - "saved_object:query/open_point_in_time", - "saved_object:query/close_point_in_time", - "saved_object:query/create", - "saved_object:query/bulk_create", - "saved_object:query/update", - "saved_object:query/bulk_update", - "saved_object:query/delete", - "saved_object:query/bulk_delete", - "saved_object:query/share_to_space", - "saved_object:telemetry/bulk_get", - "saved_object:telemetry/get", - "saved_object:telemetry/find", - "saved_object:telemetry/open_point_in_time", - "saved_object:telemetry/close_point_in_time", - "saved_object:telemetry/create", - "saved_object:telemetry/bulk_create", - "saved_object:telemetry/update", - "saved_object:telemetry/bulk_update", - "saved_object:telemetry/delete", - "saved_object:telemetry/bulk_delete", - "saved_object:telemetry/share_to_space", - "saved_object:index-pattern/bulk_get", - "saved_object:index-pattern/get", - "saved_object:index-pattern/find", - "saved_object:index-pattern/open_point_in_time", - "saved_object:index-pattern/close_point_in_time", - "saved_object:config/bulk_get", - "saved_object:config/get", - "saved_object:config/find", - "saved_object:config/open_point_in_time", - "saved_object:config/close_point_in_time", - "saved_object:config-global/bulk_get", - "saved_object:config-global/get", - "saved_object:config-global/find", - "saved_object:config-global/open_point_in_time", - "saved_object:config-global/close_point_in_time", - "saved_object:url/bulk_get", - "saved_object:url/get", - "saved_object:url/find", - "saved_object:url/open_point_in_time", - "saved_object:url/close_point_in_time", - "ui:discover/show", - "ui:discover/save", - "ui:discover/saveQuery", - "api:rac", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "ui:observability/write", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:slo.rules.burnRate/observability/rule/get", "alerting:slo.rules.burnRate/observability/rule/getRuleState", "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", @@ -3254,6 +5656,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:slo.rules.burnRate/observability/rule/runSoon", "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/observability/rule/get", "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", @@ -3282,6 +5712,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/observability/rule/runSoon", "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:.es-query/observability/rule/get", "alerting:.es-query/observability/rule/getRuleState", "alerting:.es-query/observability/rule/getAlertSummary", @@ -3310,6 +5768,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/observability/rule/runSoon", "alerting:.es-query/observability/rule/scheduleBackfill", "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", @@ -3338,34 +5824,284 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", + "alerting:apm.error_rate/observability/alert/get", + "alerting:apm.error_rate/observability/alert/find", + "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", + "alerting:apm.transaction_error_rate/observability/alert/get", + "alerting:apm.transaction_error_rate/observability/alert/find", + "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", + "alerting:apm.transaction_duration/observability/alert/get", + "alerting:apm.transaction_duration/observability/alert/find", + "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", + "alerting:apm.anomaly/observability/alert/get", + "alerting:apm.anomaly/observability/alert/find", + "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.synthetics.alerts.tls/observability/alert/get", + "alerting:xpack.synthetics.alerts.tls/observability/alert/find", + "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", + ], + "generate_report": Array [ + "login:", + "api:generateReport", + "ui:management/insightsAndAlerting/reporting", + "ui:discover/generateCsv", + ], + "minimal_all": Array [ + "login:", + "api:fileUpload:analyzeFile", + "app:discover", + "app:kibana", + "ui:catalogue/discover", + "ui:navLinks/discover", + "ui:navLinks/kibana", + "saved_object:search/bulk_get", + "saved_object:search/get", + "saved_object:search/find", + "saved_object:search/open_point_in_time", + "saved_object:search/close_point_in_time", + "saved_object:search/create", + "saved_object:search/bulk_create", + "saved_object:search/update", + "saved_object:search/bulk_update", + "saved_object:search/delete", + "saved_object:search/bulk_delete", + "saved_object:search/share_to_space", + "saved_object:query/bulk_get", + "saved_object:query/get", + "saved_object:query/find", + "saved_object:query/open_point_in_time", + "saved_object:query/close_point_in_time", + "saved_object:query/create", + "saved_object:query/bulk_create", + "saved_object:query/update", + "saved_object:query/bulk_update", + "saved_object:query/delete", + "saved_object:query/bulk_delete", + "saved_object:query/share_to_space", + "saved_object:telemetry/bulk_get", + "saved_object:telemetry/get", + "saved_object:telemetry/find", + "saved_object:telemetry/open_point_in_time", + "saved_object:telemetry/close_point_in_time", + "saved_object:telemetry/create", + "saved_object:telemetry/bulk_create", + "saved_object:telemetry/update", + "saved_object:telemetry/bulk_update", + "saved_object:telemetry/delete", + "saved_object:telemetry/bulk_delete", + "saved_object:telemetry/share_to_space", + "saved_object:index-pattern/bulk_get", + "saved_object:index-pattern/get", + "saved_object:index-pattern/find", + "saved_object:index-pattern/open_point_in_time", + "saved_object:index-pattern/close_point_in_time", + "saved_object:config/bulk_get", + "saved_object:config/get", + "saved_object:config/find", + "saved_object:config/open_point_in_time", + "saved_object:config/close_point_in_time", + "saved_object:config-global/bulk_get", + "saved_object:config-global/get", + "saved_object:config-global/find", + "saved_object:config-global/open_point_in_time", + "saved_object:config-global/close_point_in_time", + "saved_object:url/bulk_get", + "saved_object:url/get", + "saved_object:url/find", + "saved_object:url/open_point_in_time", + "saved_object:url/close_point_in_time", + "ui:discover/show", + "ui:discover/save", + "ui:discover/saveQuery", + "api:rac", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -3394,6 +6130,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -3422,6 +6186,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -3450,6 +6242,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -3478,6 +6298,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -3506,6 +6354,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -3534,61 +6410,820 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", ], "minimal_read": Array [ "login:", @@ -3638,51 +7273,6 @@ export default function ({ getService }: FtrProviderContext) { "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -3692,6 +7282,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -3701,6 +7300,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -3710,6 +7318,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -3719,6 +7336,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -3728,6 +7354,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -3737,50 +7372,349 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], "read": Array [ "login:", @@ -3838,51 +7772,6 @@ export default function ({ getService }: FtrProviderContext) { "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -3892,6 +7781,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -3901,6 +7799,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -3910,6 +7817,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -3919,6 +7835,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -3928,6 +7853,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -3937,50 +7871,349 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], "store_search_session": Array [ "login:", @@ -4266,6 +8499,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/runSoon", "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -4294,6 +8555,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/runSoon", "alerting:.es-query/logs/rule/scheduleBackfill", "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -4322,6 +8611,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/runSoon", "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -4350,26 +8667,74 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", "alerting:logs.alert.document.count/logs/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", "alerting:.es-query/logs/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", ], "minimal_all": Array [ "login:", @@ -4619,6 +8984,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/runSoon", "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -4647,6 +9040,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/runSoon", "alerting:.es-query/logs/rule/scheduleBackfill", "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -4675,6 +9096,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/runSoon", "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -4703,26 +9152,74 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", "alerting:logs.alert.document.count/logs/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", "alerting:.es-query/logs/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", ], "minimal_read": Array [ "login:", @@ -4844,6 +9341,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", "alerting:logs.alert.document.count/logs/rule/getBackfill", "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -4853,6 +9359,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/getRuleExecutionKPI", "alerting:.es-query/logs/rule/getBackfill", "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -4862,6 +9377,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -4871,22 +9395,47 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], "read": Array [ "login:", @@ -5008,6 +9557,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", "alerting:logs.alert.document.count/logs/rule/getBackfill", "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -5017,6 +9575,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/getRuleExecutionKPI", "alerting:.es-query/logs/rule/getBackfill", "alerting:.es-query/logs/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", "alerting:observability.rules.custom_threshold/logs/rule/get", "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", @@ -5026,6 +9593,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", @@ -5035,22 +9611,47 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:logs.alert.document.count/logs/alert/get", "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/logs/alert/get", "alerting:observability.rules.custom_threshold/logs/alert/find", "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], }, "infrastructure": Object { @@ -5154,6 +9755,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.threshold/infrastructure/rule/runSoon", "alerting:metrics.alert.threshold/infrastructure/rule/scheduleBackfill", "alerting:metrics.alert.threshold/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", @@ -5182,6 +9811,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.inventory.threshold/infrastructure/rule/runSoon", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/scheduleBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", "alerting:.es-query/infrastructure/rule/get", "alerting:.es-query/infrastructure/rule/getRuleState", "alerting:.es-query/infrastructure/rule/getAlertSummary", @@ -5210,6 +9867,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/infrastructure/rule/runSoon", "alerting:.es-query/infrastructure/rule/scheduleBackfill", "alerting:.es-query/infrastructure/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/get", "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", @@ -5238,6 +9923,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/infrastructure/rule/runSoon", "alerting:observability.rules.custom_threshold/infrastructure/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", @@ -5266,31 +9979,84 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:metrics.alert.threshold/infrastructure/alert/get", "alerting:metrics.alert.threshold/infrastructure/alert/find", "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", "alerting:metrics.alert.threshold/infrastructure/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", "alerting:.es-query/infrastructure/alert/get", "alerting:.es-query/infrastructure/alert/find", "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:.es-query/infrastructure/alert/getAlertSummary", "alerting:.es-query/infrastructure/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", "alerting:observability.rules.custom_threshold/infrastructure/alert/get", "alerting:observability.rules.custom_threshold/infrastructure/alert/find", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/infrastructure/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", "app:logs", "app:observability-logs-explorer", "ui:catalogue/infralogging", @@ -5340,6 +10106,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/runSoon", "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -5367,228 +10161,93 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/unsnooze", "alerting:.es-query/logs/rule/runSoon", "alerting:.es-query/logs/rule/scheduleBackfill", - "alerting:.es-query/logs/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/get", - "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", - "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/logs/rule/find", - "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/create", - "alerting:observability.rules.custom_threshold/logs/rule/delete", - "alerting:observability.rules.custom_threshold/logs/rule/update", - "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/logs/rule/enable", - "alerting:observability.rules.custom_threshold/logs/rule/disable", - "alerting:observability.rules.custom_threshold/logs/rule/muteAll", - "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", - "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/logs/rule/snooze", - "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", - "alerting:observability.rules.custom_threshold/logs/rule/runSoon", - "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", - "alerting:logs.alert.document.count/logs/alert/get", - "alerting:logs.alert.document.count/logs/alert/find", - "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", - "alerting:logs.alert.document.count/logs/alert/getAlertSummary", - "alerting:logs.alert.document.count/logs/alert/update", - "alerting:.es-query/logs/alert/get", - "alerting:.es-query/logs/alert/find", - "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/logs/alert/getAlertSummary", - "alerting:.es-query/logs/alert/update", - "alerting:observability.rules.custom_threshold/logs/alert/get", - "alerting:observability.rules.custom_threshold/logs/alert/find", - "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/logs/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -5617,6 +10276,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -5645,6 +10332,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -5673,6 +10388,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -5701,6 +10444,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -5729,6 +10500,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -5757,61 +10556,622 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", ], "minimal_all": Array [ "login:", @@ -5913,6 +11273,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.threshold/infrastructure/rule/runSoon", "alerting:metrics.alert.threshold/infrastructure/rule/scheduleBackfill", "alerting:metrics.alert.threshold/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", @@ -5941,6 +11329,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.inventory.threshold/infrastructure/rule/runSoon", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/scheduleBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", "alerting:.es-query/infrastructure/rule/get", "alerting:.es-query/infrastructure/rule/getRuleState", "alerting:.es-query/infrastructure/rule/getAlertSummary", @@ -5969,6 +11385,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/infrastructure/rule/runSoon", "alerting:.es-query/infrastructure/rule/scheduleBackfill", "alerting:.es-query/infrastructure/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/get", "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", @@ -5997,6 +11441,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/infrastructure/rule/runSoon", "alerting:observability.rules.custom_threshold/infrastructure/rule/scheduleBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", @@ -6025,31 +11497,84 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/runSoon", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/scheduleBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:metrics.alert.threshold/infrastructure/alert/get", "alerting:metrics.alert.threshold/infrastructure/alert/find", "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", "alerting:metrics.alert.threshold/infrastructure/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", "alerting:.es-query/infrastructure/alert/get", "alerting:.es-query/infrastructure/alert/find", "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:.es-query/infrastructure/alert/getAlertSummary", "alerting:.es-query/infrastructure/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", "alerting:observability.rules.custom_threshold/infrastructure/alert/get", "alerting:observability.rules.custom_threshold/infrastructure/alert/find", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/infrastructure/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", "app:logs", "app:observability-logs-explorer", "ui:catalogue/infralogging", @@ -6099,6 +11624,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/runSoon", "alerting:logs.alert.document.count/logs/rule/scheduleBackfill", "alerting:logs.alert.document.count/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -6108,246 +11661,111 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/logs/rule/getRuleExecutionKPI", "alerting:.es-query/logs/rule/getBackfill", "alerting:.es-query/logs/rule/findBackfill", - "alerting:.es-query/logs/rule/create", - "alerting:.es-query/logs/rule/delete", - "alerting:.es-query/logs/rule/update", - "alerting:.es-query/logs/rule/updateApiKey", - "alerting:.es-query/logs/rule/enable", - "alerting:.es-query/logs/rule/disable", - "alerting:.es-query/logs/rule/muteAll", - "alerting:.es-query/logs/rule/unmuteAll", - "alerting:.es-query/logs/rule/muteAlert", - "alerting:.es-query/logs/rule/unmuteAlert", - "alerting:.es-query/logs/rule/snooze", - "alerting:.es-query/logs/rule/bulkEdit", - "alerting:.es-query/logs/rule/bulkDelete", - "alerting:.es-query/logs/rule/bulkEnable", - "alerting:.es-query/logs/rule/bulkDisable", - "alerting:.es-query/logs/rule/unsnooze", - "alerting:.es-query/logs/rule/runSoon", - "alerting:.es-query/logs/rule/scheduleBackfill", - "alerting:.es-query/logs/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/get", - "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", - "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/logs/rule/find", - "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/create", - "alerting:observability.rules.custom_threshold/logs/rule/delete", - "alerting:observability.rules.custom_threshold/logs/rule/update", - "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/logs/rule/enable", - "alerting:observability.rules.custom_threshold/logs/rule/disable", - "alerting:observability.rules.custom_threshold/logs/rule/muteAll", - "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", - "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/logs/rule/snooze", - "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", - "alerting:observability.rules.custom_threshold/logs/rule/runSoon", - "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", - "alerting:logs.alert.document.count/logs/alert/get", - "alerting:logs.alert.document.count/logs/alert/find", - "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", - "alerting:logs.alert.document.count/logs/alert/getAlertSummary", - "alerting:logs.alert.document.count/logs/alert/update", - "alerting:.es-query/logs/alert/get", - "alerting:.es-query/logs/alert/find", - "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/logs/alert/getAlertSummary", - "alerting:.es-query/logs/alert/update", - "alerting:observability.rules.custom_threshold/logs/alert/get", - "alerting:observability.rules.custom_threshold/logs/alert/find", - "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/logs/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:.es-query/logs/rule/create", + "alerting:.es-query/logs/rule/delete", + "alerting:.es-query/logs/rule/update", + "alerting:.es-query/logs/rule/updateApiKey", + "alerting:.es-query/logs/rule/enable", + "alerting:.es-query/logs/rule/disable", + "alerting:.es-query/logs/rule/muteAll", + "alerting:.es-query/logs/rule/unmuteAll", + "alerting:.es-query/logs/rule/muteAlert", + "alerting:.es-query/logs/rule/unmuteAlert", + "alerting:.es-query/logs/rule/snooze", + "alerting:.es-query/logs/rule/bulkEdit", + "alerting:.es-query/logs/rule/bulkDelete", + "alerting:.es-query/logs/rule/bulkEnable", + "alerting:.es-query/logs/rule/bulkDisable", + "alerting:.es-query/logs/rule/unsnooze", + "alerting:.es-query/logs/rule/runSoon", + "alerting:.es-query/logs/rule/scheduleBackfill", + "alerting:.es-query/logs/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/get", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleState", + "alerting:observability.rules.custom_threshold/logs/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/logs/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/logs/rule/find", + "alerting:observability.rules.custom_threshold/logs/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/logs/rule/getBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/findBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/create", + "alerting:observability.rules.custom_threshold/logs/rule/delete", + "alerting:observability.rules.custom_threshold/logs/rule/update", + "alerting:observability.rules.custom_threshold/logs/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/logs/rule/enable", + "alerting:observability.rules.custom_threshold/logs/rule/disable", + "alerting:observability.rules.custom_threshold/logs/rule/muteAll", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/logs/rule/muteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/logs/rule/snooze", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/logs/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/logs/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/logs/rule/unsnooze", + "alerting:observability.rules.custom_threshold/logs/rule/runSoon", + "alerting:observability.rules.custom_threshold/logs/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/logs/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/logs/rule/deleteBackfill", + "alerting:logs.alert.document.count/logs/alert/get", + "alerting:logs.alert.document.count/logs/alert/find", + "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/logs/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:.es-query/logs/alert/get", + "alerting:.es-query/logs/alert/find", + "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/logs/alert/getAlertSummary", + "alerting:.es-query/logs/alert/update", + "alerting:observability.rules.custom_threshold/logs/alert/get", + "alerting:observability.rules.custom_threshold/logs/alert/find", + "alerting:observability.rules.custom_threshold/logs/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/logs/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/logs/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/logs/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -6376,6 +11794,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -6404,6 +11850,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -6432,6 +11906,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -6460,6 +11962,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -6488,6 +12018,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -6516,61 +12074,622 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", ], "minimal_read": Array [ "login:", @@ -6630,6 +12749,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.threshold/infrastructure/rule/getRuleExecutionKPI", "alerting:metrics.alert.threshold/infrastructure/rule/getBackfill", "alerting:metrics.alert.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", @@ -6639,6 +12767,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleExecutionKPI", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", "alerting:.es-query/infrastructure/rule/get", "alerting:.es-query/infrastructure/rule/getRuleState", "alerting:.es-query/infrastructure/rule/getAlertSummary", @@ -6648,6 +12785,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/infrastructure/rule/getRuleExecutionKPI", "alerting:.es-query/infrastructure/rule/getBackfill", "alerting:.es-query/infrastructure/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/get", "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", @@ -6657,6 +12803,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleExecutionKPI", "alerting:observability.rules.custom_threshold/infrastructure/rule/getBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", @@ -6666,26 +12821,55 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleExecutionKPI", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:metrics.alert.threshold/infrastructure/alert/get", "alerting:metrics.alert.threshold/infrastructure/alert/find", "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", "alerting:.es-query/infrastructure/alert/get", "alerting:.es-query/infrastructure/alert/find", "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:.es-query/infrastructure/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/infrastructure/alert/get", "alerting:observability.rules.custom_threshold/infrastructure/alert/find", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", "app:logs", "app:observability-logs-explorer", "ui:catalogue/infralogging", @@ -6707,6 +12891,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", "alerting:logs.alert.document.count/logs/rule/getBackfill", "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -6738,6 +12931,10 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", @@ -6754,51 +12951,6 @@ export default function ({ getService }: FtrProviderContext) { "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -6808,6 +12960,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -6817,6 +12978,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -6826,6 +12996,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -6835,6 +13014,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -6844,6 +13032,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -6853,50 +13050,271 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", ], "read": Array [ "login:", @@ -6956,6 +13374,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.threshold/infrastructure/rule/getRuleExecutionKPI", "alerting:metrics.alert.threshold/infrastructure/rule/getBackfill", "alerting:metrics.alert.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/get", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleState", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getAlertSummary", @@ -6965,6 +13392,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getRuleExecutionKPI", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/getBackfill", "alerting:metrics.alert.inventory.threshold/infrastructure/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", "alerting:.es-query/infrastructure/rule/get", "alerting:.es-query/infrastructure/rule/getRuleState", "alerting:.es-query/infrastructure/rule/getAlertSummary", @@ -6974,6 +13410,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:.es-query/infrastructure/rule/getRuleExecutionKPI", "alerting:.es-query/infrastructure/rule/getBackfill", "alerting:.es-query/infrastructure/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/get", "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleState", "alerting:observability.rules.custom_threshold/infrastructure/rule/getAlertSummary", @@ -6983,6 +13428,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:observability.rules.custom_threshold/infrastructure/rule/getRuleExecutionKPI", "alerting:observability.rules.custom_threshold/infrastructure/rule/getBackfill", "alerting:observability.rules.custom_threshold/infrastructure/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleState", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getAlertSummary", @@ -6992,26 +13446,55 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getRuleExecutionKPI", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/getBackfill", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:metrics.alert.threshold/infrastructure/alert/get", "alerting:metrics.alert.threshold/infrastructure/alert/find", "alerting:metrics.alert.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/get", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/find", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:metrics.alert.inventory.threshold/infrastructure/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", "alerting:.es-query/infrastructure/alert/get", "alerting:.es-query/infrastructure/alert/find", "alerting:.es-query/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:.es-query/infrastructure/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", "alerting:observability.rules.custom_threshold/infrastructure/alert/get", "alerting:observability.rules.custom_threshold/infrastructure/alert/find", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:observability.rules.custom_threshold/infrastructure/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/get", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/find", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAuthorizedAlertsIndices", "alerting:xpack.ml.anomaly_detection_alert/infrastructure/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", "app:logs", "app:observability-logs-explorer", "ui:catalogue/infralogging", @@ -7033,6 +13516,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/rule/getRuleExecutionKPI", "alerting:logs.alert.document.count/logs/rule/getBackfill", "alerting:logs.alert.document.count/logs/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", "alerting:.es-query/logs/rule/get", "alerting:.es-query/logs/rule/getRuleState", "alerting:.es-query/logs/rule/getAlertSummary", @@ -7064,6 +13556,10 @@ export default function ({ getService }: FtrProviderContext) { "alerting:logs.alert.document.count/logs/alert/find", "alerting:logs.alert.document.count/logs/alert/getAuthorizedAlertsIndices", "alerting:logs.alert.document.count/logs/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", "alerting:.es-query/logs/alert/get", "alerting:.es-query/logs/alert/find", "alerting:.es-query/logs/alert/getAuthorizedAlertsIndices", @@ -7080,51 +13576,6 @@ export default function ({ getService }: FtrProviderContext) { "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -7134,6 +13585,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -7143,6 +13603,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -7152,6 +13621,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -7161,6 +13639,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -7170,6 +13657,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -7179,50 +13675,271 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", ], }, "reporting": Object { @@ -7436,155 +14153,48 @@ export default function ({ getService }: FtrProviderContext) { "alerting:slo.rules.burnRate/slo/rule/runSoon", "alerting:slo.rules.burnRate/slo/rule/scheduleBackfill", "alerting:slo.rules.burnRate/slo/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", "alerting:slo.rules.burnRate/slo/alert/get", "alerting:slo.rules.burnRate/slo/alert/find", "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", "alerting:slo.rules.burnRate/slo/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", "app:observability", "ui:navLinks/observability", "ui:observability/read", "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -7613,6 +14223,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -7641,6 +14279,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -7669,6 +14335,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -7697,6 +14391,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -7725,6 +14447,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -7753,61 +14503,787 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", ], "minimal_all": Array [ "login:", @@ -7901,155 +15377,48 @@ export default function ({ getService }: FtrProviderContext) { "alerting:slo.rules.burnRate/slo/rule/runSoon", "alerting:slo.rules.burnRate/slo/rule/scheduleBackfill", "alerting:slo.rules.burnRate/slo/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", "alerting:slo.rules.burnRate/slo/alert/get", "alerting:slo.rules.burnRate/slo/alert/find", "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", "alerting:slo.rules.burnRate/slo/alert/update", - "app:observability", - "ui:navLinks/observability", - "ui:observability/read", - "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "app:observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -8078,6 +15447,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -8106,6 +15503,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -8134,6 +15559,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -8162,6 +15615,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -8190,6 +15671,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -8218,61 +15727,787 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", ], "minimal_read": Array [ "login:", @@ -8314,68 +16549,36 @@ export default function ({ getService }: FtrProviderContext) { "saved_object:url/find", "saved_object:url/open_point_in_time", "saved_object:url/close_point_in_time", - "ui:slo/read", - "alerting:slo.rules.burnRate/slo/rule/get", - "alerting:slo.rules.burnRate/slo/rule/getRuleState", - "alerting:slo.rules.burnRate/slo/rule/getAlertSummary", - "alerting:slo.rules.burnRate/slo/rule/getExecutionLog", - "alerting:slo.rules.burnRate/slo/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/slo/rule/find", - "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/slo/rule/getBackfill", - "alerting:slo.rules.burnRate/slo/rule/findBackfill", - "alerting:slo.rules.burnRate/slo/alert/get", - "alerting:slo.rules.burnRate/slo/alert/find", - "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", - "app:observability", - "ui:navLinks/observability", - "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "ui:slo/read", + "alerting:slo.rules.burnRate/slo/rule/get", + "alerting:slo.rules.burnRate/slo/rule/getRuleState", + "alerting:slo.rules.burnRate/slo/rule/getAlertSummary", + "alerting:slo.rules.burnRate/slo/rule/getExecutionLog", + "alerting:slo.rules.burnRate/slo/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/slo/rule/find", + "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/slo/rule/getBackfill", + "alerting:slo.rules.burnRate/slo/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/slo/alert/get", + "alerting:slo.rules.burnRate/slo/alert/find", + "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "app:observability", + "ui:navLinks/observability", + "ui:observability/read", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -8385,6 +16588,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -8394,6 +16606,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -8403,6 +16624,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -8412,6 +16642,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -8421,6 +16660,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -8430,50 +16678,336 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], "read": Array [ "login:", @@ -8525,58 +17059,26 @@ export default function ({ getService }: FtrProviderContext) { "alerting:slo.rules.burnRate/slo/rule/getRuleExecutionKPI", "alerting:slo.rules.burnRate/slo/rule/getBackfill", "alerting:slo.rules.burnRate/slo/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", "alerting:slo.rules.burnRate/slo/alert/get", "alerting:slo.rules.burnRate/slo/alert/find", "alerting:slo.rules.burnRate/slo/alert/getAuthorizedAlertsIndices", "alerting:slo.rules.burnRate/slo/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", "app:observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -8586,6 +17088,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -8595,6 +17106,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -8604,6 +17124,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -8613,6 +17142,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -8622,6 +17160,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/get", "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/observability/rule/getAlertSummary", @@ -8631,50 +17178,336 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/get", "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], }, "uptime": Object { @@ -8684,6 +17517,7 @@ export default function ({ getService }: FtrProviderContext) { "api:uptime-write", "api:lists-all", "api:rac", + "api:private-location-write", "app:uptime", "app:kibana", "app:synthetics", @@ -8728,30 +17562,6 @@ export default function ({ getService }: FtrProviderContext) { "saved_object:uptime-synthetics-api-key/delete", "saved_object:uptime-synthetics-api-key/bulk_delete", "saved_object:uptime-synthetics-api-key/share_to_space", - "saved_object:synthetics-private-location/bulk_get", - "saved_object:synthetics-private-location/get", - "saved_object:synthetics-private-location/find", - "saved_object:synthetics-private-location/open_point_in_time", - "saved_object:synthetics-private-location/close_point_in_time", - "saved_object:synthetics-private-location/create", - "saved_object:synthetics-private-location/bulk_create", - "saved_object:synthetics-private-location/update", - "saved_object:synthetics-private-location/bulk_update", - "saved_object:synthetics-private-location/delete", - "saved_object:synthetics-private-location/bulk_delete", - "saved_object:synthetics-private-location/share_to_space", - "saved_object:synthetics-privates-locations/bulk_get", - "saved_object:synthetics-privates-locations/get", - "saved_object:synthetics-privates-locations/find", - "saved_object:synthetics-privates-locations/open_point_in_time", - "saved_object:synthetics-privates-locations/close_point_in_time", - "saved_object:synthetics-privates-locations/create", - "saved_object:synthetics-privates-locations/bulk_create", - "saved_object:synthetics-privates-locations/update", - "saved_object:synthetics-privates-locations/bulk_update", - "saved_object:synthetics-privates-locations/delete", - "saved_object:synthetics-privates-locations/bulk_delete", - "saved_object:synthetics-privates-locations/share_to_space", "saved_object:synthetics-param/bulk_get", "saved_object:synthetics-param/get", "saved_object:synthetics-param/find", @@ -8788,6 +17598,30 @@ export default function ({ getService }: FtrProviderContext) { "saved_object:telemetry/delete", "saved_object:telemetry/bulk_delete", "saved_object:telemetry/share_to_space", + "saved_object:synthetics-private-location/bulk_get", + "saved_object:synthetics-private-location/get", + "saved_object:synthetics-private-location/find", + "saved_object:synthetics-private-location/open_point_in_time", + "saved_object:synthetics-private-location/close_point_in_time", + "saved_object:synthetics-private-location/create", + "saved_object:synthetics-private-location/bulk_create", + "saved_object:synthetics-private-location/update", + "saved_object:synthetics-private-location/bulk_update", + "saved_object:synthetics-private-location/delete", + "saved_object:synthetics-private-location/bulk_delete", + "saved_object:synthetics-private-location/share_to_space", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", + "saved_object:synthetics-privates-locations/create", + "saved_object:synthetics-privates-locations/bulk_create", + "saved_object:synthetics-privates-locations/update", + "saved_object:synthetics-privates-locations/bulk_update", + "saved_object:synthetics-privates-locations/delete", + "saved_object:synthetics-privates-locations/bulk_delete", + "saved_object:synthetics-privates-locations/share_to_space", "saved_object:config/bulk_get", "saved_object:config/get", "saved_object:config/find", @@ -8808,6 +17642,7 @@ export default function ({ getService }: FtrProviderContext) { "ui:uptime/show", "ui:uptime/alerting:save", "ui:uptime/elasticManagedLocationsEnabled", + "ui:uptime/canManagePrivateLocations", "alerting:xpack.uptime.alerts.tls/uptime/rule/get", "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.tls/uptime/rule/getAlertSummary", @@ -8836,6 +17671,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tls/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.tls/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", @@ -8864,6 +17727,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", @@ -8892,6 +17783,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", @@ -8919,238 +17838,212 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/unsnooze", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/scheduleBackfill", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/deleteBackfill", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/create", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/delete", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/update", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/updateApiKey", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/enable", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/disable", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAll", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAll", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAlert", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAlert", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/snooze", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEdit", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDelete", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEnable", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDisable", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unsnooze", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/runSoon", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/scheduleBackfill", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/deleteBackfill", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/create", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/delete", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/update", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/updateApiKey", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/enable", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/disable", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAll", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAll", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAlert", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAlert", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/snooze", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEdit", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDelete", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEnable", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDisable", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/unsnooze", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/runSoon", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/scheduleBackfill", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/deleteBackfill", - "alerting:xpack.uptime.alerts.tls/uptime/alert/get", - "alerting:xpack.uptime.alerts.tls/uptime/alert/find", - "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.tls/uptime/alert/update", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/update", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/update", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/update", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/update", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/update", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/create", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/delete", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/update", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/enable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/disable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/alert/get", + "alerting:xpack.uptime.alerts.tls/uptime/alert/find", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/uptime/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", + "ui:observability/write", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -9179,6 +18072,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -9207,6 +18128,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -9235,6 +18184,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -9263,6 +18240,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -9319,51 +18324,550 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", @@ -9374,6 +18878,125 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", + ], + "can_manage_private_locations": Array [ + "login:", + "api:private-location-write", + "saved_object:synthetics-private-location/bulk_get", + "saved_object:synthetics-private-location/get", + "saved_object:synthetics-private-location/find", + "saved_object:synthetics-private-location/open_point_in_time", + "saved_object:synthetics-private-location/close_point_in_time", + "saved_object:synthetics-private-location/create", + "saved_object:synthetics-private-location/bulk_create", + "saved_object:synthetics-private-location/update", + "saved_object:synthetics-private-location/bulk_update", + "saved_object:synthetics-private-location/delete", + "saved_object:synthetics-private-location/bulk_delete", + "saved_object:synthetics-private-location/share_to_space", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", + "saved_object:synthetics-privates-locations/create", + "saved_object:synthetics-privates-locations/bulk_create", + "saved_object:synthetics-privates-locations/update", + "saved_object:synthetics-privates-locations/bulk_update", + "saved_object:synthetics-privates-locations/delete", + "saved_object:synthetics-privates-locations/bulk_delete", + "saved_object:synthetics-privates-locations/share_to_space", + "ui:uptime/canManagePrivateLocations", ], "elastic_managed_locations_enabled": Array [ "login:", @@ -9429,30 +19052,6 @@ export default function ({ getService }: FtrProviderContext) { "saved_object:uptime-synthetics-api-key/delete", "saved_object:uptime-synthetics-api-key/bulk_delete", "saved_object:uptime-synthetics-api-key/share_to_space", - "saved_object:synthetics-private-location/bulk_get", - "saved_object:synthetics-private-location/get", - "saved_object:synthetics-private-location/find", - "saved_object:synthetics-private-location/open_point_in_time", - "saved_object:synthetics-private-location/close_point_in_time", - "saved_object:synthetics-private-location/create", - "saved_object:synthetics-private-location/bulk_create", - "saved_object:synthetics-private-location/update", - "saved_object:synthetics-private-location/bulk_update", - "saved_object:synthetics-private-location/delete", - "saved_object:synthetics-private-location/bulk_delete", - "saved_object:synthetics-private-location/share_to_space", - "saved_object:synthetics-privates-locations/bulk_get", - "saved_object:synthetics-privates-locations/get", - "saved_object:synthetics-privates-locations/find", - "saved_object:synthetics-privates-locations/open_point_in_time", - "saved_object:synthetics-privates-locations/close_point_in_time", - "saved_object:synthetics-privates-locations/create", - "saved_object:synthetics-privates-locations/bulk_create", - "saved_object:synthetics-privates-locations/update", - "saved_object:synthetics-privates-locations/bulk_update", - "saved_object:synthetics-privates-locations/delete", - "saved_object:synthetics-privates-locations/bulk_delete", - "saved_object:synthetics-privates-locations/share_to_space", "saved_object:synthetics-param/bulk_get", "saved_object:synthetics-param/get", "saved_object:synthetics-param/find", @@ -9489,6 +19088,16 @@ export default function ({ getService }: FtrProviderContext) { "saved_object:telemetry/delete", "saved_object:telemetry/bulk_delete", "saved_object:telemetry/share_to_space", + "saved_object:synthetics-private-location/bulk_get", + "saved_object:synthetics-private-location/get", + "saved_object:synthetics-private-location/find", + "saved_object:synthetics-private-location/open_point_in_time", + "saved_object:synthetics-private-location/close_point_in_time", + "saved_object:synthetics-privates-locations/bulk_get", + "saved_object:synthetics-privates-locations/get", + "saved_object:synthetics-privates-locations/find", + "saved_object:synthetics-privates-locations/open_point_in_time", + "saved_object:synthetics-privates-locations/close_point_in_time", "saved_object:config/bulk_get", "saved_object:config/get", "saved_object:config/find", @@ -9536,6 +19145,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tls/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.tls/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/create", + "alerting:xpack.uptime.alerts.tls/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/update", + "alerting:xpack.uptime.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", @@ -9564,6 +19201,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", @@ -9592,6 +19257,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", @@ -9620,6 +19313,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/runSoon", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/scheduleBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", @@ -9648,6 +19369,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/runSoon", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/create", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", @@ -9676,181 +19425,99 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/uptime/rule/runSoon", "alerting:xpack.synthetics.alerts.tls/uptime/rule/scheduleBackfill", "alerting:xpack.synthetics.alerts.tls/uptime/rule/deleteBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/create", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/delete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/update", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/updateApiKey", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/enable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/disable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAll", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/muteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unmuteAlert", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/snooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEdit", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDelete", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkEnable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/deleteBackfill", "alerting:xpack.uptime.alerts.tls/uptime/alert/get", "alerting:xpack.uptime.alerts.tls/uptime/alert/find", "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", "alerting:xpack.uptime.alerts.tls/uptime/alert/update", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/update", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/update", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/update", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/update", "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/uptime/alert/update", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/update", "app:observability", "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", "ui:observability/write", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/rule/create", - "alerting:slo.rules.burnRate/observability/rule/delete", - "alerting:slo.rules.burnRate/observability/rule/update", - "alerting:slo.rules.burnRate/observability/rule/updateApiKey", - "alerting:slo.rules.burnRate/observability/rule/enable", - "alerting:slo.rules.burnRate/observability/rule/disable", - "alerting:slo.rules.burnRate/observability/rule/muteAll", - "alerting:slo.rules.burnRate/observability/rule/unmuteAll", - "alerting:slo.rules.burnRate/observability/rule/muteAlert", - "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", - "alerting:slo.rules.burnRate/observability/rule/snooze", - "alerting:slo.rules.burnRate/observability/rule/bulkEdit", - "alerting:slo.rules.burnRate/observability/rule/bulkDelete", - "alerting:slo.rules.burnRate/observability/rule/bulkEnable", - "alerting:slo.rules.burnRate/observability/rule/bulkDisable", - "alerting:slo.rules.burnRate/observability/rule/unsnooze", - "alerting:slo.rules.burnRate/observability/rule/runSoon", - "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", - "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/create", - "alerting:observability.rules.custom_threshold/observability/rule/delete", - "alerting:observability.rules.custom_threshold/observability/rule/update", - "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", - "alerting:observability.rules.custom_threshold/observability/rule/enable", - "alerting:observability.rules.custom_threshold/observability/rule/disable", - "alerting:observability.rules.custom_threshold/observability/rule/muteAll", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", - "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", - "alerting:observability.rules.custom_threshold/observability/rule/snooze", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", - "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", - "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", - "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", - "alerting:observability.rules.custom_threshold/observability/rule/runSoon", - "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/create", - "alerting:.es-query/observability/rule/delete", - "alerting:.es-query/observability/rule/update", - "alerting:.es-query/observability/rule/updateApiKey", - "alerting:.es-query/observability/rule/enable", - "alerting:.es-query/observability/rule/disable", - "alerting:.es-query/observability/rule/muteAll", - "alerting:.es-query/observability/rule/unmuteAll", - "alerting:.es-query/observability/rule/muteAlert", - "alerting:.es-query/observability/rule/unmuteAlert", - "alerting:.es-query/observability/rule/snooze", - "alerting:.es-query/observability/rule/bulkEdit", - "alerting:.es-query/observability/rule/bulkDelete", - "alerting:.es-query/observability/rule/bulkEnable", - "alerting:.es-query/observability/rule/bulkDisable", - "alerting:.es-query/observability/rule/unsnooze", - "alerting:.es-query/observability/rule/runSoon", - "alerting:.es-query/observability/rule/scheduleBackfill", - "alerting:.es-query/observability/rule/deleteBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/create", - "alerting:metrics.alert.inventory.threshold/observability/rule/delete", - "alerting:metrics.alert.inventory.threshold/observability/rule/update", - "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", - "alerting:metrics.alert.inventory.threshold/observability/rule/enable", - "alerting:metrics.alert.inventory.threshold/observability/rule/disable", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", - "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", - "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", - "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", - "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", - "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", - "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -9879,6 +19546,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/runSoon", "alerting:apm.error_rate/observability/rule/scheduleBackfill", "alerting:apm.error_rate/observability/rule/deleteBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/create", + "alerting:apm.error_rate/alerts/rule/delete", + "alerting:apm.error_rate/alerts/rule/update", + "alerting:apm.error_rate/alerts/rule/updateApiKey", + "alerting:apm.error_rate/alerts/rule/enable", + "alerting:apm.error_rate/alerts/rule/disable", + "alerting:apm.error_rate/alerts/rule/muteAll", + "alerting:apm.error_rate/alerts/rule/unmuteAll", + "alerting:apm.error_rate/alerts/rule/muteAlert", + "alerting:apm.error_rate/alerts/rule/unmuteAlert", + "alerting:apm.error_rate/alerts/rule/snooze", + "alerting:apm.error_rate/alerts/rule/bulkEdit", + "alerting:apm.error_rate/alerts/rule/bulkDelete", + "alerting:apm.error_rate/alerts/rule/bulkEnable", + "alerting:apm.error_rate/alerts/rule/bulkDisable", + "alerting:apm.error_rate/alerts/rule/unsnooze", + "alerting:apm.error_rate/alerts/rule/runSoon", + "alerting:apm.error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -9907,6 +19602,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/runSoon", "alerting:apm.transaction_error_rate/observability/rule/scheduleBackfill", "alerting:apm.transaction_error_rate/observability/rule/deleteBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/create", + "alerting:apm.transaction_error_rate/alerts/rule/delete", + "alerting:apm.transaction_error_rate/alerts/rule/update", + "alerting:apm.transaction_error_rate/alerts/rule/updateApiKey", + "alerting:apm.transaction_error_rate/alerts/rule/enable", + "alerting:apm.transaction_error_rate/alerts/rule/disable", + "alerting:apm.transaction_error_rate/alerts/rule/muteAll", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAll", + "alerting:apm.transaction_error_rate/alerts/rule/muteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/unmuteAlert", + "alerting:apm.transaction_error_rate/alerts/rule/snooze", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEdit", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDelete", + "alerting:apm.transaction_error_rate/alerts/rule/bulkEnable", + "alerting:apm.transaction_error_rate/alerts/rule/bulkDisable", + "alerting:apm.transaction_error_rate/alerts/rule/unsnooze", + "alerting:apm.transaction_error_rate/alerts/rule/runSoon", + "alerting:apm.transaction_error_rate/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/deleteBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -9935,6 +19658,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/runSoon", "alerting:apm.transaction_duration/observability/rule/scheduleBackfill", "alerting:apm.transaction_duration/observability/rule/deleteBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/create", + "alerting:apm.transaction_duration/alerts/rule/delete", + "alerting:apm.transaction_duration/alerts/rule/update", + "alerting:apm.transaction_duration/alerts/rule/updateApiKey", + "alerting:apm.transaction_duration/alerts/rule/enable", + "alerting:apm.transaction_duration/alerts/rule/disable", + "alerting:apm.transaction_duration/alerts/rule/muteAll", + "alerting:apm.transaction_duration/alerts/rule/unmuteAll", + "alerting:apm.transaction_duration/alerts/rule/muteAlert", + "alerting:apm.transaction_duration/alerts/rule/unmuteAlert", + "alerting:apm.transaction_duration/alerts/rule/snooze", + "alerting:apm.transaction_duration/alerts/rule/bulkEdit", + "alerting:apm.transaction_duration/alerts/rule/bulkDelete", + "alerting:apm.transaction_duration/alerts/rule/bulkEnable", + "alerting:apm.transaction_duration/alerts/rule/bulkDisable", + "alerting:apm.transaction_duration/alerts/rule/unsnooze", + "alerting:apm.transaction_duration/alerts/rule/runSoon", + "alerting:apm.transaction_duration/alerts/rule/scheduleBackfill", + "alerting:apm.transaction_duration/alerts/rule/deleteBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -9963,6 +19714,34 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/runSoon", "alerting:apm.anomaly/observability/rule/scheduleBackfill", "alerting:apm.anomaly/observability/rule/deleteBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/create", + "alerting:apm.anomaly/alerts/rule/delete", + "alerting:apm.anomaly/alerts/rule/update", + "alerting:apm.anomaly/alerts/rule/updateApiKey", + "alerting:apm.anomaly/alerts/rule/enable", + "alerting:apm.anomaly/alerts/rule/disable", + "alerting:apm.anomaly/alerts/rule/muteAll", + "alerting:apm.anomaly/alerts/rule/unmuteAll", + "alerting:apm.anomaly/alerts/rule/muteAlert", + "alerting:apm.anomaly/alerts/rule/unmuteAlert", + "alerting:apm.anomaly/alerts/rule/snooze", + "alerting:apm.anomaly/alerts/rule/bulkEdit", + "alerting:apm.anomaly/alerts/rule/bulkDelete", + "alerting:apm.anomaly/alerts/rule/bulkEnable", + "alerting:apm.anomaly/alerts/rule/bulkDisable", + "alerting:apm.anomaly/alerts/rule/unsnooze", + "alerting:apm.anomaly/alerts/rule/runSoon", + "alerting:apm.anomaly/alerts/rule/scheduleBackfill", + "alerting:apm.anomaly/alerts/rule/deleteBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -10014,56 +19793,555 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/bulkEdit", "alerting:xpack.synthetics.alerts.tls/observability/rule/bulkDelete", "alerting:xpack.synthetics.alerts.tls/observability/rule/bulkEnable", - "alerting:xpack.synthetics.alerts.tls/observability/rule/bulkDisable", - "alerting:xpack.synthetics.alerts.tls/observability/rule/unsnooze", - "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", - "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", - "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:slo.rules.burnRate/observability/alert/update", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/update", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/update", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:xpack.synthetics.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.synthetics.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.synthetics.alerts.tls/observability/rule/runSoon", + "alerting:xpack.synthetics.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.synthetics.alerts.tls/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/observability/rule/create", + "alerting:metrics.alert.threshold/observability/rule/delete", + "alerting:metrics.alert.threshold/observability/rule/update", + "alerting:metrics.alert.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.threshold/observability/rule/enable", + "alerting:metrics.alert.threshold/observability/rule/disable", + "alerting:metrics.alert.threshold/observability/rule/muteAll", + "alerting:metrics.alert.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.threshold/observability/rule/snooze", + "alerting:metrics.alert.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.threshold/observability/rule/runSoon", + "alerting:metrics.alert.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/create", + "alerting:metrics.alert.threshold/alerts/rule/delete", + "alerting:metrics.alert.threshold/alerts/rule/update", + "alerting:metrics.alert.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.threshold/alerts/rule/enable", + "alerting:metrics.alert.threshold/alerts/rule/disable", + "alerting:metrics.alert.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.threshold/alerts/rule/snooze", + "alerting:metrics.alert.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.threshold/alerts/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/create", + "alerting:metrics.alert.inventory.threshold/observability/rule/delete", + "alerting:metrics.alert.inventory.threshold/observability/rule/update", + "alerting:metrics.alert.inventory.threshold/observability/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/observability/rule/enable", + "alerting:metrics.alert.inventory.threshold/observability/rule/disable", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/observability/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/observability/rule/snooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/observability/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/observability/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/observability/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/observability/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/deleteBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/create", + "alerting:metrics.alert.inventory.threshold/alerts/rule/delete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/update", + "alerting:metrics.alert.inventory.threshold/alerts/rule/updateApiKey", + "alerting:metrics.alert.inventory.threshold/alerts/rule/enable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/disable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAll", + "alerting:metrics.alert.inventory.threshold/alerts/rule/muteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unmuteAlert", + "alerting:metrics.alert.inventory.threshold/alerts/rule/snooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEdit", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDelete", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkEnable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/bulkDisable", + "alerting:metrics.alert.inventory.threshold/alerts/rule/unsnooze", + "alerting:metrics.alert.inventory.threshold/alerts/rule/runSoon", + "alerting:metrics.alert.inventory.threshold/alerts/rule/scheduleBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/create", + "alerting:xpack.uptime.alerts.tls/observability/rule/delete", + "alerting:xpack.uptime.alerts.tls/observability/rule/update", + "alerting:xpack.uptime.alerts.tls/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tls/observability/rule/enable", + "alerting:xpack.uptime.alerts.tls/observability/rule/disable", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tls/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tls/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tls/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tls/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tls/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tls/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/create", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/delete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/enable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/disable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/snooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/create", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/delete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/enable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/disable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/snooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/deleteBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/create", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/delete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/updateApiKey", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/enable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/disable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAll", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/muteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unmuteAlert", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/snooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEdit", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDelete", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkEnable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/bulkDisable", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/unsnooze", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/runSoon", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/scheduleBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/create", + "alerting:logs.alert.document.count/observability/rule/delete", + "alerting:logs.alert.document.count/observability/rule/update", + "alerting:logs.alert.document.count/observability/rule/updateApiKey", + "alerting:logs.alert.document.count/observability/rule/enable", + "alerting:logs.alert.document.count/observability/rule/disable", + "alerting:logs.alert.document.count/observability/rule/muteAll", + "alerting:logs.alert.document.count/observability/rule/unmuteAll", + "alerting:logs.alert.document.count/observability/rule/muteAlert", + "alerting:logs.alert.document.count/observability/rule/unmuteAlert", + "alerting:logs.alert.document.count/observability/rule/snooze", + "alerting:logs.alert.document.count/observability/rule/bulkEdit", + "alerting:logs.alert.document.count/observability/rule/bulkDelete", + "alerting:logs.alert.document.count/observability/rule/bulkEnable", + "alerting:logs.alert.document.count/observability/rule/bulkDisable", + "alerting:logs.alert.document.count/observability/rule/unsnooze", + "alerting:logs.alert.document.count/observability/rule/runSoon", + "alerting:logs.alert.document.count/observability/rule/scheduleBackfill", + "alerting:logs.alert.document.count/observability/rule/deleteBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/create", + "alerting:logs.alert.document.count/alerts/rule/delete", + "alerting:logs.alert.document.count/alerts/rule/update", + "alerting:logs.alert.document.count/alerts/rule/updateApiKey", + "alerting:logs.alert.document.count/alerts/rule/enable", + "alerting:logs.alert.document.count/alerts/rule/disable", + "alerting:logs.alert.document.count/alerts/rule/muteAll", + "alerting:logs.alert.document.count/alerts/rule/unmuteAll", + "alerting:logs.alert.document.count/alerts/rule/muteAlert", + "alerting:logs.alert.document.count/alerts/rule/unmuteAlert", + "alerting:logs.alert.document.count/alerts/rule/snooze", + "alerting:logs.alert.document.count/alerts/rule/bulkEdit", + "alerting:logs.alert.document.count/alerts/rule/bulkDelete", + "alerting:logs.alert.document.count/alerts/rule/bulkEnable", + "alerting:logs.alert.document.count/alerts/rule/bulkDisable", + "alerting:logs.alert.document.count/alerts/rule/unsnooze", + "alerting:logs.alert.document.count/alerts/rule/runSoon", + "alerting:logs.alert.document.count/alerts/rule/scheduleBackfill", + "alerting:logs.alert.document.count/alerts/rule/deleteBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/create", + "alerting:slo.rules.burnRate/observability/rule/delete", + "alerting:slo.rules.burnRate/observability/rule/update", + "alerting:slo.rules.burnRate/observability/rule/updateApiKey", + "alerting:slo.rules.burnRate/observability/rule/enable", + "alerting:slo.rules.burnRate/observability/rule/disable", + "alerting:slo.rules.burnRate/observability/rule/muteAll", + "alerting:slo.rules.burnRate/observability/rule/unmuteAll", + "alerting:slo.rules.burnRate/observability/rule/muteAlert", + "alerting:slo.rules.burnRate/observability/rule/unmuteAlert", + "alerting:slo.rules.burnRate/observability/rule/snooze", + "alerting:slo.rules.burnRate/observability/rule/bulkEdit", + "alerting:slo.rules.burnRate/observability/rule/bulkDelete", + "alerting:slo.rules.burnRate/observability/rule/bulkEnable", + "alerting:slo.rules.burnRate/observability/rule/bulkDisable", + "alerting:slo.rules.burnRate/observability/rule/unsnooze", + "alerting:slo.rules.burnRate/observability/rule/runSoon", + "alerting:slo.rules.burnRate/observability/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/observability/rule/deleteBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/create", + "alerting:slo.rules.burnRate/alerts/rule/delete", + "alerting:slo.rules.burnRate/alerts/rule/update", + "alerting:slo.rules.burnRate/alerts/rule/updateApiKey", + "alerting:slo.rules.burnRate/alerts/rule/enable", + "alerting:slo.rules.burnRate/alerts/rule/disable", + "alerting:slo.rules.burnRate/alerts/rule/muteAll", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAll", + "alerting:slo.rules.burnRate/alerts/rule/muteAlert", + "alerting:slo.rules.burnRate/alerts/rule/unmuteAlert", + "alerting:slo.rules.burnRate/alerts/rule/snooze", + "alerting:slo.rules.burnRate/alerts/rule/bulkEdit", + "alerting:slo.rules.burnRate/alerts/rule/bulkDelete", + "alerting:slo.rules.burnRate/alerts/rule/bulkEnable", + "alerting:slo.rules.burnRate/alerts/rule/bulkDisable", + "alerting:slo.rules.burnRate/alerts/rule/unsnooze", + "alerting:slo.rules.burnRate/alerts/rule/runSoon", + "alerting:slo.rules.burnRate/alerts/rule/scheduleBackfill", + "alerting:slo.rules.burnRate/alerts/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/create", + "alerting:observability.rules.custom_threshold/observability/rule/delete", + "alerting:observability.rules.custom_threshold/observability/rule/update", + "alerting:observability.rules.custom_threshold/observability/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/observability/rule/enable", + "alerting:observability.rules.custom_threshold/observability/rule/disable", + "alerting:observability.rules.custom_threshold/observability/rule/muteAll", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/observability/rule/muteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/observability/rule/snooze", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/observability/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/observability/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/observability/rule/unsnooze", + "alerting:observability.rules.custom_threshold/observability/rule/runSoon", + "alerting:observability.rules.custom_threshold/observability/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/deleteBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/create", + "alerting:observability.rules.custom_threshold/alerts/rule/delete", + "alerting:observability.rules.custom_threshold/alerts/rule/update", + "alerting:observability.rules.custom_threshold/alerts/rule/updateApiKey", + "alerting:observability.rules.custom_threshold/alerts/rule/enable", + "alerting:observability.rules.custom_threshold/alerts/rule/disable", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAll", + "alerting:observability.rules.custom_threshold/alerts/rule/muteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/unmuteAlert", + "alerting:observability.rules.custom_threshold/alerts/rule/snooze", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEdit", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDelete", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkEnable", + "alerting:observability.rules.custom_threshold/alerts/rule/bulkDisable", + "alerting:observability.rules.custom_threshold/alerts/rule/unsnooze", + "alerting:observability.rules.custom_threshold/alerts/rule/runSoon", + "alerting:observability.rules.custom_threshold/alerts/rule/scheduleBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/deleteBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/observability/rule/create", + "alerting:.es-query/observability/rule/delete", + "alerting:.es-query/observability/rule/update", + "alerting:.es-query/observability/rule/updateApiKey", + "alerting:.es-query/observability/rule/enable", + "alerting:.es-query/observability/rule/disable", + "alerting:.es-query/observability/rule/muteAll", + "alerting:.es-query/observability/rule/unmuteAll", + "alerting:.es-query/observability/rule/muteAlert", + "alerting:.es-query/observability/rule/unmuteAlert", + "alerting:.es-query/observability/rule/snooze", + "alerting:.es-query/observability/rule/bulkEdit", + "alerting:.es-query/observability/rule/bulkDelete", + "alerting:.es-query/observability/rule/bulkEnable", + "alerting:.es-query/observability/rule/bulkDisable", + "alerting:.es-query/observability/rule/unsnooze", + "alerting:.es-query/observability/rule/runSoon", + "alerting:.es-query/observability/rule/scheduleBackfill", + "alerting:.es-query/observability/rule/deleteBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:.es-query/alerts/rule/create", + "alerting:.es-query/alerts/rule/delete", + "alerting:.es-query/alerts/rule/update", + "alerting:.es-query/alerts/rule/updateApiKey", + "alerting:.es-query/alerts/rule/enable", + "alerting:.es-query/alerts/rule/disable", + "alerting:.es-query/alerts/rule/muteAll", + "alerting:.es-query/alerts/rule/unmuteAll", + "alerting:.es-query/alerts/rule/muteAlert", + "alerting:.es-query/alerts/rule/unmuteAlert", + "alerting:.es-query/alerts/rule/snooze", + "alerting:.es-query/alerts/rule/bulkEdit", + "alerting:.es-query/alerts/rule/bulkDelete", + "alerting:.es-query/alerts/rule/bulkEnable", + "alerting:.es-query/alerts/rule/bulkDisable", + "alerting:.es-query/alerts/rule/unsnooze", + "alerting:.es-query/alerts/rule/runSoon", + "alerting:.es-query/alerts/rule/scheduleBackfill", + "alerting:.es-query/alerts/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/deleteBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/create", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/delete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/updateApiKey", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/enable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/disable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAll", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/muteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unmuteAlert", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/snooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEdit", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDelete", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkEnable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/bulkDisable", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/unsnooze", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/runSoon", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/scheduleBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/deleteBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", "alerting:apm.error_rate/observability/alert/update", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/update", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/update", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/update", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/update", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/update", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/update", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/update", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", @@ -10074,6 +20352,96 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/observability/alert/update", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/update", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/update", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/update", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/update", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/update", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/update", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/update", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/update", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/update", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/update", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/update", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/update", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/update", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/update", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/observability/alert/update", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/update", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/update", ], "minimal_read": Array [ "login:", @@ -10154,6 +20522,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.tls/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", @@ -10163,6 +20540,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", @@ -10172,6 +20558,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", @@ -10181,97 +20576,103 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getExecutionLog", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getActionErrorLog", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", - "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", - "alerting:xpack.uptime.alerts.tls/uptime/alert/get", - "alerting:xpack.uptime.alerts.tls/uptime/alert/find", - "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", - "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", - "app:observability", - "ui:catalogue/observability", - "ui:navLinks/observability", - "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/find", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/uptime/alert/get", + "alerting:xpack.uptime.alerts.tls/uptime/alert/find", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", + "app:observability", + "ui:catalogue/observability", + "ui:navLinks/observability", + "ui:observability/read", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -10281,6 +20682,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -10290,6 +20700,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -10299,6 +20718,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -10308,6 +20736,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -10326,42 +20763,200 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", @@ -10370,6 +20965,78 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], "read": Array [ "login:", @@ -10450,6 +21117,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tls/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.tls/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/get", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/alerts/rule/find", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/get", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getAlertSummary", @@ -10459,6 +21135,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getAlertSummary", @@ -10468,6 +21153,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/get", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleState", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getAlertSummary", @@ -10477,6 +21171,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getRuleExecutionKPI", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/getBackfill", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getAlertSummary", @@ -10486,6 +21189,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/getBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.tls/uptime/rule/get", "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleState", "alerting:xpack.synthetics.alerts.tls/uptime/rule/getAlertSummary", @@ -10495,79 +21207,67 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/uptime/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/uptime/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/uptime/rule/findBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/get", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleState", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getExecutionLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getActionErrorLog", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/find", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/getBackfill", + "alerting:xpack.synthetics.alerts.tls/alerts/rule/findBackfill", "alerting:xpack.uptime.alerts.tls/uptime/alert/get", "alerting:xpack.uptime.alerts.tls/uptime/alert/find", "alerting:xpack.uptime.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/alerts/alert/get", + "alerting:xpack.uptime.alerts.tls/alerts/alert/find", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/alerts/alert/getAlertSummary", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/get", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/find", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.tlsCertificate/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/alerts/alert/getAlertSummary", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/get", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/find", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/get", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/find", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.uptime.alerts.durationAnomaly/uptime/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.monitorStatus/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/get", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/find", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.monitorStatus/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.tls/uptime/alert/get", "alerting:xpack.synthetics.alerts.tls/uptime/alert/find", "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/uptime/alert/getAlertSummary", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/get", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/find", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.synthetics.alerts.tls/alerts/alert/getAlertSummary", "app:observability", "ui:catalogue/observability", "ui:navLinks/observability", "ui:observability/read", - "alerting:slo.rules.burnRate/observability/rule/get", - "alerting:slo.rules.burnRate/observability/rule/getRuleState", - "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", - "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", - "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", - "alerting:slo.rules.burnRate/observability/rule/find", - "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", - "alerting:slo.rules.burnRate/observability/rule/getBackfill", - "alerting:slo.rules.burnRate/observability/rule/findBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/get", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", - "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", - "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", - "alerting:observability.rules.custom_threshold/observability/rule/find", - "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", - "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", - "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", - "alerting:.es-query/observability/rule/get", - "alerting:.es-query/observability/rule/getRuleState", - "alerting:.es-query/observability/rule/getAlertSummary", - "alerting:.es-query/observability/rule/getExecutionLog", - "alerting:.es-query/observability/rule/getActionErrorLog", - "alerting:.es-query/observability/rule/find", - "alerting:.es-query/observability/rule/getRuleExecutionKPI", - "alerting:.es-query/observability/rule/getBackfill", - "alerting:.es-query/observability/rule/findBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", - "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/get", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", - "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", - "alerting:metrics.alert.inventory.threshold/observability/rule/find", - "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", - "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", - "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", "alerting:apm.error_rate/observability/rule/get", "alerting:apm.error_rate/observability/rule/getRuleState", "alerting:apm.error_rate/observability/rule/getAlertSummary", @@ -10577,6 +21277,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.error_rate/observability/rule/getBackfill", "alerting:apm.error_rate/observability/rule/findBackfill", + "alerting:apm.error_rate/alerts/rule/get", + "alerting:apm.error_rate/alerts/rule/getRuleState", + "alerting:apm.error_rate/alerts/rule/getAlertSummary", + "alerting:apm.error_rate/alerts/rule/getExecutionLog", + "alerting:apm.error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.error_rate/alerts/rule/find", + "alerting:apm.error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.error_rate/alerts/rule/getBackfill", + "alerting:apm.error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_error_rate/observability/rule/get", "alerting:apm.transaction_error_rate/observability/rule/getRuleState", "alerting:apm.transaction_error_rate/observability/rule/getAlertSummary", @@ -10586,6 +21295,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_error_rate/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_error_rate/observability/rule/getBackfill", "alerting:apm.transaction_error_rate/observability/rule/findBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/get", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleState", + "alerting:apm.transaction_error_rate/alerts/rule/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/rule/getExecutionLog", + "alerting:apm.transaction_error_rate/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_error_rate/alerts/rule/find", + "alerting:apm.transaction_error_rate/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_error_rate/alerts/rule/getBackfill", + "alerting:apm.transaction_error_rate/alerts/rule/findBackfill", "alerting:apm.transaction_duration/observability/rule/get", "alerting:apm.transaction_duration/observability/rule/getRuleState", "alerting:apm.transaction_duration/observability/rule/getAlertSummary", @@ -10595,6 +21313,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.transaction_duration/observability/rule/getRuleExecutionKPI", "alerting:apm.transaction_duration/observability/rule/getBackfill", "alerting:apm.transaction_duration/observability/rule/findBackfill", + "alerting:apm.transaction_duration/alerts/rule/get", + "alerting:apm.transaction_duration/alerts/rule/getRuleState", + "alerting:apm.transaction_duration/alerts/rule/getAlertSummary", + "alerting:apm.transaction_duration/alerts/rule/getExecutionLog", + "alerting:apm.transaction_duration/alerts/rule/getActionErrorLog", + "alerting:apm.transaction_duration/alerts/rule/find", + "alerting:apm.transaction_duration/alerts/rule/getRuleExecutionKPI", + "alerting:apm.transaction_duration/alerts/rule/getBackfill", + "alerting:apm.transaction_duration/alerts/rule/findBackfill", "alerting:apm.anomaly/observability/rule/get", "alerting:apm.anomaly/observability/rule/getRuleState", "alerting:apm.anomaly/observability/rule/getAlertSummary", @@ -10604,6 +21331,15 @@ export default function ({ getService }: FtrProviderContext) { "alerting:apm.anomaly/observability/rule/getRuleExecutionKPI", "alerting:apm.anomaly/observability/rule/getBackfill", "alerting:apm.anomaly/observability/rule/findBackfill", + "alerting:apm.anomaly/alerts/rule/get", + "alerting:apm.anomaly/alerts/rule/getRuleState", + "alerting:apm.anomaly/alerts/rule/getAlertSummary", + "alerting:apm.anomaly/alerts/rule/getExecutionLog", + "alerting:apm.anomaly/alerts/rule/getActionErrorLog", + "alerting:apm.anomaly/alerts/rule/find", + "alerting:apm.anomaly/alerts/rule/getRuleExecutionKPI", + "alerting:apm.anomaly/alerts/rule/getBackfill", + "alerting:apm.anomaly/alerts/rule/findBackfill", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getRuleState", "alerting:xpack.synthetics.alerts.monitorStatus/observability/rule/getAlertSummary", @@ -10622,42 +21358,200 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/rule/getRuleExecutionKPI", "alerting:xpack.synthetics.alerts.tls/observability/rule/getBackfill", "alerting:xpack.synthetics.alerts.tls/observability/rule/findBackfill", - "alerting:slo.rules.burnRate/observability/alert/get", - "alerting:slo.rules.burnRate/observability/alert/find", - "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", - "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", - "alerting:observability.rules.custom_threshold/observability/alert/get", - "alerting:observability.rules.custom_threshold/observability/alert/find", - "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", - "alerting:.es-query/observability/alert/get", - "alerting:.es-query/observability/alert/find", - "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", - "alerting:.es-query/observability/alert/getAlertSummary", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", - "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", - "alerting:metrics.alert.inventory.threshold/observability/alert/get", - "alerting:metrics.alert.inventory.threshold/observability/alert/find", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", - "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/get", + "alerting:metrics.alert.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/observability/rule/find", + "alerting:metrics.alert.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.threshold/alerts/rule/get", + "alerting:metrics.alert.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.threshold/alerts/rule/find", + "alerting:metrics.alert.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.threshold/alerts/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/get", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/observability/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/observability/rule/find", + "alerting:metrics.alert.inventory.threshold/observability/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/observability/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/observability/rule/findBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/get", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleState", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getExecutionLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getActionErrorLog", + "alerting:metrics.alert.inventory.threshold/alerts/rule/find", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getRuleExecutionKPI", + "alerting:metrics.alert.inventory.threshold/alerts/rule/getBackfill", + "alerting:metrics.alert.inventory.threshold/alerts/rule/findBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/get", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tls/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tls/observability/rule/find", + "alerting:xpack.uptime.alerts.tls/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tls/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tls/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.monitorStatus/observability/rule/findBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleState", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getExecutionLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getActionErrorLog", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getRuleExecutionKPI", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/getBackfill", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/rule/findBackfill", + "alerting:logs.alert.document.count/observability/rule/get", + "alerting:logs.alert.document.count/observability/rule/getRuleState", + "alerting:logs.alert.document.count/observability/rule/getAlertSummary", + "alerting:logs.alert.document.count/observability/rule/getExecutionLog", + "alerting:logs.alert.document.count/observability/rule/getActionErrorLog", + "alerting:logs.alert.document.count/observability/rule/find", + "alerting:logs.alert.document.count/observability/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/observability/rule/getBackfill", + "alerting:logs.alert.document.count/observability/rule/findBackfill", + "alerting:logs.alert.document.count/alerts/rule/get", + "alerting:logs.alert.document.count/alerts/rule/getRuleState", + "alerting:logs.alert.document.count/alerts/rule/getAlertSummary", + "alerting:logs.alert.document.count/alerts/rule/getExecutionLog", + "alerting:logs.alert.document.count/alerts/rule/getActionErrorLog", + "alerting:logs.alert.document.count/alerts/rule/find", + "alerting:logs.alert.document.count/alerts/rule/getRuleExecutionKPI", + "alerting:logs.alert.document.count/alerts/rule/getBackfill", + "alerting:logs.alert.document.count/alerts/rule/findBackfill", + "alerting:slo.rules.burnRate/observability/rule/get", + "alerting:slo.rules.burnRate/observability/rule/getRuleState", + "alerting:slo.rules.burnRate/observability/rule/getAlertSummary", + "alerting:slo.rules.burnRate/observability/rule/getExecutionLog", + "alerting:slo.rules.burnRate/observability/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/observability/rule/find", + "alerting:slo.rules.burnRate/observability/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/observability/rule/getBackfill", + "alerting:slo.rules.burnRate/observability/rule/findBackfill", + "alerting:slo.rules.burnRate/alerts/rule/get", + "alerting:slo.rules.burnRate/alerts/rule/getRuleState", + "alerting:slo.rules.burnRate/alerts/rule/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/rule/getExecutionLog", + "alerting:slo.rules.burnRate/alerts/rule/getActionErrorLog", + "alerting:slo.rules.burnRate/alerts/rule/find", + "alerting:slo.rules.burnRate/alerts/rule/getRuleExecutionKPI", + "alerting:slo.rules.burnRate/alerts/rule/getBackfill", + "alerting:slo.rules.burnRate/alerts/rule/findBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/get", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleState", + "alerting:observability.rules.custom_threshold/observability/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/observability/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/observability/rule/find", + "alerting:observability.rules.custom_threshold/observability/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/observability/rule/getBackfill", + "alerting:observability.rules.custom_threshold/observability/rule/findBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/get", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleState", + "alerting:observability.rules.custom_threshold/alerts/rule/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/rule/getExecutionLog", + "alerting:observability.rules.custom_threshold/alerts/rule/getActionErrorLog", + "alerting:observability.rules.custom_threshold/alerts/rule/find", + "alerting:observability.rules.custom_threshold/alerts/rule/getRuleExecutionKPI", + "alerting:observability.rules.custom_threshold/alerts/rule/getBackfill", + "alerting:observability.rules.custom_threshold/alerts/rule/findBackfill", + "alerting:.es-query/observability/rule/get", + "alerting:.es-query/observability/rule/getRuleState", + "alerting:.es-query/observability/rule/getAlertSummary", + "alerting:.es-query/observability/rule/getExecutionLog", + "alerting:.es-query/observability/rule/getActionErrorLog", + "alerting:.es-query/observability/rule/find", + "alerting:.es-query/observability/rule/getRuleExecutionKPI", + "alerting:.es-query/observability/rule/getBackfill", + "alerting:.es-query/observability/rule/findBackfill", + "alerting:.es-query/alerts/rule/get", + "alerting:.es-query/alerts/rule/getRuleState", + "alerting:.es-query/alerts/rule/getAlertSummary", + "alerting:.es-query/alerts/rule/getExecutionLog", + "alerting:.es-query/alerts/rule/getActionErrorLog", + "alerting:.es-query/alerts/rule/find", + "alerting:.es-query/alerts/rule/getRuleExecutionKPI", + "alerting:.es-query/alerts/rule/getBackfill", + "alerting:.es-query/alerts/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/observability/rule/findBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleState", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getExecutionLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getActionErrorLog", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getRuleExecutionKPI", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/getBackfill", + "alerting:xpack.ml.anomaly_detection_alert/alerts/rule/findBackfill", "alerting:apm.error_rate/observability/alert/get", "alerting:apm.error_rate/observability/alert/find", "alerting:apm.error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.error_rate/observability/alert/getAlertSummary", + "alerting:apm.error_rate/alerts/alert/get", + "alerting:apm.error_rate/alerts/alert/find", + "alerting:apm.error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_error_rate/observability/alert/get", "alerting:apm.transaction_error_rate/observability/alert/find", "alerting:apm.transaction_error_rate/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_error_rate/observability/alert/getAlertSummary", + "alerting:apm.transaction_error_rate/alerts/alert/get", + "alerting:apm.transaction_error_rate/alerts/alert/find", + "alerting:apm.transaction_error_rate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_error_rate/alerts/alert/getAlertSummary", "alerting:apm.transaction_duration/observability/alert/get", "alerting:apm.transaction_duration/observability/alert/find", "alerting:apm.transaction_duration/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.transaction_duration/observability/alert/getAlertSummary", + "alerting:apm.transaction_duration/alerts/alert/get", + "alerting:apm.transaction_duration/alerts/alert/find", + "alerting:apm.transaction_duration/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.transaction_duration/alerts/alert/getAlertSummary", "alerting:apm.anomaly/observability/alert/get", "alerting:apm.anomaly/observability/alert/find", "alerting:apm.anomaly/observability/alert/getAuthorizedAlertsIndices", "alerting:apm.anomaly/observability/alert/getAlertSummary", + "alerting:apm.anomaly/alerts/alert/get", + "alerting:apm.anomaly/alerts/alert/find", + "alerting:apm.anomaly/alerts/alert/getAuthorizedAlertsIndices", + "alerting:apm.anomaly/alerts/alert/getAlertSummary", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/get", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/find", "alerting:xpack.synthetics.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", @@ -10666,6 +21560,78 @@ export default function ({ getService }: FtrProviderContext) { "alerting:xpack.synthetics.alerts.tls/observability/alert/find", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAuthorizedAlertsIndices", "alerting:xpack.synthetics.alerts.tls/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/observability/alert/get", + "alerting:metrics.alert.threshold/observability/alert/find", + "alerting:metrics.alert.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.threshold/alerts/alert/get", + "alerting:metrics.alert.threshold/alerts/alert/find", + "alerting:metrics.alert.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.threshold/alerts/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/observability/alert/get", + "alerting:metrics.alert.inventory.threshold/observability/alert/find", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/observability/alert/getAlertSummary", + "alerting:metrics.alert.inventory.threshold/alerts/alert/get", + "alerting:metrics.alert.inventory.threshold/alerts/alert/find", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:metrics.alert.inventory.threshold/alerts/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tls/observability/alert/get", + "alerting:xpack.uptime.alerts.tls/observability/alert/find", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tls/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/get", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/find", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.tlsCertificate/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/get", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/find", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.monitorStatus/observability/alert/getAlertSummary", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/get", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/find", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.uptime.alerts.durationAnomaly/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/observability/alert/get", + "alerting:logs.alert.document.count/observability/alert/find", + "alerting:logs.alert.document.count/observability/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/observability/alert/getAlertSummary", + "alerting:logs.alert.document.count/alerts/alert/get", + "alerting:logs.alert.document.count/alerts/alert/find", + "alerting:logs.alert.document.count/alerts/alert/getAuthorizedAlertsIndices", + "alerting:logs.alert.document.count/alerts/alert/getAlertSummary", + "alerting:slo.rules.burnRate/observability/alert/get", + "alerting:slo.rules.burnRate/observability/alert/find", + "alerting:slo.rules.burnRate/observability/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/observability/alert/getAlertSummary", + "alerting:slo.rules.burnRate/alerts/alert/get", + "alerting:slo.rules.burnRate/alerts/alert/find", + "alerting:slo.rules.burnRate/alerts/alert/getAuthorizedAlertsIndices", + "alerting:slo.rules.burnRate/alerts/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/observability/alert/get", + "alerting:observability.rules.custom_threshold/observability/alert/find", + "alerting:observability.rules.custom_threshold/observability/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/observability/alert/getAlertSummary", + "alerting:observability.rules.custom_threshold/alerts/alert/get", + "alerting:observability.rules.custom_threshold/alerts/alert/find", + "alerting:observability.rules.custom_threshold/alerts/alert/getAuthorizedAlertsIndices", + "alerting:observability.rules.custom_threshold/alerts/alert/getAlertSummary", + "alerting:.es-query/observability/alert/get", + "alerting:.es-query/observability/alert/find", + "alerting:.es-query/observability/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/observability/alert/getAlertSummary", + "alerting:.es-query/alerts/alert/get", + "alerting:.es-query/alerts/alert/find", + "alerting:.es-query/alerts/alert/getAuthorizedAlertsIndices", + "alerting:.es-query/alerts/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/observability/alert/getAlertSummary", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/get", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/find", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAuthorizedAlertsIndices", + "alerting:xpack.ml.anomaly_detection_alert/alerts/alert/getAlertSummary", ], }, } diff --git a/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts index 36249651d516..dd0222a24582 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/common_configs/config.group1.ts @@ -31,6 +31,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/saved_objects_management'), require.resolve('../../common/telemetry'), require.resolve('../../common/data_usage'), + require.resolve('../../common/favorites'), ], junit: { reportName: 'Serverless Search API Integration Tests - Common Group 1', diff --git a/x-pack/test_serverless/api_integration/test_suites/search/config.ts b/x-pack/test_serverless/api_integration/test_suites/search/config.ts index 4db3e86bb978..b662b105b54b 100644 --- a/x-pack/test_serverless/api_integration/test_suites/search/config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/search/config.ts @@ -23,6 +23,7 @@ export default createTestConfig({ // useful for testing (also enabled in MKI QA) '--coreApp.allowDynamicConfigOverrides=true', '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', // dataUsage.autoops* config is set in kibana controller '--xpack.dataUsage.autoops.enabled=true', '--xpack.dataUsage.autoops.api.url=http://localhost:9000', diff --git a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts index 577b4f8ba4ee..29888d803198 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/common_configs/config.group1.ts @@ -33,6 +33,7 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { require.resolve('../../common/saved_objects_management'), require.resolve('../../common/telemetry'), require.resolve('../../common/data_usage'), + require.resolve('../../common/favorites'), ], junit: { reportName: 'Serverless Security API Integration Tests - Common Group 1', diff --git a/x-pack/test_serverless/api_integration/test_suites/security/config.ts b/x-pack/test_serverless/api_integration/test_suites/security/config.ts index 511ec3176ef6..d5d816dfcdf1 100644 --- a/x-pack/test_serverless/api_integration/test_suites/security/config.ts +++ b/x-pack/test_serverless/api_integration/test_suites/security/config.ts @@ -27,6 +27,7 @@ export default createTestConfig({ `--xpack.securitySolutionServerless.cloudSecurityUsageReportingTaskInterval=5s`, `--xpack.securitySolutionServerless.usageApi.url=http://localhost:8081`, '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', // dataUsage.autoops* config is set in kibana controller '--xpack.dataUsage.autoops.enabled=true', '--xpack.dataUsage.autoops.api.url=http://localhost:9000', diff --git a/x-pack/test_serverless/functional/config.base.ts b/x-pack/test_serverless/functional/config.base.ts index f904c53195dc..ad1b01664873 100644 --- a/x-pack/test_serverless/functional/config.base.ts +++ b/x-pack/test_serverless/functional/config.base.ts @@ -11,7 +11,9 @@ import { pageObjects } from './page_objects'; import { services } from './services'; import type { CreateTestConfigOptions } from '../shared/types'; -export function createTestConfig(options: CreateTestConfigOptions) { +export function createTestConfig( + options: CreateTestConfigOptions +) { return async ({ readConfigFile }: FtrConfigProviderContext) => { const svlSharedConfig = await readConfigFile(require.resolve('../shared/config.base.ts')); @@ -19,7 +21,7 @@ export function createTestConfig(options: CreateTestConfigOptions) { ...svlSharedConfig.getAll(), pageObjects, - services, + services: { ...services, ...options.services }, esTestCluster: { ...svlSharedConfig.get('esTestCluster'), serverArgs: [ diff --git a/x-pack/test_serverless/functional/page_objects/index.ts b/x-pack/test_serverless/functional/page_objects/index.ts index 2c894b28b065..e10e98529b8b 100644 --- a/x-pack/test_serverless/functional/page_objects/index.ts +++ b/x-pack/test_serverless/functional/page_objects/index.ts @@ -25,6 +25,7 @@ import { SvlSearchIndexDetailPageProvider } from './svl_search_index_detail_page import { SvlSearchElasticsearchStartPageProvider } from './svl_search_elasticsearch_start_page'; import { SvlApiKeysProvider } from './svl_api_keys'; import { SvlSearchCreateIndexPageProvider } from './svl_search_create_index_page'; +import { SvlSearchInferenceManagementPageProvider } from './svl_search_inference_management_page'; export const pageObjects = { ...xpackFunctionalPageObjects, @@ -47,4 +48,5 @@ export const pageObjects = { svlSearchElasticsearchStartPage: SvlSearchElasticsearchStartPageProvider, svlApiKeys: SvlApiKeysProvider, svlSearchCreateIndexPage: SvlSearchCreateIndexPageProvider, + svlSearchInferenceManagementPage: SvlSearchInferenceManagementPageProvider, }; diff --git a/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts b/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts index 217a17263b1f..2228967f2915 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_api_keys.ts @@ -44,6 +44,10 @@ export function SvlApiKeysProvider({ getService, getPageObjects }: FtrProviderCo expect(sessionStorageKey.encoded).to.eql(apiKey); }, + async expectAPIKeyNoPrivileges() { + await testSubjects.existOrFail('apiKeyFormNoUserPrivileges'); + }, + async getAPIKeyFromSessionStorage() { return getAPIKeyFromSessionStorage(); }, diff --git a/x-pack/test_serverless/functional/page_objects/svl_search_inference_management_page.ts b/x-pack/test_serverless/functional/page_objects/svl_search_inference_management_page.ts new file mode 100644 index 000000000000..4424238a9c80 --- /dev/null +++ b/x-pack/test_serverless/functional/page_objects/svl_search_inference_management_page.ts @@ -0,0 +1,127 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import { FtrProviderContext } from '../ftr_provider_context'; + +export function SvlSearchInferenceManagementPageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + const browser = getService('browser'); + + return { + InferenceTabularPage: { + async expectHeaderToBeExist() { + await testSubjects.existOrFail('allInferenceEndpointsPage'); + await testSubjects.existOrFail('api-documentation'); + await testSubjects.existOrFail('view-your-models'); + }, + + async expectTabularViewToBeLoaded() { + await testSubjects.existOrFail('search-field-endpoints'); + await testSubjects.existOrFail('type-field-endpoints'); + await testSubjects.existOrFail('service-field-endpoints'); + + const table = await testSubjects.find('inferenceEndpointTable'); + const rows = await table.findAllByClassName('euiTableRow'); + expect(rows.length).to.equal(2); + + const elserEndpointCell = await rows[0].findByTestSubject('endpointCell'); + const elserEndpointName = await elserEndpointCell.getVisibleText(); + expect(elserEndpointName).to.contain('.elser-2-elasticsearch'); + + const elserProviderCell = await rows[0].findByTestSubject('providerCell'); + const elserProviderName = await elserProviderCell.getVisibleText(); + expect(elserProviderName).to.contain('Elasticsearch'); + expect(elserProviderName).to.contain('.elser_model_2'); + + const elserTypeCell = await rows[0].findByTestSubject('typeCell'); + const elserTypeName = await elserTypeCell.getVisibleText(); + expect(elserTypeName).to.contain('sparse_embedding'); + + const e5EndpointCell = await rows[1].findByTestSubject('endpointCell'); + const e5EndpointName = await e5EndpointCell.getVisibleText(); + expect(e5EndpointName).to.contain('.multilingual-e5-small-elasticsearch'); + + const e5ProviderCell = await rows[1].findByTestSubject('providerCell'); + const e5ProviderName = await e5ProviderCell.getVisibleText(); + expect(e5ProviderName).to.contain('Elasticsearch'); + expect(e5ProviderName).to.contain('.multilingual-e5-small'); + + const e5TypeCell = await rows[1].findByTestSubject('typeCell'); + const e5TypeName = await e5TypeCell.getVisibleText(); + expect(e5TypeName).to.contain('text_embedding'); + }, + + async expectPreconfiguredEndpointsCannotBeDeleted() { + const table = await testSubjects.find('inferenceEndpointTable'); + const rows = await table.findAllByClassName('euiTableRow'); + + const elserDeleteAction = await rows[0].findByTestSubject('inferenceUIDeleteAction'); + const e5DeleteAction = await rows[1].findByTestSubject('inferenceUIDeleteAction'); + + expect(await elserDeleteAction.isEnabled()).to.be(false); + expect(await e5DeleteAction.isEnabled()).to.be(false); + }, + + async expectEndpointWithoutUsageTobeDelete() { + const table = await testSubjects.find('inferenceEndpointTable'); + const rows = await table.findAllByClassName('euiTableRow'); + + const userCreatedEndpoint = await rows[2].findByTestSubject('inferenceUIDeleteAction'); + + await userCreatedEndpoint.click(); + await testSubjects.existOrFail('deleteModalForInferenceUI'); + await testSubjects.existOrFail('deleteModalInferenceEndpointName'); + + await testSubjects.click('confirmModalConfirmButton'); + + await testSubjects.existOrFail('inferenceEndpointTable'); + }, + + async expectEndpointWithUsageTobeDelete() { + const table = await testSubjects.find('inferenceEndpointTable'); + const rows = await table.findAllByClassName('euiTableRow'); + + const userCreatedEndpoint = await rows[2].findByTestSubject('inferenceUIDeleteAction'); + + await userCreatedEndpoint.click(); + await testSubjects.existOrFail('deleteModalForInferenceUI'); + await testSubjects.existOrFail('deleteModalInferenceEndpointName'); + + const items = await testSubjects.findAll('usageItem'); + expect(items.length).to.equal(2); + + const index = await items[0].getVisibleText(); + const pipeline = await items[1].getVisibleText(); + + expect(index.includes('elser_index')).to.be(true); + expect(pipeline.includes('endpoint-1')).to.be(true); + + expect(await testSubjects.isEnabled('confirmModalConfirmButton')).to.be(false); + + await testSubjects.click('warningCheckbox'); + + expect(await testSubjects.isEnabled('confirmModalConfirmButton')).to.be(true); + await testSubjects.click('confirmModalConfirmButton'); + + await testSubjects.existOrFail('inferenceEndpointTable'); + }, + + async expectToCopyEndpoint() { + const table = await testSubjects.find('inferenceEndpointTable'); + const rows = await table.findAllByClassName('euiTableRow'); + + const elserCopyEndpointId = await rows[0].findByTestSubject( + 'inference-endpoints-action-copy-id-label' + ); + + await elserCopyEndpointId.click(); + expect((await browser.getClipboardValue()).includes('.elser-2-elasticsearch')).to.be(true); + }, + }, + }; +} diff --git a/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts b/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts index 314ecf93fb7b..1f09e7353763 100644 --- a/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts +++ b/x-pack/test_serverless/functional/services/deployment_agnostic_services.ts @@ -36,7 +36,6 @@ const deploymentAgnosticFunctionalServices = _.pick(functionalServices, [ 'dashboardVisualizations', 'dataGrid', 'dataStreams', - 'docTable', 'dataViews', 'elasticChart', 'embedding', diff --git a/x-pack/test_serverless/functional/services/ml/observability_navigation.ts b/x-pack/test_serverless/functional/services/ml/observability_navigation.ts index 83f6cd4ea94d..5181d4981321 100644 --- a/x-pack/test_serverless/functional/services/ml/observability_navigation.ts +++ b/x-pack/test_serverless/functional/services/ml/observability_navigation.ts @@ -15,7 +15,7 @@ export function MachineLearningNavigationProviderObservability({ const svlCommonNavigation = getPageObject('svlCommonNavigation'); async function navigateToArea(id: string) { - await svlCommonNavigation.sidenav.openPanel('machine_learning-landing'); + await svlCommonNavigation.sidenav.openPanel('machine_learning-landing', { button: 'link' }); await testSubjects.existOrFail(`~panelNavItem-id-ml:${id}`, { timeout: 60 * 1000, }); diff --git a/x-pack/test_serverless/functional/services/svl_search_navigation.ts b/x-pack/test_serverless/functional/services/svl_search_navigation.ts index 1f27cf18ec8c..434a5bd4e42a 100644 --- a/x-pack/test_serverless/functional/services/svl_search_navigation.ts +++ b/x-pack/test_serverless/functional/services/svl_search_navigation.ts @@ -47,5 +47,10 @@ export function SvlSearchNavigationServiceProvider({ }); await testSubjects.existOrFail('searchIndicesDetailsPage', { timeout: 2000 }); }, + async navigateToInferenceManagementPage(expectRedirect: boolean = false) { + await PageObjects.common.navigateToApp('searchInferenceEndpoints', { + shouldLoginIfPrompted: false, + }); + }, }; } diff --git a/x-pack/test_serverless/functional/test_suites/common/data_usage/privileges.ts b/x-pack/test_serverless/functional/test_suites/common/data_usage/privileges.ts index 7865672e9049..e926b43aedfc 100644 --- a/x-pack/test_serverless/functional/test_suites/common/data_usage/privileges.ts +++ b/x-pack/test_serverless/functional/test_suites/common/data_usage/privileges.ts @@ -32,14 +32,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }; describe('privileges', function () { - // plugin needs to be enabled in serverless - this.tags(['skipMKI']); - it('renders for the admin role', async () => { await pageObjects.svlCommonPage.loginAsAdmin(); await navigateAndVerify(true); }); - it('does not render for viewer', async () => { await pageObjects.svlCommonPage.loginAsViewer(); await navigateAndVerify(false); @@ -61,8 +57,9 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); describe('with custom role', function () { - // custom roles aren't available in observability yet - this.tags(['skipSvlOblt']); + // skipSvlOblt: custom roles aren't available in observability yet + // skipMKI: custom roles aren't available in MKI testing yet + this.tags(['skipSvlOblt', 'skipMKI']); afterEach(async () => { await samlAuth.deleteCustomRole(); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts index 5867eb528bf8..6bb8eaee1df9 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/context_awareness/extensions/_get_default_app_state.ts @@ -43,8 +43,15 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); } + function expectBreakdown(breakdown: string) { + return retry.try(async () => { + const breakdownFieldValue = await PageObjects.discover.getBreakdownFieldValue(); + expect(breakdownFieldValue).to.be(breakdown); + }); + } + describe('ES|QL mode', () => { - it('should render default columns and row height', async () => { + it('should render default state', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -60,9 +67,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should render default columns and row height when switching index patterns', async () => { + it('should render default state when switching index patterns', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -86,9 +94,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should reset default columns and row height when clicking "New"', async () => { + it('should reset default state when clicking "New"', async () => { const state = kbnRison.encode({ dataSource: { type: 'esql' }, query: { @@ -114,6 +123,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); it('should merge and dedup configured default columns with default profile columns', async () => { @@ -134,7 +144,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); describe('data view mode', () => { - it('should render default columns and row height', async () => { + it('should render default state', async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -147,9 +157,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should render default columns and row height when switching data views', async () => { + it('should render default state when switching data views', async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -169,9 +180,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); - it('should reset default columns and row height when clicking "New"', async () => { + it('should reset default state when clicking "New"', async () => { await PageObjects.common.navigateToActualUrl('discover', undefined, { ensureCurrentUrl: false, }); @@ -194,6 +206,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(rowHeightValue).to.be('Custom'); const rowHeightNumber = await dataGrid.getCustomRowHeightNumber(); expect(rowHeightNumber).to.be(5); + await expectBreakdown('Breakdown by log.level'); }); it('should merge and dedup configured default columns with default profile columns', async () => { diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts index ff0f2eadf3e2..6402b5ce4737 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group3/_request_counts.ts @@ -95,7 +95,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { savedSearchesRequests?: number; setQuery: (query: string) => Promise; }) => { - it('should send 2 search requests (documents + chart) on page load', async () => { + it('should send no more than 2 search requests (documents + chart) on page load', async () => { await browser.refresh(); await browser.execute(async () => { performance.setResourceTimingBufferSize(Number.MAX_SAFE_INTEGER); @@ -105,20 +105,20 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(searchCount).to.be(2); }); - it('should send 2 requests (documents + chart) when refreshing', async () => { + it('should send no more than 2 requests (documents + chart) when refreshing', async () => { await expectSearches(type, 2, async () => { await queryBar.clickQuerySubmitButton(); }); }); - it('should send 2 requests (documents + chart) when changing the query', async () => { + it('should send no more than 2 requests (documents + chart) when changing the query', async () => { await expectSearches(type, 2, async () => { await setQuery(query1); await queryBar.clickQuerySubmitButton(); }); }); - it('should send 2 requests (documents + chart) when changing the time range', async () => { + it('should send no more than 2 requests (documents + chart) when changing the time range', async () => { await expectSearches(type, 2, async () => { await PageObjects.timePicker.setAbsoluteRange( 'Sep 21, 2015 @ 06:31:44.000', @@ -127,7 +127,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should send 2 requests (documents + chart) when toggling the chart visibility', async () => { + it('should send no more than 2 requests (documents + chart) when toggling the chart visibility', async () => { await expectSearches(type, 2, async () => { await PageObjects.discover.toggleChartVisibility(); }); @@ -136,7 +136,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should send 2 requests for saved search changes', async () => { + it('should send no more than 2 requests for saved search changes', async () => { await setQuery(query1); await queryBar.clickQuerySubmitButton(); await PageObjects.timePicker.setAbsoluteRange( @@ -181,7 +181,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { setQuery: (query) => queryBar.setQuery(query), }); - it('should send 2 requests (documents + chart) when adding a filter', async () => { + it('should send no more than 2 requests (documents + chart) when adding a filter', async () => { await expectSearches(type, 2, async () => { await filterBar.addFilter({ field: 'extension', @@ -191,31 +191,31 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); }); - it('should send 2 requests (documents + chart) when sorting', async () => { + it('should send no more than 2 requests (documents + chart) when sorting', async () => { await expectSearches(type, 2, async () => { await PageObjects.discover.clickFieldSort('@timestamp', 'Sort Old-New'); }); }); - it('should send 2 requests (documents + chart) when changing to a breakdown field without an other bucket', async () => { + it('should send no more than 2 requests (documents + chart) when changing to a breakdown field without an other bucket', async () => { await expectSearches(type, 2, async () => { await PageObjects.discover.chooseBreakdownField('type'); }); }); - it('should send 3 requests (documents + chart + other bucket) when changing to a breakdown field with an other bucket', async () => { + it('should send no more than 3 requests (documents + chart + other bucket) when changing to a breakdown field with an other bucket', async () => { await expectSearches(type, 3, async () => { await PageObjects.discover.chooseBreakdownField('extension.raw'); }); }); - it('should send 2 requests (documents + chart) when changing the chart interval', async () => { + it('should send no more than 2 requests (documents + chart) when changing the chart interval', async () => { await expectSearches(type, 2, async () => { await PageObjects.discover.setChartInterval('Day'); }); }); - it('should send 2 requests (documents + chart) when changing the data view', async () => { + it('should send no more than 2 requests (documents + chart) when changing the data view', async () => { await expectSearches(type, 2, async () => { await dataViews.switchToAndValidate('long-window-logstash-*'); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/discover/group6/_sidebar.ts b/x-pack/test_serverless/functional/test_suites/common/discover/group6/_sidebar.ts index 61cd9728223d..e7be4ab2859f 100644 --- a/x-pack/test_serverless/functional/test_suites/common/discover/group6/_sidebar.ts +++ b/x-pack/test_serverless/functional/test_suites/common/discover/group6/_sidebar.ts @@ -27,12 +27,26 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const retry = getService('retry'); const dataGrid = getService('dataGrid'); const dataViews = getService('dataViews'); + const queryBar = getService('queryBar'); + const log = getService('log'); const INITIAL_FIELD_LIST_SUMMARY = '48 available fields. 5 empty fields. 4 meta fields.'; - describe('discover sidebar', function describeIndexTests() { - // see details: https://github.com/elastic/kibana/issues/195100 - this.tags(['failsOnMKI']); + const expectFieldListDescription = async (expectedNumber: string) => { + return await retry.try(async () => { + await PageObjects.discover.waitUntilSearchingHasFinished(); + await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + const ariaDescription = await PageObjects.unifiedFieldList.getSidebarAriaDescription(); + if (ariaDescription !== expectedNumber) { + log.warning( + `Expected Sidebar Aria Description: ${expectedNumber}, got: ${ariaDescription}` + ); + await queryBar.submitQuery(); + } + expect(ariaDescription).to.be(expectedNumber); + }); + }; + describe('discover sidebar', function describeIndexTests() { before(async function () { await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); await PageObjects.svlCommonPage.loginAsAdmin(); @@ -66,36 +80,21 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); await PageObjects.unifiedFieldList.openSidebarFieldFilter(); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await testSubjects.click('typeFilter-keyword'); - - await retry.waitFor('first updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '6 available fields. 1 empty field. 3 meta fields.' - ); - }); + // first update + await expectFieldListDescription('6 available fields. 1 empty field. 3 meta fields.'); await testSubjects.click('typeFilter-number'); - await retry.waitFor('second updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '10 available fields. 3 empty fields. 4 meta fields.' - ); - }); + // second update + await expectFieldListDescription('10 available fields. 3 empty fields. 4 meta fields.'); await testSubjects.click('fieldListFiltersFieldTypeFilterClearAll'); - await retry.waitFor('reset', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - INITIAL_FIELD_LIST_SUMMARY - ); - }); + // reset + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); // TODO: ES|QL tests removed since ES|QL isn't supported in Serverless @@ -103,44 +102,23 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('search', function () { beforeEach(async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); afterEach(async () => { const fieldSearch = await testSubjects.find('clearSearchButton'); await fieldSearch.click(); - await retry.waitFor('reset', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - INITIAL_FIELD_LIST_SUMMARY - ); - }); + // reset + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should be able to search by string', async function () { await PageObjects.unifiedFieldList.findFieldByName('i'); - await retry.waitFor('first updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '28 available fields. 2 empty fields. 3 meta fields.' - ); - }); - + await expectFieldListDescription('28 available fields. 2 empty fields. 3 meta fields.'); await PageObjects.unifiedFieldList.findFieldByName('p'); - - await retry.waitFor('second updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect( (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') @@ -149,13 +127,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search by wildcard', async function () { await PageObjects.unifiedFieldList.findFieldByName('relatedContent*image'); - - await retry.waitFor('updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '2 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('2 available fields. 0 meta fields.'); expect( (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') @@ -165,12 +137,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search with spaces as wildcard', async function () { await PageObjects.unifiedFieldList.findFieldByName('relatedContent image'); - await retry.waitFor('updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect( (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') @@ -181,13 +148,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('should be able to search with fuzzy search (1 typo)', async function () { await PageObjects.unifiedFieldList.findFieldByName('rel4tedContent.art'); - - await retry.waitFor('updates', async () => { - return ( - (await PageObjects.unifiedFieldList.getSidebarAriaDescription()) === - '4 available fields. 0 meta fields.' - ); - }); + await expectFieldListDescription('4 available fields. 0 meta fields.'); expect( (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('available')).join(', ') @@ -204,9 +165,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); // expect no changes in the list - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); }); @@ -311,9 +270,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('meta')).join(', ') ).to.be('_id, _ignored, _index, _score'); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); }); it('should show field list groups excluding subfields when searched from source', async function () { @@ -354,7 +311,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('unmapped')).join(', ') ).to.be('relatedContent'); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '48 available fields. 1 unmapped field. 5 empty fields. 4 meta fields.' ); }); @@ -375,7 +332,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(availableFields.includes('extension')).to.be(true); expect(availableFields.includes('@message')).to.be(true); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '2 selected fields. 2 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); @@ -395,7 +352,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { (await PageObjects.unifiedFieldList.getSidebarSectionFieldNames('popular')).join(', ') ).to.be('@message, _id, extension'); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( + await expectFieldListDescription( '3 selected fields. 3 popular fields. 48 available fields. 5 empty fields. 4 meta fields.' ); }); @@ -408,20 +365,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); await browser.refresh(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); - + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('with-timefield'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 0 meta fields.' - ); + await expectFieldListDescription('0 available fields. 0 meta fields.'); await testSubjects.missingOrFail( `${PageObjects.unifiedFieldList.getSidebarSectionSelector('available')}-fetchWarning` ); @@ -433,12 +380,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataViews.switchToAndValidate('logstash-*'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); @@ -453,29 +395,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); await browser.refresh(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('without-timefield'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '6 available fields. 4 meta fields.' - ); + await expectFieldListDescription('6 available fields. 4 meta fields.'); await dataViews.switchToAndValidate('with-timefield'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); + await expectFieldListDescription('0 available fields. 7 empty fields. 4 meta fields.'); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 7 empty fields. 4 meta fields.' - ); await testSubjects.existOrFail( `${PageObjects.unifiedFieldList.getSidebarSectionSelector( 'available' @@ -484,12 +413,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dataViews.switchToAndValidate('logstash-*'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' @@ -501,11 +425,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should work when filters change', async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await PageObjects.unifiedFieldList.clickFieldListItem('extension'); expect(await testSubjects.getVisibleText('dscFieldStats-topValues')).to.be( @@ -516,9 +436,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); // check that the filter was passed down to the sidebar await PageObjects.unifiedFieldList.clickFieldListItem('extension'); @@ -530,31 +448,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.load( 'test/functional/fixtures/kbn_archiver/many_fields_data_view' ); - + await dataViews.switchToAndValidate('logstash-*'); await browser.refresh(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('indices-stats*'); - - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '6873 available fields. 4 meta fields.' - ); + await expectFieldListDescription('6873 available fields. 4 meta fields.'); await dataViews.switchToAndValidate('logstash-*'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/many_fields_data_view' @@ -569,12 +472,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { hasTimeField: true, }); - await PageObjects.discover.waitUntilSearchingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await PageObjects.discover.addRuntimeField( '_bytes-runtimefield', @@ -585,12 +483,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return !(await testSubjects.exists('fieldEditor')); }); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); let allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield')).to.be(true); @@ -604,23 +497,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { return !(await testSubjects.exists('fieldEditor')); }); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield2')).to.be(true); expect(allFields.includes('_bytes-runtimefield')).to.be(false); await PageObjects.discover.removeField('_bytes-runtimefield'); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_bytes-runtimefield2')).to.be(false); @@ -628,11 +511,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('should render even when retrieving documents failed with an error', async () => { - await PageObjects.header.waitUntilLoadingHasFinished(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await PageObjects.discover.addRuntimeField('_invalid-runtimefield', `emit(‘’);`); @@ -641,12 +520,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { // error in fetching documents because of the invalid runtime field await PageObjects.discover.showsErrorCallout(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - // check that the sidebar is rendered - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '49 available fields. 5 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('49 available fields. 5 empty fields. 4 meta fields.'); + let allFields = await PageObjects.unifiedFieldList.getAllFieldNames(); expect(allFields.includes('_invalid-runtimefield')).to.be(true); @@ -671,22 +547,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await kibanaServer.importExport.load( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' ); - await browser.refresh(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - INITIAL_FIELD_LIST_SUMMARY - ); + await expectFieldListDescription(INITIAL_FIELD_LIST_SUMMARY); await dataViews.switchToAndValidate('with-timefield'); - - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '0 available fields. 7 empty fields. 4 meta fields.' - ); + await expectFieldListDescription('0 available fields. 7 empty fields. 4 meta fields.'); await testSubjects.existOrFail( `${PageObjects.unifiedFieldList.getSidebarSectionSelector( 'available' @@ -698,12 +563,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'Sep 23, 2019 @ 00:00:00.000' ); - await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.unifiedFieldList.waitUntilSidebarHasLoaded(); - - expect(await PageObjects.unifiedFieldList.getSidebarAriaDescription()).to.be( - '7 available fields. 4 meta fields.' - ); + await expectFieldListDescription('7 available fields. 4 meta fields.'); await kibanaServer.importExport.unload( 'test/functional/fixtures/kbn_archiver/index_pattern_without_timefield' diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/index.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/index.ts index db5876127014..0b27d719b339 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/index.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/index.ts @@ -17,7 +17,7 @@ export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext const config = getService('config'); let remoteEsArchiver; - describe('lens serverless - group 1', function () { + describe('lens serverless - group 1 - subgroup 1', function () { this.tags(['esGate']); const esArchive = 'x-pack/test/functional/es_archives/logstash_functional'; @@ -73,9 +73,7 @@ export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext await kibanaServer.savedObjects.cleanStandardList(); }); - loadTestFile(require.resolve('./smokescreen.ts')); - loadTestFile(require.resolve('./tsdb.ts')); - loadTestFile(require.resolve('./logsdb.ts')); - loadTestFile(require.resolve('./vega_chart.ts')); + loadTestFile(require.resolve('./smokescreen.ts')); // 14m 25s + loadTestFile(require.resolve('./vega_chart.ts')); // 3m }); }; diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts index eff79084e9de..8b4a0019433b 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group3/open_in_lens/tsvb/dashboard.ts @@ -113,7 +113,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const titles = await dashboard.getPanelTitles(); expect(titles[0]).to.be(`${visTitle} (converted)`); - await panelActions.expectNotLinkedToLibrary(titles[0], true); + await panelActions.expectNotLinkedToLibrary(titles[0]); await dashboardBadgeActions.expectExistsTimeRangeBadgeAction(); await panelActions.removePanel(); }); diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group5/index.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group5/index.ts new file mode 100644 index 000000000000..4a6e7528e79a --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group5/index.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EsArchiver } from '@kbn/es-archiver'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext) => { + const browser = getService('browser'); + const log = getService('log'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['timePicker', 'svlCommonPage']); + const config = getService('config'); + let remoteEsArchiver; + + describe('lens serverless - group 1 - subgroup 5', function () { + this.tags(['esGate']); + + const esArchive = 'x-pack/test/functional/es_archives/logstash_functional'; + const localIndexPatternString = 'logstash-*'; + const remoteIndexPatternString = 'ftr-remote:logstash-*'; + const localFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/default', + }; + + const remoteFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/default', + }; + let esNode: EsArchiver; + let fixtureDirs: { + lensBasic: string; + lensDefault: string; + }; + let indexPatternString: string; + before(async () => { + log.debug('Starting lens before method'); + await browser.setWindowSize(1280, 1200); + await kibanaServer.savedObjects.cleanStandardList(); + try { + config.get('esTestCluster.ccs'); + remoteEsArchiver = getService('remoteEsArchiver' as 'esArchiver'); + esNode = remoteEsArchiver; + fixtureDirs = remoteFixtures; + indexPatternString = remoteIndexPatternString; + } catch (error) { + esNode = esArchiver; + fixtureDirs = localFixtures; + indexPatternString = localIndexPatternString; + } + + await esNode.load(esArchive); + await kibanaServer.uiSettings.update({ + defaultIndex: indexPatternString, + 'dateFormat:tz': 'UTC', + }); + await kibanaServer.importExport.load(fixtureDirs.lensBasic); + await kibanaServer.importExport.load(fixtureDirs.lensDefault); + // changing the timepicker default here saves us from having to set it in Discover (~8s) + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + }); + + after(async () => { + await esArchiver.unload(esArchive); + await PageObjects.timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.importExport.unload(fixtureDirs.lensBasic); + await kibanaServer.importExport.unload(fixtureDirs.lensDefault); + await kibanaServer.savedObjects.cleanStandardList(); + }); + + loadTestFile(require.resolve('./tsdb.ts')); // 14m 25s + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/tsdb.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group5/tsdb.ts similarity index 99% rename from x-pack/test_serverless/functional/test_suites/common/visualizations/group1/tsdb.ts rename to x-pack/test_serverless/functional/test_suites/common/visualizations/group5/tsdb.ts index 111cf30e919c..37c74a091975 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/tsdb.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group5/tsdb.ts @@ -17,7 +17,7 @@ import { getDocsGenerator, setupScenarioRunner, sumFirstNValues, -} from './tsdb_logsdb_helpers'; +} from '../tsdb_logsdb_helpers'; export default function ({ getService, getPageObjects }: FtrProviderContext) { const { common, lens, dashboard, svlCommonPage } = getPageObjects([ diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group6/index.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group6/index.ts new file mode 100644 index 000000000000..d320116aa24c --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group6/index.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { EsArchiver } from '@kbn/es-archiver'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default ({ getService, loadTestFile, getPageObjects }: FtrProviderContext) => { + const browser = getService('browser'); + const log = getService('log'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['timePicker', 'svlCommonPage']); + const config = getService('config'); + let remoteEsArchiver; + + describe('lens serverless - group 1 - subgroup 6', function () { + this.tags(['esGate']); + + const esArchive = 'x-pack/test/functional/es_archives/logstash_functional'; + const localIndexPatternString = 'logstash-*'; + const remoteIndexPatternString = 'ftr-remote:logstash-*'; + const localFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/default', + }; + + const remoteFixtures = { + lensBasic: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/lens_basic.json', + lensDefault: 'x-pack/test/functional/fixtures/kbn_archiver/lens/ccs/default', + }; + let esNode: EsArchiver; + let fixtureDirs: { + lensBasic: string; + lensDefault: string; + }; + let indexPatternString: string; + before(async () => { + log.debug('Starting lens before method'); + await browser.setWindowSize(1280, 1200); + await kibanaServer.savedObjects.cleanStandardList(); + try { + config.get('esTestCluster.ccs'); + remoteEsArchiver = getService('remoteEsArchiver' as 'esArchiver'); + esNode = remoteEsArchiver; + fixtureDirs = remoteFixtures; + indexPatternString = remoteIndexPatternString; + } catch (error) { + esNode = esArchiver; + fixtureDirs = localFixtures; + indexPatternString = localIndexPatternString; + } + + await esNode.load(esArchive); + await kibanaServer.uiSettings.update({ + defaultIndex: indexPatternString, + 'dateFormat:tz': 'UTC', + }); + await kibanaServer.importExport.load(fixtureDirs.lensBasic); + await kibanaServer.importExport.load(fixtureDirs.lensDefault); + // changing the timepicker default here saves us from having to set it in Discover (~8s) + await PageObjects.timePicker.setDefaultAbsoluteRangeViaUiSettings(); + }); + + after(async () => { + await esArchiver.unload(esArchive); + await PageObjects.timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + await kibanaServer.importExport.unload(fixtureDirs.lensBasic); + await kibanaServer.importExport.unload(fixtureDirs.lensDefault); + await kibanaServer.savedObjects.cleanStandardList(); + }); + + loadTestFile(require.resolve('./logsdb.ts')); // 28m + }); +}; diff --git a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/logsdb.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/group6/logsdb.ts similarity index 99% rename from x-pack/test_serverless/functional/test_suites/common/visualizations/group1/logsdb.ts rename to x-pack/test_serverless/functional/test_suites/common/visualizations/group6/logsdb.ts index 040490310d95..868c7ac0609e 100644 --- a/x-pack/test_serverless/functional/test_suites/common/visualizations/group1/logsdb.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/group6/logsdb.ts @@ -14,14 +14,15 @@ import { getDocsGenerator, setupScenarioRunner, TIME_PICKER_FORMAT, -} from './tsdb_logsdb_helpers'; +} from '../tsdb_logsdb_helpers'; export default function ({ getService, getPageObjects }: FtrProviderContext) { - const { common, lens, discover, header } = getPageObjects([ + const { common, lens, discover, header, svlCommonPage } = getPageObjects([ 'common', 'lens', 'discover', 'header', + 'svlCommonPage', ]); const testSubjects = getService('testSubjects'); const find = getService('find'); @@ -46,6 +47,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const toTime = 'Jun 16, 2023 @ 00:00:00.000'; before(async () => { + await svlCommonPage.loginAsAdmin(); log.info(`loading ${logsdbIndex} index...`); await esArchiver.loadIfNeeded(logsdbEsArchive); log.info(`creating a data view for "${logsdbDataView}"...`); diff --git a/x-pack/test/functional/apps/lens/group4/tsdb_logsdb_helpers.ts b/x-pack/test_serverless/functional/test_suites/common/visualizations/tsdb_logsdb_helpers.ts similarity index 99% rename from x-pack/test/functional/apps/lens/group4/tsdb_logsdb_helpers.ts rename to x-pack/test_serverless/functional/test_suites/common/visualizations/tsdb_logsdb_helpers.ts index e0169ebbae57..cf7272e6d85b 100644 --- a/x-pack/test/functional/apps/lens/group4/tsdb_logsdb_helpers.ts +++ b/x-pack/test_serverless/functional/test_suites/common/visualizations/tsdb_logsdb_helpers.ts @@ -9,7 +9,7 @@ import { Client } from '@elastic/elasticsearch'; import { MappingProperty } from '@elastic/elasticsearch/lib/api/types'; import { ToolingLog } from '@kbn/tooling-log'; import moment from 'moment'; -import type { FtrProviderContext } from '../../../ftr_provider_context'; +import { FtrProviderContext } from '../../../ftr_provider_context'; export const TEST_DOC_COUNT = 100; export const TIME_PICKER_FORMAT = 'MMM D, YYYY [@] HH:mm:ss.SSS'; diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group7.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group7.ts new file mode 100644 index 000000000000..62e1e388b95b --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group7.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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [require.resolve('../../common/visualizations/group5')], + junit: { + reportName: 'Serverless Observability Functional Tests - Common Group 7', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group8.ts b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group8.ts new file mode 100644 index 000000000000..c12a600b1d46 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/common_configs/config.group8.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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [require.resolve('../../common/visualizations/group6')], + junit: { + reportName: 'Serverless Observability Functional Tests - Common Group 8', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.telemetry.ts b/x-pack/test_serverless/functional/test_suites/observability/config.telemetry.ts new file mode 100644 index 000000000000..8779fe53c242 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/config.telemetry.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { resolve } from 'path'; +import type { GenericFtrProviderContext } from '@kbn/test'; +import { KibanaEBTUIProvider } from '@kbn/test-suites-src/analytics/services/kibana_ebt'; +import { services as inheritedServices } from '../../services'; +import { pageObjects } from '../../page_objects'; +import { createTestConfig } from '../../config.base'; + +type ObservabilityTelemetryServices = typeof inheritedServices & { + kibana_ebt_ui: typeof KibanaEBTUIProvider; +}; + +const services: ObservabilityTelemetryServices = { + ...inheritedServices, + kibana_ebt_ui: KibanaEBTUIProvider, +}; + +export type ObservabilityTelemetryFtrProviderContext = GenericFtrProviderContext< + ObservabilityTelemetryServices, + typeof pageObjects +>; + +export default createTestConfig({ + serverlessProject: 'oblt', + testFiles: [require.resolve('./index.telemetry.ts')], + junit: { + reportName: 'Serverless Observability Telemetry Functional Tests', + }, + suiteTags: { exclude: ['skipSvlOblt'] }, + services, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/observability/config/elasticsearch.yml + esServerArgs: ['xpack.ml.dfa.enabled=false'], + kbnServerArgs: [ + `--plugin-path=${resolve( + __dirname, + '../../../../../test/analytics/plugins/analytics_ftr_helpers' + )}`, + ], +}); diff --git a/x-pack/test_serverless/functional/test_suites/observability/config.ts b/x-pack/test_serverless/functional/test_suites/observability/config.ts index 41093df64097..40ca0c915d2a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/config.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/config.ts @@ -20,6 +20,7 @@ export default createTestConfig({ esServerArgs: ['xpack.ml.dfa.enabled=false'], kbnServerArgs: [ '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', // dataUsage.autoops* config is set in kibana controller '--xpack.dataUsage.autoops.enabled=true', '--xpack.dataUsage.autoops.api.url=http://localhost:9000', diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts index 0d8d8e8865d5..f4f0c8172de4 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_details.ts @@ -92,7 +92,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { getLogsForDataset({ to, count: 10, dataset: bitbucketDatasetName }), ]); - await PageObjects.svlCommonPage.loginAsAdmin(); + await PageObjects.svlCommonPage.loginAsViewer(); }); after(async () => { @@ -365,7 +365,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); }); - it('should show the degraded fields table with data when present', async () => { + it('should show the degraded fields table with data and spark plots when present', async () => { await PageObjects.datasetQuality.navigateToDetails({ dataStream: degradedDataStreamName, }); @@ -378,17 +378,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); expect(rows.length).to.eql(3); - }); - - it('should display Spark Plot for every row of degraded fields', async () => { - await PageObjects.datasetQuality.navigateToDetails({ - dataStream: degradedDataStreamName, - }); - - await PageObjects.datasetQuality.waitUntilTableLoaded(); - - const rows = - await PageObjects.datasetQuality.getDatasetQualityDetailsDegradedFieldTableRows(); const sparkPlots = await testSubjects.findAll( PageObjects.datasetQuality.testSubjectSelectors.datasetQualitySparkPlot diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts index 728fbe5dc40a..ac4a2597f3d9 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/dataset_quality_summary.ts @@ -51,7 +51,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Dataset quality summary', () => { before(async () => { await synthtrace.index(getInitialTestLogs({ to, count: 4 })); - await PageObjects.svlCommonPage.loginAsAdmin(); + await PageObjects.svlCommonPage.loginAsViewer(); await PageObjects.datasetQuality.navigateTo(); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts index 42a5a095ed6c..4b28ba5e897d 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/dataset_quality/degraded_field_flyout.ts @@ -22,6 +22,7 @@ import { logsNginxMappings } from './custom_mappings/custom_integration_mappings export default function ({ getService, getPageObjects }: FtrProviderContext) { const PageObjects = getPageObjects([ 'common', + 'header', 'navigationalSearch', 'observabilityLogsExplorer', 'datasetQuality', @@ -43,13 +44,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const customComponentTemplateName = 'logs-synth@mappings'; const nginxAccessDatasetName = 'nginx.access'; - const customComponentTemplateNameNginx = 'logs-nginx.access@custom'; + const customComponentTemplateNameNginx = `logs-${nginxAccessDatasetName}@custom`; const nginxAccessDataStreamName = `${type}-${nginxAccessDatasetName}-${defaultNamespace}`; const nginxPkg = { name: 'nginx', version: '1.23.0', }; + const apmAppDatasetName = 'apm.app.tug'; + const apmAppDataStreamName = `${type}-${apmAppDatasetName}-${defaultNamespace}`; + describe('Degraded fields flyout', () => { describe('degraded field flyout open-close', () => { before(async () => { @@ -182,6 +186,29 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { .timestamp(timestamp) ); }), + // Ingest Degraded Logs with 26 fields in Apm DataSet + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return Array(1) + .fill(0) + .flatMap(() => + log + .create() + .dataset(apmAppDatasetName) + .message('a log message') + .logLevel(MORE_THAN_1024_CHARS) + .service(serviceName) + .namespace(defaultNamespace) + .defaults({ + 'service.name': serviceName, + 'trace.id': generateShortId(), + test_field: [MORE_THAN_1024_CHARS, ANOTHER_1024_CHARS], + }) + .timestamp(timestamp) + ); + }), ]); // Set Limit of 25 @@ -197,6 +224,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { 'mapping.total_fields.limit': 42, }); + // Set Limit of 26 + await PageObjects.datasetQuality.setDataStreamSettings(apmAppDataStreamName, { + 'mapping.total_fields.limit': 25, + }); + await synthtrace.index([ // Ingest Degraded Logs with 26 field timerange(moment(to).subtract(count, 'minute'), moment(to)) @@ -246,11 +278,36 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { .timestamp(timestamp) ); }), + // Ingest Degraded Logs with 27 fields in Apm APP DataSet + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return Array(1) + .fill(0) + .flatMap(() => + log + .create() + .dataset(apmAppDatasetName) + .message('a log message') + .logLevel(MORE_THAN_1024_CHARS) + .service(serviceName) + .namespace(defaultNamespace) + .defaults({ + 'service.name': serviceName, + 'trace.id': generateShortId(), + test_field: [MORE_THAN_1024_CHARS, ANOTHER_1024_CHARS], + 'cloud.project.id': generateShortId(), + }) + .timestamp(timestamp) + ); + }), ]); // Rollover Datastream to reset the limit to default which is 1000 await PageObjects.datasetQuality.rolloverDataStream(degradedDatasetWithLimitDataStreamName); await PageObjects.datasetQuality.rolloverDataStream(nginxAccessDataStreamName); + await PageObjects.datasetQuality.rolloverDataStream(apmAppDataStreamName); // Set Limit of 26 await PageObjects.datasetQuality.setDataStreamSettings( @@ -272,6 +329,16 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { } ); + // Set Limit of 27 + await PageObjects.datasetQuality.setDataStreamSettings( + PageObjects.datasetQuality.generateBackingIndexNameWithoutVersion({ + dataset: apmAppDatasetName, + }) + '-000002', + { + 'mapping.total_fields.limit': 27, + } + ); + await synthtrace.index([ // Ingest Degraded Logs with 26 field timerange(moment(to).subtract(count, 'minute'), moment(to)) @@ -321,6 +388,30 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { .timestamp(timestamp) ); }), + // Ingest Degraded Logs with 27 fields in Apm APP DataSet + timerange(moment(to).subtract(count, 'minute'), moment(to)) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return Array(1) + .fill(0) + .flatMap(() => + log + .create() + .dataset(apmAppDatasetName) + .message('a log message') + .logLevel(MORE_THAN_1024_CHARS) + .service(serviceName) + .namespace(defaultNamespace) + .defaults({ + 'service.name': serviceName, + 'trace.id': generateShortId(), + test_field: [MORE_THAN_1024_CHARS, ANOTHER_1024_CHARS], + 'cloud.project.id': generateShortId(), + }) + .timestamp(timestamp) + ); + }), ]); await PageObjects.svlCommonPage.loginAsAdmin(); }); @@ -452,6 +543,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'test_field', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.tryForTime(5000, async () => { const fieldIgnoredMessageExists = await PageObjects.datasetQuality.doesTextExist( 'datasetQualityDetailsDegradedFieldFlyoutFieldValue-cause', @@ -469,6 +562,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'test_field', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.tryForTime(5000, async () => { const testFieldValue1Exists = await PageObjects.datasetQuality.doesTextExist( 'datasetQualityDetailsDegradedFieldFlyoutFieldValue-values', @@ -491,6 +586,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'test_field', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.tryForTime(5000, async () => { const limitValueExists = await PageObjects.datasetQuality.doesTextExist( 'datasetQualityDetailsDegradedFieldFlyoutFieldValue-characterLimit', @@ -508,6 +605,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'test_field', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + // Possible Mitigation Section should exist await testSubjects.existOrFail( 'datasetQualityDetailsDegradedFieldFlyoutPossibleMitigationTitle' @@ -567,6 +666,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'test_field', }); + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.datasetQuality.waitUntilPossibleMitigationsLoaded(); // Possible Mitigation Section should exist @@ -632,6 +732,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.tryForTime(5000, async () => { const fieldLimitMessageExists = await PageObjects.datasetQuality.doesTextExist( 'datasetQualityDetailsDegradedFieldFlyoutFieldValue-cause', @@ -649,6 +751,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.tryForTime(5000, async () => { const limitExists = await PageObjects.datasetQuality.doesTextExist( 'datasetQualityDetailsDegradedFieldFlyoutFieldValue-mappingLimit', @@ -666,6 +770,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await testSubjects.existOrFail( PageObjects.datasetQuality.testSubjectSelectors .datasetQualityDetailsDegradedFieldFlyoutIssueDoesNotExist @@ -680,6 +786,38 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud.project.id', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + + // Field Limit Mitigation Section should exist + await testSubjects.existOrFail( + 'datasetQualityDetailsDegradedFieldFlyoutFieldLimitMitigationAccordion' + ); + + // Should display the panel to increase field limit + await testSubjects.existOrFail( + 'datasetQualityDetailsDegradedFieldFlyoutIncreaseFieldLimitPanel' + ); + + // Should display official online documentation link + await testSubjects.existOrFail( + 'datasetQualityManualMitigationsPipelineOfficialDocumentationLink' + ); + + const linkButton = await testSubjects.find( + 'datasetQualityManualMitigationsPipelineOfficialDocumentationLink' + ); + + const linkURL = await linkButton.getAttribute('href'); + + expect(linkURL?.endsWith('mapping-settings-limit.html')).to.be(true); + }); + + it('should display increase field limit as a possible mitigation for special packages like apm app', async () => { + await PageObjects.datasetQuality.navigateToDetails({ + dataStream: apmAppDataStreamName, + expandedDegradedField: 'cloud.project', + }); + // Field Limit Mitigation Section should exist await testSubjects.existOrFail( 'datasetQualityDetailsDegradedFieldFlyoutFieldLimitMitigationAccordion' @@ -710,6 +848,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud.project', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + // Field Limit Mitigation Section should exist await testSubjects.existOrFail( 'datasetQualityDetailsDegradedFieldFlyoutFieldLimitMitigationAccordion' @@ -732,6 +872,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud.project.id', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + // Should display current field limit await testSubjects.existOrFail('datasetQualityIncreaseFieldMappingCurrentLimitFieldText'); @@ -765,10 +907,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(newFieldLimit).to.be(newLimit); // Should display the apply button - await testSubjects.existOrFail('datasetQualityIncreaseFieldMappingLimitButtonButton'); + await testSubjects.existOrFail('datasetQualityIncreaseFieldMappingLimitButton'); const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); const applyButtonDisabledStatus = await applyButton.getAttribute('disabled'); @@ -782,6 +924,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud.project.id', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + // Should not allow values less than current limit of 44 await testSubjects.setValue( 'datasetQualityIncreaseFieldMappingProposedLimitFieldText', @@ -793,7 +937,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { ); const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); const applyButtonDisabledStatus = await applyButton.getAttribute('disabled'); @@ -816,9 +960,11 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud.project.id', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + await retry.tryForTime(5000, async () => { const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); await applyButton.click(); @@ -835,8 +981,10 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expandedDegradedField: 'cloud.project.id', }); + await PageObjects.header.waitUntilLoadingHasFinished(); + const applyButton = await testSubjects.find( - 'datasetQualityIncreaseFieldMappingLimitButtonButton' + 'datasetQualityIncreaseFieldMappingLimitButton' ); await applyButton.click(); diff --git a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_app_menu.ts b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_app_menu.ts index 2be17df28d12..fdbc0e6c110a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_app_menu.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_app_menu.ts @@ -25,7 +25,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('extension getAppMenu', () => { before(async () => { - await svlCommonPage.loginAsAdmin(); + await svlCommonPage.loginAsViewer(); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_cell_renderers.ts b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_cell_renderers.ts index 4fb26ff1a23d..19845d332a73 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_cell_renderers.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_cell_renderers.ts @@ -28,7 +28,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('extension getCellRenderers', () => { before(async () => { - await PageObjects.svlCommonPage.loginAsAdmin(); + await PageObjects.svlCommonPage.loginAsViewer(); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_doc_viewer.ts b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_doc_viewer.ts index adc466f238a5..ed021246b109 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_doc_viewer.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_doc_viewer.ts @@ -17,7 +17,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('extension getDocViewer', () => { before(async () => { - await PageObjects.svlCommonPage.loginAsAdmin(); + await PageObjects.svlCommonPage.loginAsViewer(); }); describe('ES|QL mode', () => { diff --git a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_row_indicator_provider.ts b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_row_indicator_provider.ts index ddc3c1827055..2c7338627ddf 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_row_indicator_provider.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/_get_row_indicator_provider.ts @@ -26,7 +26,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('extension getRowIndicatorProvider', () => { before(async () => { - await PageObjects.svlCommonPage.loginAsAdmin(); + await PageObjects.svlCommonPage.loginAsViewer(); await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/telemetry/_telemetry.ts b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/telemetry/_telemetry.ts new file mode 100644 index 000000000000..cc0b7c25abb3 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/telemetry/_telemetry.ts @@ -0,0 +1,339 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import expect from '@kbn/expect'; +import type { ObservabilityTelemetryFtrProviderContext } from '../../../config.telemetry'; + +export default function ({ getService, getPageObjects }: ObservabilityTelemetryFtrProviderContext) { + const { common, discover, unifiedFieldList, dashboard, header, timePicker, svlCommonPage } = + getPageObjects([ + 'common', + 'discover', + 'unifiedFieldList', + 'dashboard', + 'header', + 'timePicker', + 'svlCommonPage', + ]); + const testSubjects = getService('testSubjects'); + const dataGrid = getService('dataGrid'); + const dataViews = getService('dataViews'); + const monacoEditor = getService('monacoEditor'); + const ebtUIHelper = getService('kibana_ebt_ui'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const dashboardAddPanel = getService('dashboardAddPanel'); + const browser = getService('browser'); + + describe('telemetry', () => { + describe('context', () => { + before(async () => { + await svlCommonPage.loginAsAdmin(); + await esArchiver.loadIfNeeded('test/functional/fixtures/es_archiver/logstash_functional'); + await kibanaServer.importExport.load('test/functional/fixtures/kbn_archiver/discover'); + }); + + after(async () => { + await kibanaServer.importExport.unload('test/functional/fixtures/kbn_archiver/discover'); + }); + + it('should set EBT context for telemetry events with o11y root profile', async () => { + await common.navigateToApp('discover'); + await discover.selectTextBaseLang(); + await discover.waitUntilSearchingHasFinished(); + await monacoEditor.setCodeEditorValue('from my-example-* | sort @timestamp desc'); + await ebtUIHelper.setOptIn(true); + await testSubjects.click('querySubmitButton'); + await discover.waitUntilSearchingHasFinished(); + + const events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['performance_metric'], + withTimeoutMs: 500, + }); + + expect(events[events.length - 1].context.discoverProfiles).to.eql([ + 'observability-root-profile', + 'default-data-source-profile', + ]); + }); + + it('should set EBT context for telemetry events when logs data source profile and reset', async () => { + await common.navigateToApp('discover'); + await discover.selectTextBaseLang(); + await discover.waitUntilSearchingHasFinished(); + await monacoEditor.setCodeEditorValue('from my-example-logs | sort @timestamp desc'); + await ebtUIHelper.setOptIn(true); + await testSubjects.click('querySubmitButton'); + await discover.waitUntilSearchingHasFinished(); + + const events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['performance_metric'], + withTimeoutMs: 500, + }); + + expect(events[events.length - 1].context.discoverProfiles).to.eql([ + 'observability-root-profile', + 'observability-logs-data-source-profile', + ]); + + // should reset the profiles when navigating away from Discover + await common.navigateToApp('home'); + await retry.waitFor('home page to open', async () => { + return await testSubjects.exists('homeApp'); + }); + await testSubjects.click('addSampleData'); + + await retry.try(async () => { + const eventsAfter = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['click'], + withTimeoutMs: 500, + }); + + expect(eventsAfter[eventsAfter.length - 1].context.discoverProfiles).to.eql([]); + }); + }); + + it('should not set EBT context for embeddables', async () => { + await dashboard.navigateToApp(); + await dashboard.gotoDashboardLandingPage(); + await dashboard.clickNewDashboard(); + await timePicker.setDefaultAbsoluteRange(); + await ebtUIHelper.setOptIn(true); + await dashboardAddPanel.addSavedSearch('A Saved Search'); + await header.waitUntilLoadingHasFinished(); + await dashboard.waitForRenderComplete(); + const rows = await dataGrid.getDocTableRows(); + expect(rows.length).to.be.above(0); + await testSubjects.click('dashboardEditorMenuButton'); + + const events = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['click'], + withTimeoutMs: 500, + }); + + expect( + events.length > 0 && + events.every((event) => !(event.context.discoverProfiles as string[])?.length) + ).to.be(true); + }); + }); + + describe('events', () => { + beforeEach(async () => { + await common.navigateToApp('discover'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + }); + + it('should track field usage when a field is added to the table', async () => { + await dataViews.switchToAndValidate('my-example-*'); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await ebtUIHelper.setOptIn(true); + await unifiedFieldList.clickFieldListItemAdd('service.name'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + + const [event] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event.properties).to.eql({ + eventName: 'dataTableSelection', + fieldName: 'service.name', + }); + + await unifiedFieldList.clickFieldListItemAdd('_score'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + + const [_, event2] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event2.properties).to.eql({ + eventName: 'dataTableSelection', + }); + }); + + it('should track field usage when a field is removed from the table', async () => { + await dataViews.switchToAndValidate('my-example-logs'); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await unifiedFieldList.clickFieldListItemAdd('log.level'); + await browser.refresh(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await ebtUIHelper.setOptIn(true); + await unifiedFieldList.clickFieldListItemRemove('log.level'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + + const [event] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event.properties).to.eql({ + eventName: 'dataTableRemoval', + fieldName: 'log.level', + }); + }); + + it('should track field usage when a filter is added', async () => { + await dataViews.switchToAndValidate('my-example-logs'); + await discover.waitUntilSearchingHasFinished(); + await ebtUIHelper.setOptIn(true); + await dataGrid.clickCellFilterForButtonExcludingControlColumns(0, 0); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + + const [event] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event.properties).to.eql({ + eventName: 'filterAddition', + fieldName: '@timestamp', + filterOperation: '+', + }); + + await unifiedFieldList.clickFieldListExistsFilter('log.level'); + + const [_, event2] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event2.properties).to.eql({ + eventName: 'filterAddition', + fieldName: 'log.level', + filterOperation: '_exists_', + }); + }); + + it('should track field usage for doc viewer too', async () => { + await dataViews.switchToAndValidate('my-example-logs'); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await unifiedFieldList.clickFieldListItemAdd('log.level'); + await browser.refresh(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await ebtUIHelper.setOptIn(true); + + await dataGrid.clickRowToggle(); + await discover.isShowingDocViewer(); + + // event 1 + await dataGrid.clickFieldActionInFlyout('service.name', 'toggleColumnButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + // event 2 + await dataGrid.clickFieldActionInFlyout('log.level', 'toggleColumnButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + // event 3 + await dataGrid.clickFieldActionInFlyout('log.level', 'addFilterOutValueButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + const [event1, event2, event3] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event1.properties).to.eql({ + eventName: 'dataTableSelection', + fieldName: 'service.name', + }); + + expect(event2.properties).to.eql({ + eventName: 'dataTableRemoval', + fieldName: 'log.level', + }); + + expect(event3.properties).to.eql({ + eventName: 'filterAddition', + fieldName: 'log.level', + filterOperation: '-', + }); + }); + + it('should track field usage on surrounding documents page', async () => { + await dataViews.switchToAndValidate('my-example-logs'); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await unifiedFieldList.clickFieldListItemAdd('log.level'); + await browser.refresh(); + await discover.waitUntilSearchingHasFinished(); + await unifiedFieldList.waitUntilSidebarHasLoaded(); + await dataGrid.clickRowToggle({ rowIndex: 1 }); + await discover.isShowingDocViewer(); + + const [, surroundingActionEl] = await dataGrid.getRowActions(); + await surroundingActionEl.click(); + await header.waitUntilLoadingHasFinished(); + await ebtUIHelper.setOptIn(true); + + await dataGrid.clickRowToggle({ rowIndex: 0 }); + await discover.isShowingDocViewer(); + + // event 1 + await dataGrid.clickFieldActionInFlyout('service.name', 'toggleColumnButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + // event 2 + await dataGrid.clickFieldActionInFlyout('log.level', 'toggleColumnButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + // event 3 + await dataGrid.clickFieldActionInFlyout('log.level', 'addFilterOutValueButton'); + await header.waitUntilLoadingHasFinished(); + await discover.waitUntilSearchingHasFinished(); + + const [event1, event2, event3] = await ebtUIHelper.getEvents(Number.MAX_SAFE_INTEGER, { + eventTypes: ['discover_field_usage'], + withTimeoutMs: 500, + }); + + expect(event1.properties).to.eql({ + eventName: 'dataTableSelection', + fieldName: 'service.name', + }); + + expect(event2.properties).to.eql({ + eventName: 'dataTableRemoval', + fieldName: 'log.level', + }); + + expect(event3.properties).to.eql({ + eventName: 'filterAddition', + fieldName: 'log.level', + filterOperation: '-', + }); + + expect(event3.context.discoverProfiles).to.eql([ + 'observability-root-profile', + 'observability-logs-data-source-profile', + ]); + }); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/telemetry/index.ts b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/telemetry/index.ts new file mode 100644 index 000000000000..48ce02d1735c --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/discover/context_awareness/telemetry/index.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ObservabilityTelemetryFtrProviderContext } from '../../../config.telemetry'; + +export default function ({ + getService, + getPageObjects, + loadTestFile, +}: ObservabilityTelemetryFtrProviderContext) { + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['timePicker', 'svlCommonPage']); + const from = '2024-06-10T14:00:00.000Z'; + const to = '2024-06-10T16:30:00.000Z'; + + describe('discover/observabilitySolution/context_awareness/telemetry', function () { + before(async () => { + await esArchiver.load('test/functional/fixtures/es_archiver/discover/context_awareness'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/discover/context_awareness' + ); + await kibanaServer.uiSettings.update({ + 'timepicker:timeDefaults': `{ "from": "${from}", "to": "${to}"}`, + }); + }); + + after(async () => { + await esArchiver.unload('test/functional/fixtures/es_archiver/discover/context_awareness'); + await kibanaServer.importExport.unload( + 'test/functional/fixtures/kbn_archiver/discover/context_awareness' + ); + await PageObjects.timePicker.resetDefaultAbsoluteRangeViaUiSettings(); + }); + + loadTestFile(require.resolve('./_telemetry')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/index.telemetry.ts b/x-pack/test_serverless/functional/test_suites/observability/index.telemetry.ts new file mode 100644 index 000000000000..0639465db60e --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/index.telemetry.ts @@ -0,0 +1,16 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { ObservabilityTelemetryFtrProviderContext } from './config.telemetry'; + +export default function ({ loadTestFile }: ObservabilityTelemetryFtrProviderContext) { + describe('serverless observability UI - telemetry', function () { + this.tags(['skipMKI', 'esGate']); + + loadTestFile(require.resolve('./discover/context_awareness/telemetry')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/header_menu.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/header_menu.ts deleted file mode 100644 index 775055825d2e..000000000000 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/header_menu.ts +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { FtrProviderContext } from '../../../ftr_provider_context'; - -import { HOSTS_VIEW_PATH } from './constants'; - -export default ({ getPageObjects, getService }: FtrProviderContext) => { - const esArchiver = getService('esArchiver'); - const pageObjects = getPageObjects(['svlCommonPage', 'common', 'infraHome', 'header']); - - // failing feature flag test, see https://github.com/elastic/kibana/issues/191809 - describe.skip('Header menu', () => { - before(async () => { - await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - await pageObjects.svlCommonPage.loginAsViewer(); - }); - - after(async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); - }); - - describe('Alerts dropdown', () => { - beforeEach(async () => { - await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); - await pageObjects.header.waitUntilLoadingHasFinished(); - }); - - it('is hidden', async () => { - await pageObjects.infraHome.ensureAlertsAndRulesDropdownIsMissing(); - }); - }); - }); -}; diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts index 808b07989646..f6acf29cb3a9 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/hosts_page.ts @@ -40,28 +40,22 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { (await pageObjects.infraHostsView.isKPIChartsLoaded()) ); - // failing feature flag test, see https://github.com/elastic/kibana/issues/191810 - describe.skip('Hosts Page', function () { + describe('Hosts Page', function () { before(async () => { - await Promise.all([ - esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'), - ]); + await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); await pageObjects.svlCommonPage.loginAsViewer(); - await browser.setWindowSize(1600, 1200); + + await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); + await pageObjects.header.waitUntilLoadingHasFinished(); + + await browser.setWindowSize(1600, 1400); }); after(async () => { - await Promise.all([ - esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'), - ]); + await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs'); }); describe('#Single Host Flyout', () => { - before(async () => { - await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); - await pageObjects.header.waitUntilLoadingHasFinished(); - }); - describe('Tabs', () => { before(async () => { await pageObjects.timePicker.setAbsoluteRange( @@ -100,10 +94,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should show alerts', async () => { await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.assetDetails.overviewAlertsTitleExists(); - const CreateRuleButtonExist = await testSubjects.exists( - 'infraAssetDetailsCreateAlertsRuleButton' - ); - expect(CreateRuleButtonExist).to.be(true); + await pageObjects.assetDetails.overviewOpenAlertsFlyoutExist(); }); }); @@ -123,7 +114,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); it('should show processes title', async () => { - await await testSubjects.existOrFail('infraAssetDetailsTopProcessesTitle'); + await testSubjects.existOrFail('infraAssetDetailsTopProcessesTitle'); }); }); @@ -175,7 +166,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Metrics Tab', () => { before(async () => { - await browser.scrollTop(); await pageObjects.infraHostsView.visitMetricsTab(); }); @@ -191,7 +181,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Logs Tab', () => { before(async () => { - await browser.scrollTop(); await pageObjects.infraHostsView.visitLogsTab(); }); @@ -206,7 +195,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Alerts Tab', () => { before(async () => { - await browser.scrollTop(); await pageObjects.infraHostsView.visitAlertTab(); }); diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts index b646ba71f960..914f7760f900 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts @@ -9,7 +9,6 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Observability Infra', function () { - loadTestFile(require.resolve('./header_menu')); loadTestFile(require.resolve('./navigation')); loadTestFile(require.resolve('./node_details')); loadTestFile(require.resolve('./hosts_page')); diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/node_details.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/node_details.ts index 25d30117ad6b..254bf9e555a1 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/node_details.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/node_details.ts @@ -30,8 +30,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { 'svlCommonPage', ]); - // failing feature flag test, see https://github.com/elastic/kibana/issues/191809 - describe.skip('Node Details', () => { + describe('Node Details', () => { describe('#With Asset Details', () => { before(async () => { await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs'); @@ -50,7 +49,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { describe('Osquery Tab', () => { it('should not render in serverless', async () => { const OsqueryExist = await testSubjects.exists('infraAssetDetailsOsqueryTab'); - expect(OsqueryExist).to.be(false); + expect(OsqueryExist).to.be(true); }); }); @@ -68,10 +67,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('should show alerts', async () => { await pageObjects.header.waitUntilLoadingHasFinished(); await pageObjects.assetDetails.overviewAlertsTitleExists(); - const CreateRuleButtonExist = await testSubjects.exists( - 'infraAssetDetailsCreateAlertsRuleButton' - ); - expect(CreateRuleButtonExist).to.be(true); + await pageObjects.assetDetails.overviewOpenAlertsFlyoutExist(); }); [ diff --git a/x-pack/test_serverless/functional/test_suites/observability/ml/anomaly_detection_jobs_list.ts b/x-pack/test_serverless/functional/test_suites/observability/ml/anomaly_detection_jobs_list.ts index bdd5d443b359..8073a7c5fcc7 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/ml/anomaly_detection_jobs_list.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/ml/anomaly_detection_jobs_list.ts @@ -31,7 +31,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { - await ml.api.cleanMlIndices(); + await ml.api.cleanAnomalyDetection(); await ml.testResources.cleanMLSavedObjects(); await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.savedObjects.cleanStandardList(); diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group7.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group7.ts new file mode 100644 index 000000000000..723c9ac2c45a --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group7.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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [require.resolve('../../common/visualizations/group5')], + junit: { + reportName: 'Serverless Search Functional Tests - Common Group 7', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group8.ts b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group8.ts new file mode 100644 index 000000000000..521691ffabd8 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/common_configs/config.group8.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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [require.resolve('../../common/visualizations/group6')], + junit: { + reportName: 'Serverless Search Functional Tests - Common Group 8', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/search/config.ts b/x-pack/test_serverless/functional/test_suites/search/config.ts index 5c52828a1165..dbf69f1c7091 100644 --- a/x-pack/test_serverless/functional/test_suites/search/config.ts +++ b/x-pack/test_serverless/functional/test_suites/search/config.ts @@ -23,6 +23,7 @@ export default createTestConfig({ `--xpack.cloud.serverless.project_name=ES3_FTR_TESTS`, `--xpack.cloud.deployment_url=/projects/elasticsearch/fakeprojectid`, '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', // dataUsage.autoops* config is set in kibana controller '--xpack.dataUsage.autoops.enabled=true', '--xpack.dataUsage.autoops.api.url=http://localhost:9000', @@ -45,5 +46,8 @@ export default createTestConfig({ elasticsearchIndices: { pathname: '/app/elasticsearch/indices', }, + searchInferenceEndpoints: { + pathname: '/app/elasticsearch/relevance/inference_endpoints', + }, }, }); diff --git a/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts b/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts index 8f97f53c6275..aefd4c6da983 100644 --- a/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts +++ b/x-pack/test_serverless/functional/test_suites/search/dashboards/build_dashboard.ts @@ -56,7 +56,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { it('can edit a Lens panel by value and save changes', async () => { await PageObjects.dashboard.waitForRenderComplete(); - await dashboardPanelActions.clickEdit(); + await dashboardPanelActions.navigateToEditorFromFlyout(); await PageObjects.lens.switchToVisualization('pie'); await PageObjects.lens.saveAndReturn(); await PageObjects.dashboard.waitForRenderComplete(); diff --git a/x-pack/test_serverless/functional/test_suites/search/index.ts b/x-pack/test_serverless/functional/test_suites/search/index.ts index 99190ae0cc07..dd7021aebe80 100644 --- a/x-pack/test_serverless/functional/test_suites/search/index.ts +++ b/x-pack/test_serverless/functional/test_suites/search/index.ts @@ -28,5 +28,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./search_playground/playground_overview')); loadTestFile(require.resolve('./ml')); loadTestFile(require.resolve('./custom_role_access')); + loadTestFile(require.resolve('./inference_management')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/search/inference_management.ts b/x-pack/test_serverless/functional/test_suites/search/inference_management.ts new file mode 100644 index 000000000000..5293655ef092 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/search/inference_management.ts @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; + +import { testHasEmbeddedConsole } from './embedded_console'; + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const pageObjects = getPageObjects([ + 'svlCommonPage', + 'embeddedConsole', + 'svlSearchInferenceManagementPage', + 'header', + ]); + const svlSearchNavigation = getService('svlSearchNavigation'); + const browser = getService('browser'); + const ml = getService('ml'); + + describe('Serverless Inference Management UI', function () { + const endpoint = 'endpoint-1'; + const taskType = 'sparse_embedding'; + const modelConfig = { + service: 'elser', + service_settings: { + num_allocations: 1, + num_threads: 1, + }, + }; + + before(async () => { + await pageObjects.svlCommonPage.loginWithRole('developer'); + }); + + after(async () => { + await ml.api.cleanMlIndices(); + }); + + beforeEach(async () => { + await svlSearchNavigation.navigateToInferenceManagementPage(); + }); + + describe('endpoint tabular view', () => { + it('is loaded successfully', async () => { + await pageObjects.svlSearchInferenceManagementPage.InferenceTabularPage.expectHeaderToBeExist(); + await pageObjects.svlSearchInferenceManagementPage.InferenceTabularPage.expectTabularViewToBeLoaded(); + }); + + it('preconfigured endpoints can not be deleted', async () => { + await pageObjects.svlSearchInferenceManagementPage.InferenceTabularPage.expectPreconfiguredEndpointsCannotBeDeleted(); + }); + }); + + describe('copy endpoint id action', () => { + it('can copy an endpoint id', async () => { + await pageObjects.svlSearchInferenceManagementPage.InferenceTabularPage.expectToCopyEndpoint(); + }); + }); + + describe('delete action', () => { + const usageIndex = 'elser_index'; + beforeEach(async () => { + await ml.api.createInferenceEndpoint(endpoint, taskType, modelConfig); + await browser.refresh(); + await pageObjects.header.waitUntilLoadingHasFinished(); + }); + + after(async () => { + await ml.api.deleteIndices(usageIndex); + await ml.api.deleteIngestPipeline(endpoint); + }); + + it('deletes modal successfully without any usage', async () => { + await pageObjects.svlSearchInferenceManagementPage.InferenceTabularPage.expectEndpointWithoutUsageTobeDelete(); + }); + + it('deletes modal successfully with usage', async () => { + const indexMapping: estypes.MappingTypeMapping = { + properties: { + content: { + type: 'text', + }, + content_embedding: { + type: 'semantic_text', + inference_id: endpoint, + }, + }, + }; + await ml.api.createIngestPipeline(endpoint); + await ml.api.createIndex(usageIndex, indexMapping); + + await pageObjects.svlSearchInferenceManagementPage.InferenceTabularPage.expectEndpointWithUsageTobeDelete(); + }); + }); + + it('has embedded dev console', async () => { + await testHasEmbeddedConsole(pageObjects); + }); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index 24009866b2b1..74d1c59cbc8e 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -95,17 +95,17 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { }); // check Relevance // > Inference Endpoints - // await solutionNavigation.sidenav.clickLink({ - // deepLinkId: 'searchInferenceEndpoints', - // }); - // await solutionNavigation.sidenav.expectLinkActive({ - // deepLinkId: 'searchInferenceEndpoints', - // }); - // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Relevance' }); - // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Inference Endpoints' }); - // await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - // deepLinkId: 'searchInferenceEndpoints', - // }); + await solutionNavigation.sidenav.clickLink({ + deepLinkId: 'searchInferenceEndpoints', + }); + await solutionNavigation.sidenav.expectLinkActive({ + deepLinkId: 'searchInferenceEndpoints', + }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Relevance' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Inference Endpoints' }); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + deepLinkId: 'searchInferenceEndpoints', + }); // check Analyze // > Discover @@ -245,8 +245,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await solutionNavigation.sidenav.expectLinkExists({ text: 'Build' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Dev Tools' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Playground' }); - // await solutionNavigation.sidenav.expectLinkExists({ text: 'Relevance' }); - // await solutionNavigation.sidenav.expectLinkExists({ text: 'Inference Endpoints' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Relevance' }); + await solutionNavigation.sidenav.expectLinkExists({ text: 'Inference Endpoints' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Analyze' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Discover' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Dashboards' }); @@ -270,8 +270,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { 'build', 'dev_tools', 'searchPlayground', - // 'relevance', - // 'searchInferenceEndpoints', + 'relevance', + 'searchInferenceEndpoints', 'analyze', 'discover', 'dashboards', diff --git a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts index 5aa2627a3cdf..097da2201e1e 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_index_detail.ts @@ -54,12 +54,15 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchIndexDetailPage.expectConnectionDetails(); }); - it.skip('should show api key', async () => { - await pageObjects.svlApiKeys.deleteAPIKeys(); - await svlSearchNavigation.navigateToIndexDetailPage(indexName); - await pageObjects.svlApiKeys.expectAPIKeyAvailable(); - const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); - await pageObjects.svlSearchIndexDetailPage.expectAPIKeyToBeVisibleInCodeBlock(apiKey); + describe.skip('API key details', () => { + // Flaky test related with deleting API keys + it('should show api key', async () => { + await pageObjects.svlApiKeys.deleteAPIKeys(); + await svlSearchNavigation.navigateToIndexDetailPage(indexName); + await pageObjects.svlApiKeys.expectAPIKeyAvailable(); + const apiKey = await pageObjects.svlApiKeys.getAPIKeyFromUI(); + await pageObjects.svlSearchIndexDetailPage.expectAPIKeyToBeVisibleInCodeBlock(apiKey); + }); }); it('should have quick stats', async () => { @@ -107,11 +110,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.embeddedConsole.clickEmbeddedConsoleControlBar(); }); - // FLAKY: https://github.com/elastic/kibana/issues/197144 - describe.skip('With data', () => { + describe('With data', () => { before(async () => { await es.index({ index: indexName, + refresh: true, body: { my_field: [1, 0, 1], }, @@ -305,6 +308,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.svlSearchIndexDetailPage.expectDeleteIndexButtonExistsInMoreOptions(); await pageObjects.svlSearchIndexDetailPage.expectDeleteIndexButtonToBeDisabled(); }); + it('show no privileges to create api key', async () => { + await pageObjects.svlApiKeys.expectAPIKeyNoPrivileges(); + }); }); }); }); diff --git a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts index 946afe08a0b7..9e1e36d10b17 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts @@ -106,7 +106,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { }); describe('without any indices', () => { - it('hide no create index button when index added', async () => { + it('hide create index button when index added', async () => { await createIndex(); await pageObjects.searchPlayground.PlaygroundStartChatPage.expectOpenFlyoutAndSelectIndex(); }); @@ -121,6 +121,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { before(async () => { await createConnector(); await createIndex(); + }); + + beforeEach(async () => { await pageObjects.searchPlayground.session.setSession(); await browser.refresh(); }); @@ -129,6 +132,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.searchPlayground.PlaygroundStartChatPage.expectToSelectIndicesAndLoadChat(); }); + it('load start page after removing selected index', async () => { + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectToSelectIndicesAndLoadChat(); + await esArchiver.unload(esArchiveIndex); + await browser.refresh(); + await pageObjects.searchPlayground.PlaygroundStartChatPage.expectCreateIndexButtonToExists(); + }); + after(async () => { await removeOpenAIConnector?.(); await esArchiver.unload(esArchiveIndex); diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group7.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group7.ts new file mode 100644 index 000000000000..2239eb67441d --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group7.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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [require.resolve('../../common/visualizations/group5')], + junit: { + reportName: 'Serverless Security Functional Tests - Common Group 7', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group8.ts b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group8.ts new file mode 100644 index 000000000000..0089206ce72f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/common_configs/config.group8.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 { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseTestConfig = await readConfigFile(require.resolve('../config.ts')); + + return { + ...baseTestConfig.getAll(), + testFiles: [require.resolve('../../common/visualizations/group6')], + junit: { + reportName: 'Serverless Security Functional Tests - Common Group 8', + }, + }; +} diff --git a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts index 692ae096265f..b203bc6427ed 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless.ts @@ -16,6 +16,8 @@ export default createTestConfig({ reportName: 'Serverless Security Cloud Security Agentless Onboarding Functional Tests', }, kbnServerArgs: [ + `--xpack.cloud.serverless.project_id=some_fake_project_id`, + `--xpack.fleet.packages.0.name=cloud_security_posture`, `--xpack.fleet.packages.0.version=${CLOUD_CREDENTIALS_PACKAGE_VERSION}`, `--xpack.fleet.agentless.enabled=true`, @@ -26,11 +28,10 @@ export default createTestConfig({ `--xpack.fleet.agentPolicies.0.id=agentless`, `--xpack.fleet.agentPolicies.0.name=agentless`, `--xpack.fleet.agentPolicies.0.package_policies=[]`, - `--xpack.cloud.serverless.project_id=some_fake_project_id`, `--xpack.fleet.agentPolicies.0.is_default=true`, `--xpack.fleet.agentPolicies.0.is_default_fleet_server=true`, - // Serverless Agentless API + `--xpack.fleet.agentless.enabled=true`, `--xpack.fleet.agentless.api.url=http://localhost:8089`, `--xpack.fleet.agentless.api.tls.certificate=${KBN_CERT_PATH}`, `--xpack.fleet.agentless.api.tls.key=${KBN_KEY_PATH}`, diff --git a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless_api.ts b/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless_api.ts deleted file mode 100644 index 0f37f224197e..000000000000 --- a/x-pack/test_serverless/functional/test_suites/security/config.cloud_security_posture.agentless_api.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; -import { CA_CERT_PATH, KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; -import { createTestConfig } from '../../config.base'; - -export default createTestConfig({ - serverlessProject: 'security', - junit: { - reportName: 'Serverless Security Cloud Security Agentless API Onboarding Functional Tests', - }, - kbnServerArgs: [ - `--xpack.fleet.packages.0.name=cloud_security_posture`, - `--xpack.fleet.packages.0.version=${CLOUD_CREDENTIALS_PACKAGE_VERSION}`, - - `--xpack.fleet.agents.fleet_server.hosts=["https://ftr.kibana:8220"]`, - `--xpack.fleet.internal.fleetServerStandalone=true`, - - // Agentless Configuration based on Serverless Security Dev Yaml - config/serverless.security.dev.yml - `--xpack.fleet.agentless.enabled=true`, - `--xpack.fleet.agentless.api.url=http://localhost:8089`, - `--xpack.fleet.agentless.api.tls.certificate=${KBN_CERT_PATH}`, - `--xpack.fleet.agentless.api.tls.key=${KBN_KEY_PATH}`, - `--xpack.fleet.agentless.api.tls.ca=${CA_CERT_PATH}`, - `--xpack.cloud.serverless.project_id=some_fake_project_id`, - ], - // load tests in the index file - testFiles: [require.resolve('./ftr/cloud_security_posture/agentless_api')], -}); diff --git a/x-pack/test_serverless/functional/test_suites/security/config.mki_only.ts b/x-pack/test_serverless/functional/test_suites/security/config.mki_only.ts new file mode 100644 index 000000000000..36d3bd6c7dd9 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/config.mki_only.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 { KBN_CERT_PATH, KBN_KEY_PATH } from '@kbn/dev-utils'; +import { createTestConfig } from '../../config.base'; + +export default createTestConfig({ + serverlessProject: 'security', + testFiles: [require.resolve('./index.mki_only.ts')], + junit: { + reportName: 'Serverless Security MKI Functional Tests', + }, + suiteTags: { exclude: ['skipSvlSec'] }, + + // include settings from project controller + // https://github.com/elastic/project-controller/blob/main/internal/project/security/config/elasticsearch.yml + esServerArgs: ['xpack.ml.nlp.enabled=true'], + kbnServerArgs: [ + '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', + // dataUsage.autoops* config is set in kibana controller + '--xpack.dataUsage.autoops.enabled=true', + '--xpack.dataUsage.autoops.api.url=http://localhost:9000', + `--xpack.dataUsage.autoops.api.tls.certificate=${KBN_CERT_PATH}`, + `--xpack.dataUsage.autoops.api.tls.key=${KBN_KEY_PATH}`, + ], +}); diff --git a/x-pack/test_serverless/functional/test_suites/security/config.ts b/x-pack/test_serverless/functional/test_suites/security/config.ts index 6bf456e5f6d5..0a6a3a061d1f 100644 --- a/x-pack/test_serverless/functional/test_suites/security/config.ts +++ b/x-pack/test_serverless/functional/test_suites/security/config.ts @@ -20,6 +20,7 @@ export default createTestConfig({ esServerArgs: ['xpack.ml.nlp.enabled=true'], kbnServerArgs: [ '--xpack.dataUsage.enabled=true', + '--xpack.dataUsage.enableExperimental=[]', // dataUsage.autoops* config is set in kibana controller '--xpack.dataUsage.autoops.enabled=true', '--xpack.dataUsage.autoops.api.url=http://localhost:9000', diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts index e669545d135f..ea499f96da58 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_aws.ts @@ -8,7 +8,7 @@ import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-p import expect from '@kbn/expect'; import * as http from 'http'; import type { FtrProviderContext } from '../../../../../ftr_provider_context'; -import { setupMockServer } from '../agentless_api/mock_agentless_api'; +import { setupMockServer } from './mock_agentless_api'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const mockAgentlessApiService = setupMockServer(); const pageObjects = getPageObjects([ diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts index 95f855697c5b..897a6e589fdb 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/cis_integration_gcp.ts @@ -9,7 +9,7 @@ import expect from '@kbn/expect'; import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import * as http from 'http'; import type { FtrProviderContext } from '../../../../../ftr_provider_context'; -import { setupMockServer } from '../agentless_api/mock_agentless_api'; +import { setupMockServer } from './mock_agentless_api'; export default function ({ getPageObjects, getService }: FtrProviderContext) { const pageObjects = getPageObjects(['common', 'svlCommonPage', 'cisAddIntegration', 'header']); diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/create_agent.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/create_agent.ts similarity index 80% rename from x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/create_agent.ts rename to x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/create_agent.ts index 7611061398f1..14351439ac68 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/create_agent.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/create_agent.ts @@ -25,12 +25,11 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const AWS_SINGLE_ACCOUNT_TEST_ID = 'awsSingleTestId'; describe('Agentless API Serverless', function () { + this.tags(['skipMKI', 'cloud_security_posture_agentless']); let mockApiServer: http.Server; let cisIntegration: typeof pageObjects.cisAddIntegration; before(async () => { - // If process.env.TEST_CLOUD is set, then the test is running in the Serverless Quality Gates - // and this MSW server will be listening for a request that will never come. mockApiServer = mockAgentlessApiService.listen(8089); // Start the usage api mock server on port 8089 await pageObjects.svlCommonPage.loginAsAdmin(); cisIntegration = pageObjects.cisAddIntegration; @@ -54,22 +53,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cisIntegration.selectSetupTechnology('agentless'); await cisIntegration.selectAwsCredentials('direct'); - if ( - process.env.TEST_CLOUD && - process.env.CSPM_AWS_ACCOUNT_ID && - process.env.CSPM_AWS_SECRET_KEY - ) { - await cisIntegration.fillInTextField( - cisIntegration.testSubjectIds.DIRECT_ACCESS_KEY_ID_TEST_ID, - process.env.CSPM_AWS_ACCOUNT_ID - ); - - await cisIntegration.fillInTextField( - cisIntegration.testSubjectIds.DIRECT_ACCESS_SECRET_KEY_TEST_ID, - process.env.CSPM_AWS_SECRET_KEY - ); - } - await pageObjects.header.waitUntilLoadingHasFinished(); await cisIntegration.clickSaveButton(); @@ -78,12 +61,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cisIntegration.navigateToIntegrationCspList(); await pageObjects.header.waitUntilLoadingHasFinished(); - expect(await cisIntegration.getFirstCspmIntegrationPageIntegration()).to.be( + expect(await cisIntegration.getFirstCspmIntegrationPageAgentlessIntegration()).to.be( integrationPolicyName ); - expect(await cisIntegration.getFirstCspmIntegrationPageAgent()).to.be( - `Agentless policy for ${integrationPolicyName}` - ); + + const resStatus = await cisIntegration.getFirstCspmIntegrationPageAgentlessStatus(); + // The status can only be Pending because the agentless agent will never be created + expect(resStatus).to.be('Pending'); }); it(`should create default agent-based agent`, async () => { diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/index.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/index.ts index 235757c508c1..875dd630f2ad 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/index.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/index.ts @@ -12,5 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { this.tags(['cloud_security_posture_agentless']); loadTestFile(require.resolve('./cis_integration_aws')); loadTestFile(require.resolve('./cis_integration_gcp')); + loadTestFile(require.resolve('./create_agent')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/mock_agentless_api.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/mock_agentless_api.ts similarity index 100% rename from x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/mock_agentless_api.ts rename to x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless/mock_agentless_api.ts diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/README.md b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/README.md new file mode 100644 index 000000000000..9af4048016c7 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/README.md @@ -0,0 +1,15 @@ +# MKI Serverless Quality Gates + +This folder contains tests that **ONLY** run in the MKI Serverless Quality Gates. These tests are designed to ensure the security and functionality of the system in a serverless environment. + +## Contributing + +Please prefix the tests in this folder with `mki_` so that is clear to the following developer that these tests run only in MKI and Serverless Quality Gates. + +New MKI only test files should be loaded from the root index.ts file of the mki_only directory + +``` +x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/index.ts +``` + +If you would like to contribute to these tests, please follow the contribution guidelines outlined in the main project repository. diff --git a/x-pack/test/cloud_security_posture_functional/cloud_tests/agentless_sanity.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/agentless/mki_create_agent.ts similarity index 72% rename from x-pack/test/cloud_security_posture_functional/cloud_tests/agentless_sanity.ts rename to x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/agentless/mki_create_agent.ts index d1a27bf5d8c1..4b357eb8c0f4 100644 --- a/x-pack/test/cloud_security_posture_functional/cloud_tests/agentless_sanity.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/agentless/mki_create_agent.ts @@ -7,11 +7,11 @@ import { CLOUD_CREDENTIALS_PACKAGE_VERSION } from '@kbn/cloud-security-posture-plugin/common/constants'; import expect from '@kbn/expect'; -import type { FtrProviderContext } from '../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export +import type { FtrProviderContext } from '../../../../../../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); const pageObjects = getPageObjects([ - 'common', + 'svlCommonPage', 'cspSecurity', 'security', 'header', @@ -22,17 +22,14 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { const AWS_SINGLE_ACCOUNT_TEST_ID = 'awsSingleTestId'; - describe('Agentless cloud', function () { + // This test suite is only running in the Serverless Quality Gates environment + describe('Agentless API Serverless MKI only', function () { + this.tags(['cloud_security_posture_agentless']); let cisIntegration: typeof pageObjects.cisAddIntegration; - let cisIntegrationAws: typeof pageObjects.cisAddIntegration.cisAws; before(async () => { + await pageObjects.svlCommonPage.loginAsAdmin(); cisIntegration = pageObjects.cisAddIntegration; - cisIntegrationAws = pageObjects.cisAddIntegration.cisAws; // Start the usage api mock server on port 8081 - }); - - after(async () => { - await pageObjects.cspSecurity.logout(); }); it(`should create agentless-agent`, async () => { @@ -51,20 +48,31 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await pageObjects.header.waitUntilLoadingHasFinished(); + if (process.env.CSPM_AWS_ACCOUNT_ID && process.env.CSPM_AWS_SECRET_KEY) { + await cisIntegration.fillInTextField( + cisIntegration.testSubjectIds.DIRECT_ACCESS_KEY_ID_TEST_ID, + process.env.CSPM_AWS_ACCOUNT_ID + ); + + await cisIntegration.fillInTextField( + cisIntegration.testSubjectIds.DIRECT_ACCESS_SECRET_KEY_TEST_ID, + process.env.CSPM_AWS_SECRET_KEY + ); + } + await cisIntegration.clickSaveButton(); await pageObjects.header.waitUntilLoadingHasFinished(); - expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(false); - await cisIntegration.navigateToIntegrationCspList(); await pageObjects.header.waitUntilLoadingHasFinished(); - expect(await cisIntegration.getFirstCspmIntegrationPageIntegration()).to.be( + expect(await cisIntegration.getFirstCspmIntegrationPageAgentlessIntegration()).to.be( integrationPolicyName ); - expect(await cisIntegration.getFirstCspmIntegrationPageAgent()).to.be( - `Agentless policy for ${integrationPolicyName}` - ); + + const agentStatusBadge = testSubjects.find('agentlessStatusBadge'); + // The status badge could be either "Pending", "Healthy", or "Unhealthy" so we are just checking that it exists + expect(agentStatusBadge).to.be.ok(); }); it(`should create default agent-based agent`, async () => { @@ -82,8 +90,6 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await cisIntegration.clickSaveButton(); await pageObjects.header.waitUntilLoadingHasFinished(); - expect(await cisIntegrationAws.showPostInstallCloudFormationModal()).to.be(true); - const agentPolicyName = await cisIntegration.getAgentBasedPolicyValue(); await cisIntegration.navigateToIntegrationCspList(); diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/index.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/index.ts similarity index 78% rename from x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/index.ts rename to x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/index.ts index 87008cadeff0..a1b5798f831b 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/agentless_api/index.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/cloud_security_posture/mki_only/index.ts @@ -10,6 +10,8 @@ import { FtrProviderContext } from '../../../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('cloud_security_posture', function () { this.tags(['cloud_security_posture']); - loadTestFile(require.resolve('./create_agent')); + + // do not resolve files which are ending with `.essentials.ts` + loadTestFile(require.resolve('./agentless/mki_create_agent')); }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/index.mki_only.ts b/x-pack/test_serverless/functional/test_suites/security/index.mki_only.ts new file mode 100644 index 000000000000..baff65fb737f --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/security/index.mki_only.ts @@ -0,0 +1,15 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('serverless security UI MKI only', function () { + this.tags(['security-mki-only ']); + loadTestFile(require.resolve('./ftr/cloud_security_posture/mki_only')); + }); +} diff --git a/x-pack/test_serverless/functional/test_suites/security/index.ts b/x-pack/test_serverless/functional/test_suites/security/index.ts index 833df2edb78c..30f35c52295c 100644 --- a/x-pack/test_serverless/functional/test_suites/security/index.ts +++ b/x-pack/test_serverless/functional/test_suites/security/index.ts @@ -8,8 +8,6 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { - const isCloud = !!process.env.TEST_CLOUD; - describe('serverless security UI', function () { this.tags(['esGate']); @@ -17,9 +15,5 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./ftr/cases')); loadTestFile(require.resolve('./ftr/advanced_settings')); loadTestFile(require.resolve('./ml')); - if (isCloud) { - // only run the agentless API tests in the Serverless Quality Gates - loadTestFile(require.resolve('./ftr/cloud_security_posture/agentless_api')); - } }); } diff --git a/x-pack/test_serverless/functional/test_suites/security/ml/anomaly_detection_jobs_list.ts b/x-pack/test_serverless/functional/test_suites/security/ml/anomaly_detection_jobs_list.ts index 9e1154ea09bb..e8f3f5e1796f 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ml/anomaly_detection_jobs_list.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ml/anomaly_detection_jobs_list.ts @@ -29,7 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { - await ml.api.cleanMlIndices(); + await ml.api.cleanAnomalyDetection(); await ml.testResources.cleanMLSavedObjects(); await esArchiver.unload('x-pack/test/functional/es_archives/logstash_functional'); await kibanaServer.savedObjects.cleanStandardList(); diff --git a/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts b/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts index d3caa3425f75..110cf64e07a1 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ml/data_frame_analytics_jobs_list.ts @@ -29,7 +29,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); after(async () => { - await ml.api.cleanMlIndices(); + await ml.api.cleanAnomalyDetection(); await ml.testResources.cleanMLSavedObjects(); }); diff --git a/x-pack/test_serverless/shared/types/index.ts b/x-pack/test_serverless/shared/types/index.ts index 2545bc0d3053..9690df7ac64c 100644 --- a/x-pack/test_serverless/shared/types/index.ts +++ b/x-pack/test_serverless/shared/types/index.ts @@ -8,13 +8,13 @@ import { ServerlessProjectType } from '@kbn/es'; import { InheritedServices } from '../../api_integration/services'; -export interface CreateTestConfigOptions { +export interface CreateTestConfigOptions { serverlessProject: ServerlessProjectType; esServerArgs?: string[]; kbnServerArgs?: string[]; testFiles: string[]; junit: { reportName: string }; suiteTags?: { include?: string[]; exclude?: string[] }; - services?: InheritedServices; + services?: TServices; apps?: Record; } diff --git a/yarn.lock b/yarn.lock index 94293a72dcae..c4f0f731adb4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35,6 +35,15 @@ "@jridgewell/gen-mapping" "^0.1.0" "@jridgewell/trace-mapping" "^0.3.9" +"@apidevtools/json-schema-ref-parser@9.0.6": + version "9.0.6" + resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.6.tgz#5d9000a3ac1fd25404da886da6b266adcd99cf1c" + integrity sha512-M3YgsLjI0lZxvrpeGVk9Ap032W6TPQkH6pRAZz81Ac3WUNF79VQooAFnp8umjvVzUmD93NkogxEwbSce7qMsUg== + dependencies: + "@jsdevtools/ono" "^7.1.3" + call-me-maybe "^1.0.1" + js-yaml "^3.13.1" + "@apidevtools/json-schema-ref-parser@^11.5.5": version "11.7.2" resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz#cdf3e0aded21492364a70e193b45b7cf4177f031" @@ -54,7 +63,7 @@ call-me-maybe "^1.0.1" js-yaml "^4.1.0" -"@apidevtools/openapi-schemas@^2.0.4": +"@apidevtools/openapi-schemas@^2.0.4", "@apidevtools/openapi-schemas@^2.1.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@apidevtools/openapi-schemas/-/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17" integrity sha512-Zc1AlqrJlX3SlpupFGpiLi2EbteyP7fXmUOGup6/DnkRgjP9bgMM/ag+n91rsv0U1Gpz0H3VILA/o3bW7Ua6BQ== @@ -64,7 +73,7 @@ resolved "https://registry.yarnpkg.com/@apidevtools/swagger-methods/-/swagger-methods-3.0.2.tgz#b789a362e055b0340d04712eafe7027ddc1ac267" integrity sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg== -"@apidevtools/swagger-parser@10.0.3", "@apidevtools/swagger-parser@^10.0.3": +"@apidevtools/swagger-parser@10.0.3": version "10.0.3" resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.0.3.tgz#32057ae99487872c4dd96b314a1ab4b95d89eaf5" integrity sha512-sNiLY51vZOmSPFZA5TF35KZ2HbgYklQnTSDnkghamzLb3EkNtcQnrBQEj5AOCxHpTtXpqMCRM1CrmV2rG6nw4g== @@ -76,6 +85,19 @@ call-me-maybe "^1.0.1" z-schema "^5.0.1" +"@apidevtools/swagger-parser@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@apidevtools/swagger-parser/-/swagger-parser-10.1.0.tgz#a987d71e5be61feb623203be0c96e5985b192ab6" + integrity sha512-9Kt7EuS/7WbMAUv2gSziqjvxwDbFSg3Xeyfuj5laUODX8o/k/CpsAKiQ8W7/R88eXFTMbJYg6+7uAmOWNKmwnw== + dependencies: + "@apidevtools/json-schema-ref-parser" "9.0.6" + "@apidevtools/openapi-schemas" "^2.1.0" + "@apidevtools/swagger-methods" "^3.0.2" + "@jsdevtools/ono" "^7.1.3" + ajv "^8.6.3" + ajv-draft-04 "^1.0.0" + call-me-maybe "^1.0.1" + "@appland/sql-parser@^1.5.1": version "1.5.1" resolved "https://registry.yarnpkg.com/@appland/sql-parser/-/sql-parser-1.5.1.tgz#331d644364899858ba7aa6e884e2492596990626" @@ -2068,7 +2090,7 @@ find-test-names "^1.19.0" globby "^11.0.4" -"@cypress/request@^3.0.0": +"@cypress/request@^3.0.6": version "3.0.6" resolved "https://registry.yarnpkg.com/@cypress/request/-/request-3.0.6.tgz#f5580add6acee0e183b4d4e07eff4f31327ae12b" integrity sha512-fi0eVdCOtKu5Ed6+E8mYxUF6ZTFJDZvHogCBelM0xVXmrDEkyM22gRArQzq1YcHPm1V47Vf/iAD+WgVdUlJCGg== @@ -2210,10 +2232,10 @@ dependencies: object-hash "^1.3.0" -"@elastic/charts@68.0.2": - version "68.0.2" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-68.0.2.tgz#8868a1d998137c41985a9b6da340391a31bae2f0" - integrity sha512-d0+qxiUovKwXeDDSrI4JQgTzk5YCbYnKxQAGV0jH37QLUzTo+t7yKqa7VTcCfEXzmtyD9Fwvihe/hCeHo+ii2w== +"@elastic/charts@68.0.3": + version "68.0.3" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-68.0.3.tgz#dc4aaeb4cdc8751d5759b58dc9958efb3c2639da" + integrity sha512-U+NCTo2LCDDSVkV5kGinhzbiAvfEcVAZ4D2YM/0RZQFRvJfJBvelbG+jDkt6N2mEauJ4ECDDcb33995fbs71TA== dependencies: "@popperjs/core" "^2.11.8" bezier-easing "^2.1.0" @@ -2308,25 +2330,25 @@ resolved "https://registry.yarnpkg.com/@elastic/eslint-plugin-eui/-/eslint-plugin-eui-0.0.2.tgz#56b9ef03984a05cc213772ae3713ea8ef47b0314" integrity sha512-IoxURM5zraoQ7C8f+mJb9HYSENiZGgRVcG4tLQxE61yHNNRDXtGDWTZh8N1KIHcsqN1CEPETjuzBXkJYF/fDiQ== -"@elastic/eui-theme-borealis@0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@elastic/eui-theme-borealis/-/eui-theme-borealis-0.0.2.tgz#4b65f13073b1887a12641063ace96539fa923674" - integrity sha512-ekePJ+V9UMCUDqjNLECjM+Vi/qHkJcu6lhm1GenUFs3awPxaLhvasb3pN++qnWYkXWo90vmZER62MTHpxlQyQA== +"@elastic/eui-theme-borealis@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@elastic/eui-theme-borealis/-/eui-theme-borealis-0.0.3.tgz#a84c59009a331acd711ed14729237a9f348a14b5" + integrity sha512-aO+41iq3igDC852ZUiCkbI44TAt44buxaw3bQS1/Cy50oYlG7TAGEm4f7WZbEnMRK6EeqCNs3Hj+rU5HMDi9vA== -"@elastic/eui-theme-common@0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@elastic/eui-theme-common/-/eui-theme-common-0.0.2.tgz#3da6078a5d255c5740423d26409e5e06536a5db3" - integrity sha512-tIyXrylrLhmOWiRbxuJSiHHVJpt4fVd5frzhUGoSN2frobOT9RLh8Klzyd4kmHasZ7bB1vETPR5fytqgocRvdA== +"@elastic/eui-theme-common@0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@elastic/eui-theme-common/-/eui-theme-common-0.0.3.tgz#55b916229bed02276d4cf8dc9dfb1f72fc47c482" + integrity sha512-I7x5/Z1xxhNvlWj4oUKbbExUBD3tbfIPMvcijeGy44uXOa10Bs0duAcuOdDsQZqQdB7V44KyT5rH2dTqU5ogQw== dependencies: "@types/lodash" "^4.14.202" lodash "^4.17.21" -"@elastic/eui@97.3.1-borealis.2": - version "97.3.1-borealis.2" - resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-97.3.1-borealis.2.tgz#32d9616ddbab11ef6e97739cf728a667220ca74c" - integrity sha512-j0WsE+WWtV3eEbRqyjr8hJ1swQIbCEGc9iViMtDK/XeVCVqs++dJE/+jPdjharMjXLrstOr0cx0uvtsH6OWTUw== +"@elastic/eui@98.0.0-borealis.1": + version "98.0.0-borealis.1" + resolved "https://registry.yarnpkg.com/@elastic/eui/-/eui-98.0.0-borealis.1.tgz#0f4e6a1a0afc3270ad1419f540e0d6d709899d63" + integrity sha512-npPTj62wkG2Hvqi/4bkWGi9R8LYsa6cjNBbwj60u9GQbovzR45ZGSjxWfRxrgR3ajqLqf22MnqCKab5hnu/7Mg== dependencies: - "@elastic/eui-theme-common" "0.0.2" + "@elastic/eui-theme-common" "0.0.3" "@hello-pangea/dnd" "^16.6.0" "@types/lodash" "^4.14.202" "@types/numeral" "^2.0.5" @@ -2407,10 +2429,10 @@ "@elastic/react-search-ui-views" "1.20.2" "@elastic/search-ui" "1.20.2" -"@elastic/request-converter@^8.16.1": - version "8.16.1" - resolved "https://registry.yarnpkg.com/@elastic/request-converter/-/request-converter-8.16.1.tgz#fad73db1a2ed0448501c389cf543fb77c6ffff57" - integrity sha512-lg2qCJ4kyxsP/0NpZo0+NsJfaY4JwyxGIVqD2l2Vmx9tv7ZNaZMn/TjHKBo2+jN0laJBInpxpnkPUgVWo5kw1g== +"@elastic/request-converter@^8.16.2": + version "8.16.2" + resolved "https://registry.yarnpkg.com/@elastic/request-converter/-/request-converter-8.16.2.tgz#e82c5c794adf8da37795cb8656e2f0334460cb08" + integrity sha512-bljPrXbXkImBglTz5N8Rrpmzc64ahpZxOkBIKFBX1mnU3kv/JDeMjsv1rvfHXrkuhtQQ4kRRZqfwmqzJIwzlag== dependencies: child-process-promise "^2.2.1" commander "^12.1.0" @@ -4018,6 +4040,10 @@ version "0.0.0" uid "" +"@kbn/asset-inventory-plugin@link:x-pack/plugins/asset_inventory": + version "0.0.0" + uid "" + "@kbn/audit-log-plugin@link:x-pack/test/security_api_integration/plugins/audit_log": version "0.0.0" uid "" @@ -5338,6 +5364,14 @@ version "0.0.0" uid "" +"@kbn/dependency-ownership@link:packages/kbn-dependency-ownership": + version "0.0.0" + uid "" + +"@kbn/dependency-usage@link:packages/kbn-dependency-usage": + version "0.0.0" + uid "" + "@kbn/dev-cli-errors@link:packages/kbn-dev-cli-errors": version "0.0.0" uid "" @@ -6886,10 +6920,18 @@ version "0.0.0" uid "" +"@kbn/saved-search-component@link:packages/kbn-saved-search-component": + version "0.0.0" + uid "" + "@kbn/saved-search-plugin@link:src/plugins/saved_search": version "0.0.0" uid "" +"@kbn/scout@link:packages/kbn-scout": + version "0.0.0" + uid "" + "@kbn/screenshot-mode-example-plugin@link:examples/screenshot_mode_example": version "0.0.0" uid "" @@ -7518,6 +7560,10 @@ version "0.0.0" uid "" +"@kbn/streams-app-plugin@link:x-pack/plugins/streams_app": + version "0.0.0" + uid "" + "@kbn/streams-plugin@link:x-pack/plugins/streams": version "0.0.0" uid "" @@ -8067,20 +8113,20 @@ resolved "https://registry.yarnpkg.com/@launchdarkly/js-sdk-common/-/js-sdk-common-2.12.0.tgz#c22eb9fead687260d916a75f693c7d399f085b05" integrity sha512-HIDxvgo1vksC9hsYy3517sgW0Ql+iW3fgwlq/CEigeBNmaa9/J1Pxo7LrKPzezEA0kaGedmt/DCzVVxVBmxSsQ== -"@launchdarkly/js-server-sdk-common@2.9.1": - version "2.9.1" - resolved "https://registry.yarnpkg.com/@launchdarkly/js-server-sdk-common/-/js-server-sdk-common-2.9.1.tgz#a683d682897c20a6967f5454d932663e4da6fc5c" - integrity sha512-BGIjcfel1hURvX4hM4iVruWecWMntRzh1UuPtV0uOYnXLuETp5lfpqBB6KzFoERnEZoCyX6Tmo+tPFVwteIUGA== +"@launchdarkly/js-server-sdk-common@2.10.0": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@launchdarkly/js-server-sdk-common/-/js-server-sdk-common-2.10.0.tgz#5bb0de97d86d66ffb0a92018bab7def289af1b46" + integrity sha512-zbqpmEFQW/ZElZnRYX6N4gMZMpviE0F75/IyxcifLAFsjGNouxllpOOPbdtrLiJnJ0ixzt5vbtnem4tbhlYNOw== dependencies: "@launchdarkly/js-sdk-common" "2.12.0" semver "7.5.4" -"@launchdarkly/node-server-sdk@^9.7.1": - version "9.7.1" - resolved "https://registry.yarnpkg.com/@launchdarkly/node-server-sdk/-/node-server-sdk-9.7.1.tgz#bb228e5f8c4c7ca52579f909e4150b9a749b04a9" - integrity sha512-razZ/ine5hfHiS7ZNfM1r/G7GNDQ+wHV0pRN2A0Yk5spZTmT/ecu67e+aXu/KAfEQyL0V4ofEkXJpeGl7TYJ5Q== +"@launchdarkly/node-server-sdk@^9.7.2": + version "9.7.2" + resolved "https://registry.yarnpkg.com/@launchdarkly/node-server-sdk/-/node-server-sdk-9.7.2.tgz#23929639f4b09da1f4c5bb77ca858d32c56505a4" + integrity sha512-gcRarEh0yQrlwbWDORwbfTk19M/FtZje60EIo/c4298D/sqJ906MYq0J2MmyklEuIdQx/V4qPK+ss9LCCLpm/Q== dependencies: - "@launchdarkly/js-server-sdk-common" "2.9.1" + "@launchdarkly/js-server-sdk-common" "2.10.0" https-proxy-agent "^5.0.1" launchdarkly-eventsource "2.0.3" @@ -9114,12 +9160,12 @@ require-from-string "^2.0.2" uri-js-replace "^1.0.1" -"@redocly/cli@^1.25.11": - version "1.25.11" - resolved "https://registry.yarnpkg.com/@redocly/cli/-/cli-1.25.11.tgz#8ec17a6535aebfd166e8cab8ffcc9d768af1b014" - integrity sha512-dttBsmLnnbTlJCTa+s7Sy+qtXDq692n7Ru3nUUIHp9XdCbhXIHWhpc8uAl+GmR4MGbVe8ohATl3J+zX3aFy82A== +"@redocly/cli@^1.25.14": + version "1.25.14" + resolved "https://registry.yarnpkg.com/@redocly/cli/-/cli-1.25.14.tgz#05810916bac2193137020ffbfa0bd766caca2258" + integrity sha512-HRDOoN3YpFe4+2rWrL/uTqRUDqqyrRtj1MVHFJ0heKTfBLOFEEfXXUYExw7R6yoiY3+GnptR96wePeFpH1gheg== dependencies: - "@redocly/openapi-core" "1.25.11" + "@redocly/openapi-core" "1.25.14" abort-controller "^3.0.0" chokidar "^3.5.1" colorette "^1.2.0" @@ -9144,10 +9190,10 @@ resolved "https://registry.yarnpkg.com/@redocly/config/-/config-0.16.0.tgz#4b7700a5cb6e04bc6d6fdb94b871c9e260a1fba6" integrity sha512-t9jnODbUcuANRSl/K4L9nb12V+U5acIHnVSl26NWrtSdDZVtoqUXk2yGFPZzohYf62cCfEQUT8ouJ3bhPfpnJg== -"@redocly/openapi-core@1.25.11", "@redocly/openapi-core@^1.4.0": - version "1.25.11" - resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.25.11.tgz#93f168284986da6809363b001e9aa7c2104c2fc0" - integrity sha512-bH+a8izQz4fnKROKoX3bEU8sQ9rjvEIZOqU6qTmxlhOJ0NsKa5e+LmU18SV0oFeg5YhWQhhEDihXkvKJ1wMMNQ== +"@redocly/openapi-core@1.25.14", "@redocly/openapi-core@^1.4.0": + version "1.25.14" + resolved "https://registry.yarnpkg.com/@redocly/openapi-core/-/openapi-core-1.25.14.tgz#2c0c33e0226923ed428e8d43f37f80d48b26c8d1" + integrity sha512-B9ewI0KVC1yqyeoQzErVnV4kdnxaYfwRMctxk/YwJxZZc/nVZ3VOVE+r2kXIFaGbUgc4ZHFn+aE2qvzCRXTXHw== dependencies: "@redocly/ajv" "^8.11.2" "@redocly/config" "^0.16.0" @@ -10846,10 +10892,10 @@ lz-string "^1.5.0" pretty-format "^27.0.2" -"@testing-library/jest-dom@^6.5.0": - version "6.5.0" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.5.0.tgz#50484da3f80fb222a853479f618a9ce5c47bfe54" - integrity sha512-xGGHpBXYSHUUr6XsKBfs85TWlYKpTc37cSBBVrXcib2MkHLboWlkClhWF37JKlDb9KEq3dHs+f2xR7XJEWGBxA== +"@testing-library/jest-dom@^6.6.3": + version "6.6.3" + resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz#26ba906cf928c0f8172e182c6fe214eb4f9f2bd2" + integrity sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA== dependencies: "@adobe/css-tools" "^4.4.0" aria-query "^5.0.0" @@ -11992,10 +12038,10 @@ dependencies: "@types/node" "*" -"@types/pngjs@^3.4.0": - version "3.4.2" - resolved "https://registry.yarnpkg.com/@types/pngjs/-/pngjs-3.4.2.tgz#8dc49b45fbcf18a5873179e3664f049388e39ecf" - integrity sha512-LJVPDraJ5YFEnMHnzxTN4psdWz1M61MtaAAWPn3qnDk5fvs7BAmmQ9pd3KPlrdrvozMyne4ktanD4pg0L7x1Pw== +"@types/pngjs@^6.0.5": + version "6.0.5" + resolved "https://registry.yarnpkg.com/@types/pngjs/-/pngjs-6.0.5.tgz#6dec2f7eb8284543ca4e423f3c09b119fa939ea3" + integrity sha512-0k5eKfrA83JOZPppLtS2C7OUtyNAl2wKNxfyYl9Q5g9lPkgBl/9hNyAu6HuEH2J4XmIv2znEpkDd0SaZVxW6iQ== dependencies: "@types/node" "*" @@ -13064,11 +13110,23 @@ acorn-import-attributes@^1.9.5: resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== +acorn-jsx-walk@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/acorn-jsx-walk/-/acorn-jsx-walk-2.0.0.tgz#a5ed648264e68282d7c2aead80216bfdf232573a" + integrity sha512-uuo6iJj4D4ygkdzd6jPtcxs8vZgDX9YFIkqczGImoypX2fQ4dVImmu3UzA4ynixCIMTrEOWW+95M2HuBaCEOVA== + acorn-jsx@^5.3.1, acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn-loose@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/acorn-loose/-/acorn-loose-8.4.0.tgz#26d3e219756d1e180d006f5bcc8d261a28530f55" + integrity sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ== + dependencies: + acorn "^8.11.0" + acorn-node@^1.6.1: version "1.8.2" resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" @@ -13083,7 +13141,7 @@ acorn-walk@^7.0.0, acorn-walk@^7.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -acorn-walk@^8.0.0, acorn-walk@^8.0.2, acorn-walk@^8.1.1, acorn-walk@^8.2.0: +acorn-walk@^8.0.0, acorn-walk@^8.0.2, acorn-walk@^8.1.1, acorn-walk@^8.2.0, acorn-walk@^8.3.4: version "8.3.4" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== @@ -13100,7 +13158,7 @@ acorn@^7.0.0, acorn@^7.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4, acorn@^8.1.0, acorn@^8.11.0, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0: +acorn@^8.0.4, acorn@^8.1.0, acorn@^8.11.0, acorn@^8.12.1, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0: version "8.13.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== @@ -13194,6 +13252,11 @@ airbnb-js-shims@^2.2.1: string.prototype.padstart "^3.0.0" symbol.prototype.description "^1.0.0" +ajv-draft-04@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" + integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw== + ajv-errors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.0.tgz#ecf021fa108fd17dfb5e6b383f2dd233e31ffc59" @@ -13228,7 +13291,7 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.0.1, ajv@^8.17.1, ajv@^8.8.0: +ajv@^8.0.0, ajv@^8.0.1, ajv@^8.17.1, ajv@^8.6.3, ajv@^8.8.0: version "8.17.1" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== @@ -13397,22 +13460,6 @@ arch@^2.2.0: resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== -archiver-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" - integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== - dependencies: - glob "^7.1.4" - graceful-fs "^4.2.0" - lazystream "^1.0.0" - lodash.defaults "^4.2.0" - lodash.difference "^4.5.0" - lodash.flatten "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.union "^4.6.0" - normalize-path "^3.0.0" - readable-stream "^2.0.0" - archiver-utils@^5.0.0, archiver-utils@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d" @@ -13426,19 +13473,6 @@ archiver-utils@^5.0.0, archiver-utils@^5.0.2: normalize-path "^3.0.0" readable-stream "^4.0.0" -archiver@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/archiver/-/archiver-5.3.1.tgz#21e92811d6f09ecfce649fbefefe8c79e57cbbb6" - integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== - dependencies: - archiver-utils "^2.1.0" - async "^3.2.3" - buffer-crc32 "^0.2.1" - readable-stream "^3.6.0" - readdir-glob "^1.0.0" - tar-stream "^2.2.0" - zip-stream "^4.1.0" - archiver@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61" @@ -14573,16 +14607,16 @@ buffer-builder@^0.2.0: resolved "https://registry.yarnpkg.com/buffer-builder/-/buffer-builder-0.2.0.tgz#3322cd307d8296dab1f604618593b261a3fade8f" integrity sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg== -buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - buffer-crc32@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w== +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -14612,7 +14646,7 @@ buffer@^4.3.0: ieee754 "^1.1.4" isarray "^1.0.0" -buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: +buffer@^5.2.1, buffer@^5.5.0, buffer@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== @@ -15081,10 +15115,10 @@ chrome-trace-event@^1.0.2: dependencies: tslib "^1.9.0" -chromedriver@^130.0.4: - version "130.0.4" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-130.0.4.tgz#55225ddfec428e306116507651f5a24fdb299bd6" - integrity sha512-lpR+PWXszij1k4Ig3t338Zvll9HtCTiwoLM7n4pCCswALHxzmgwaaIFBh3rt9+5wRk9D07oFblrazrBxwaYYAQ== +chromedriver@^131.0.1: + version "131.0.1" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-131.0.1.tgz#bfbf47f6c2ad7a65c154ff47d321bd8c33b52a77" + integrity sha512-LHRh+oaNU1WowJjAkWsviN8pTzQYJDbv/FvJyrQ7XhjKdIzVh/s3GV1iU7IjMTsxIQnBsTjx+9jWjzCWIXC7ug== dependencies: "@testim/chrome-version" "^1.1.4" axios "^1.7.4" @@ -15113,6 +15147,11 @@ ci-info@^3.2.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== +ci-info@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.0.0.tgz#65466f8b280fc019b9f50a5388115d17a63a44f2" + integrity sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -15562,16 +15601,6 @@ component-emitter@^1.2.1, component-emitter@^1.3.0: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -compress-commons@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-4.1.1.tgz#df2a09a7ed17447642bad10a85cc9a19e5c42a7d" - integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== - dependencies: - buffer-crc32 "^0.2.13" - crc32-stream "^4.0.2" - normalize-path "^3.0.0" - readable-stream "^3.6.0" - compress-commons@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" @@ -15858,14 +15887,6 @@ crc-32@^1.2.0: exit-on-epipe "~1.0.1" printj "~1.1.0" -crc32-stream@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-4.0.2.tgz#c922ad22b38395abe9d3870f02fa8134ed709007" - integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== - dependencies: - crc-32 "^1.2.0" - readable-stream "^3.4.0" - crc32-stream@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430" @@ -16245,22 +16266,23 @@ cypress-recurse@^1.35.2: dependencies: humanize-duration "^3.27.3" -cypress@13.6.3: - version "13.6.3" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.6.3.tgz#54f03ca07ee56b2bc18211e7bd32abd2533982ba" - integrity sha512-d/pZvgwjAyZsoyJ3FOsJT5lDsqnxQ/clMqnNc++rkHjbkkiF2h9s0JsZSyyH4QXhVFW3zPFg82jD25roFLOdZA== +cypress@13.15.2: + version "13.15.2" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-13.15.2.tgz#ef19554c274bc4ff23802aeb5c52951677fa67f1" + integrity sha512-ARbnUorjcCM3XiPwgHKuqsyr5W9Qn+pIIBPaoilnoBkLdSC2oLQjV1BUpnmc7KR+b7Avah3Ly2RMFnfxr96E/A== dependencies: - "@cypress/request" "^3.0.0" + "@cypress/request" "^3.0.6" "@cypress/xvfb" "^1.2.4" "@types/sinonjs__fake-timers" "8.1.1" "@types/sizzle" "^2.3.2" arch "^2.2.0" blob-util "^2.0.2" bluebird "^3.7.2" - buffer "^5.6.0" + buffer "^5.7.1" cachedir "^2.3.0" chalk "^4.1.0" check-more-types "^2.24.0" + ci-info "^4.0.0" cli-cursor "^3.1.0" cli-table3 "~0.6.1" commander "^6.2.1" @@ -16275,7 +16297,6 @@ cypress@13.6.3: figures "^3.2.0" fs-extra "^9.1.0" getos "^3.2.1" - is-ci "^3.0.0" is-installed-globally "~0.4.0" lazy-ass "^1.6.0" listr2 "^3.8.3" @@ -16289,7 +16310,8 @@ cypress@13.6.3: request-progress "^3.0.0" semver "^7.5.3" supports-color "^8.1.1" - tmp "~0.2.1" + tmp "~0.2.3" + tree-kill "1.2.2" untildify "^4.0.0" yauzl "^2.10.0" @@ -16982,6 +17004,34 @@ dependency-check@^4.1.0: read-package-json "^2.0.10" resolve "^1.1.7" +dependency-cruiser@^16.4.2: + version "16.4.2" + resolved "https://registry.yarnpkg.com/dependency-cruiser/-/dependency-cruiser-16.4.2.tgz#586487e1ac355912a0ad2310b830b63054733e01" + integrity sha512-mQZM95WwIvKzYYdj+1RgIBuJ6qbr1cfyzTt62dDJVrWAShfhV9IEkG/Xv4S2iD5sT+Gt3oFWyZjwNufAhcbtWA== + dependencies: + acorn "^8.12.1" + acorn-jsx "^5.3.2" + acorn-jsx-walk "^2.0.0" + acorn-loose "^8.4.0" + acorn-walk "^8.3.4" + ajv "^8.17.1" + commander "^12.1.0" + enhanced-resolve "^5.17.1" + ignore "^6.0.2" + interpret "^3.1.1" + is-installed-globally "^1.0.0" + json5 "^2.2.3" + memoize "^10.0.0" + picocolors "^1.1.0" + picomatch "^4.0.2" + prompts "^2.4.2" + rechoir "^0.8.0" + safe-regex "^2.1.1" + semver "^7.6.3" + teamcity-service-messages "^0.1.14" + tsconfig-paths-webpack-plugin "^4.1.0" + watskeburt "^4.1.0" + dependency-tree@^10.0.9: version "10.0.9" resolved "https://registry.yarnpkg.com/dependency-tree/-/dependency-tree-10.0.9.tgz#0c6c0dbeb0c5ec2cf83bf755f30e9cb12e7b4ac7" @@ -17680,7 +17730,7 @@ enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^5.14.1, enhanced-resolve@^5.16.0: +enhanced-resolve@^5.14.1, enhanced-resolve@^5.16.0, enhanced-resolve@^5.17.1, enhanced-resolve@^5.7.0: version "5.17.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== @@ -19218,7 +19268,7 @@ foreground-child@^2.0.0: cross-spawn "^7.0.0" signal-exit "^3.0.2" -foreground-child@^3.1.0: +foreground-child@^3.1.0, foreground-child@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== @@ -19306,13 +19356,13 @@ formdata-polyfill@^4.0.10: dependencies: fetch-blob "^3.1.2" -formidable@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/formidable/-/formidable-3.5.1.tgz#9360a23a656f261207868b1484624c4c8d06ee1a" - integrity sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og== +formidable@^3.5.1, formidable@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-3.5.2.tgz#207c33fecdecb22044c82ba59d0c63a12fb81d77" + integrity sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg== dependencies: dezalgo "^1.0.4" - hexoid "^1.0.0" + hexoid "^2.0.0" once "^1.4.0" formik@^2.4.6: @@ -19856,6 +19906,13 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, gl once "^1.3.0" path-is-absolute "^1.0.0" +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== + dependencies: + ini "4.1.1" + global-dirs@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" @@ -20448,10 +20505,10 @@ heap@^0.2.6: resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" integrity sha1-CH4fELBGky/IWU3Z5tN4r8nR5aw= -hexoid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" - integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== +hexoid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-2.0.0.tgz#fb36c740ebbf364403fa1ec0c7efd268460ec5b9" + integrity sha512-qlspKUK7IlSQv2o+5I7yhUd7TxlOG2Vr5LTa3ve2XSNVKAL/n/u/7KLvKmFNimomDIKvZFXWHv0T12mv7rT8Aw== highlight.js@^10.1.1, highlight.js@~10.4.0: version "10.4.1" @@ -20864,6 +20921,11 @@ ignore@^5.0.5, ignore@^5.1.1, ignore@^5.2.0, ignore@^5.3.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== +ignore@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-6.0.2.tgz#77cccb72a55796af1b6d2f9eb14fa326d24f4283" + integrity sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -20960,6 +21022,11 @@ ini@2.0.0: resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + ini@^1.3.5, ini@~1.3.0: version "1.3.7" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" @@ -21047,6 +21114,11 @@ interpret@^2.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw== +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + intl-messageformat@10.5.12: version "10.5.12" resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.5.12.tgz#a0c1a20da896b7a1f4ba1b59c8ba5d9943c29c3f" @@ -21087,11 +21159,6 @@ ip-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== -ip@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" - integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== - ip@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" @@ -21221,13 +21288,6 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-ci@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" - integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== - dependencies: - ci-info "^3.2.0" - is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" @@ -21376,6 +21436,14 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69" integrity sha1-bghLvJIGH7sJcexYts5tQE4k2mk= +is-installed-globally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-1.0.0.tgz#08952c43758c33d815692392f7f8437b9e436d5a" + integrity sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ== + dependencies: + global-directory "^4.0.1" + is-path-inside "^4.0.0" + is-installed-globally@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -21492,6 +21560,11 @@ is-path-inside@^3.0.2, is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-path-inside@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-4.0.0.tgz#805aeb62c47c1b12fc3fd13bfb3ed1e7430071db" + integrity sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA== + is-plain-obj@2.1.0, is-plain-obj@^2.0.0, is-plain-obj@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" @@ -21801,16 +21874,6 @@ istanbul-lib-hook@^3.0.0: dependencies: append-transform "^2.0.0" -istanbul-lib-instrument@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" @@ -21822,7 +21885,7 @@ istanbul-lib-instrument@^5.0.4: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" -istanbul-lib-instrument@^6.0.0: +istanbul-lib-instrument@^6.0.0, istanbul-lib-instrument@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== @@ -23230,26 +23293,11 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= - -lodash.difference@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c" - integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw= - lodash.escape@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg= -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - lodash.flattendeep@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" @@ -23350,11 +23398,6 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= -lodash.union@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88" - integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg= - lodash.uniq@4.5.0, lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -23900,6 +23943,13 @@ memoize-one@^6.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== +memoize@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/memoize/-/memoize-10.0.0.tgz#43fa66b2022363c7c50cf5dfab732a808a3d7147" + integrity sha512-H6cBLgsi6vMWOcCpvVCdFFnl3kerEXbrYh9q+lY6VXvQSmM6CkmV08VOwT+WE2tzIEqRPFfAq3fm4v/UIW6mSA== + dependencies: + mimic-function "^5.0.0" + memoizee@^0.4.15: version "0.4.17" resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.17.tgz#942a5f8acee281fa6fb9c620bddc57e3b7382949" @@ -25166,10 +25216,10 @@ nwsapi@^2.2.2: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.5.tgz#a52744c61b3889dd44b0a158687add39b8d935e2" integrity sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ== -nyc@^15.1.0: - version "15.1.0" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" - integrity sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A== +nyc@^17.1.0: + version "17.1.0" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-17.1.0.tgz#b6349a401a62ffeb912bd38ea9a018839fdb6eb1" + integrity sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ== dependencies: "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" @@ -25178,12 +25228,12 @@ nyc@^15.1.0: decamelize "^1.2.0" find-cache-dir "^3.2.0" find-up "^4.1.0" - foreground-child "^2.0.0" + foreground-child "^3.3.0" get-package-type "^0.1.0" glob "^7.1.6" istanbul-lib-coverage "^3.0.0" istanbul-lib-hook "^3.0.0" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^6.0.2" istanbul-lib-processinfo "^2.0.2" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" @@ -25388,10 +25438,10 @@ objectorarray@^1.0.4: resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.4.tgz#d69b2f0ff7dc2701903d308bb85882f4ddb49483" integrity sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w== -oboe@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6" - integrity sha1-IMiM2wwVNxuwQRklfU/dNLCqSfY= +oboe@^2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.7.tgz#14cb69c750757a964c760383e094887822a32947" + integrity sha512-Y2oCMU2xgITORaNvIDCvUyn2ZG/5NI19lLjMFThgYzCH+GA/fgYvVcwxAqnZPiMiUrPq64jLzCkBXqKSu/R6MA== dependencies: http-https "^1.0.0" @@ -25483,11 +25533,6 @@ openapi-sampler@^1.5.0: "@types/json-schema" "^7.0.7" json-pointer "0.6.2" -openapi-types@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-10.0.0.tgz#0debbf663b2feed0322030b5b7c9080804076934" - integrity sha512-Y8xOCT2eiKGYDzMW9R4x5cmfc3vGaaI4EL2pwhDmodWw1HlK18YcZ4uJxc7Rdp7/gGzAygzH9SXr6GKYIXbRcQ== - openapi-types@^12.1.3: version "12.1.3" resolved "https://registry.yarnpkg.com/openapi-types/-/openapi-types-12.1.3.tgz#471995eb26c4b97b7bd356aacf7b91b73e777dd3" @@ -25764,12 +25809,11 @@ pac-proxy-agent@^7.0.1: socks-proxy-agent "^8.0.2" pac-resolver@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.0.tgz#79376f1ca26baf245b96b34c339d79bff25e900c" - integrity sha512-Fd9lT9vJbHYRACT8OhCbZBbxr6KRSawSovFpy8nDGshaK99S/EBhVIHp9+crhxrsZOuvLpgL1n23iyPg6Rl2hg== + version "7.0.1" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-7.0.1.tgz#54675558ea368b64d210fd9c92a640b5f3b8abb6" + integrity sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg== dependencies: degenerator "^5.0.0" - ip "^1.1.8" netmask "^2.0.2" package-hash@^4.0.0: @@ -26091,6 +26135,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0, picomatc resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + pidusage@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/pidusage/-/pidusage-3.0.2.tgz#6faa5402b2530b3af2cf93d13bcf202889724a53" @@ -26297,16 +26346,11 @@ png-js@^1.0.0: resolved "https://registry.yarnpkg.com/png-js/-/png-js-1.0.0.tgz#e5484f1e8156996e383aceebb3789fd75df1874d" integrity sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g== -pngjs@7.0.0: +pngjs@7.0.0, pngjs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-7.0.0.tgz#a8b7446020ebbc6ac739db6c5415a65d17090e26" integrity sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow== -pngjs@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - pngjs@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" @@ -26905,7 +26949,7 @@ promise.prototype.finally@^3.1.0: es-abstract "^1.9.0" function-bind "^1.1.1" -prompts@^2.0.1, prompts@^2.4.0, prompts@~2.4.2: +prompts@^2.0.1, prompts@^2.4.0, prompts@^2.4.2, prompts@~2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== @@ -27301,10 +27345,10 @@ re-resizable@^6.9.9: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== -re2js@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/re2js/-/re2js-0.4.2.tgz#e344697e64d128ea65c121d6581e67ee5bfa5feb" - integrity sha512-wuv0p0BGbrVIkobV8zh82WjDurXko0QNCgaif6DdRAljgVm2iio4PVYCwjAxGaWen1/QZXWDM67dIslmz7AIbA== +re2js@0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/re2js/-/re2js-0.4.3.tgz#1318cd0c12aa6ed3ba56d5e012311ffbfb2aef35" + integrity sha512-EuNmh7jurhHEE8Ge/lBo9JuMLb3qf866Xjjfyovw3wPc7+hlqDkZq4LwhrCQMEI+ARWfrKrHozEndzlpNT0WDg== react-clientside-effect@^1.2.6: version "1.2.6" @@ -27973,7 +28017,7 @@ readable-stream@~2.0.0: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readdir-glob@^1.0.0, readdir-glob@^1.1.2: +readdir-glob@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== @@ -28027,6 +28071,13 @@ rechoir@^0.7.0: dependencies: resolve "^1.9.0" +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -28202,6 +28253,11 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexp-tree@~0.1.1: + version "0.1.27" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" + integrity sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA== + regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.4.3, regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" @@ -28851,6 +28907,13 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" +safe-regex@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-2.1.1.tgz#f7128f00d056e2fe5c11e81a1324dd974aadced2" + integrity sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A== + dependencies: + regexp-tree "~0.1.1" + safe-squel@^5.12.5: version "5.12.5" resolved "https://registry.yarnpkg.com/safe-squel/-/safe-squel-5.12.5.tgz#9597cec498dc184a15fe94082b7bcc80cb4d048b" @@ -29126,10 +29189,10 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo= -selenium-webdriver@^4.26.0: - version "4.26.0" - resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.26.0.tgz#23163cdad20388214a4ad17c1f38262a0857c902" - integrity sha512-nA7jMRIPV17mJmAiTDBWN96Sy0Uxrz5CCLb7bLVV6PpL417SyBMPc2Zo/uoREc2EOHlzHwHwAlFtgmSngSY4WQ== +selenium-webdriver@^4.27.0: + version "4.27.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.27.0.tgz#f0f26ce453805e7dc77151040442c67e441dbe7a" + integrity sha512-LkTJrNz5socxpPnWPODQ2bQ65eYx9JK+DQMYNihpTjMCqHwgWGYQnQTCAAche2W3ZP87alA+1zYPvgS8tHNzMQ== dependencies: "@bazel/runfiles" "^6.3.1" jszip "^3.10.1" @@ -30567,7 +30630,22 @@ stylus-lookup@^5.0.1: dependencies: commander "^10.0.1" -superagent@^9.0.1, superagent@^9.0.2: +superagent@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-10.1.1.tgz#2f112591a5701a1d4467048580bcfda104e5a94d" + integrity sha512-9pIwrHrOj3uAnqg9gDlW7EA2xv+N5au/dSM0kM22HTqmUu8jBxNT+8uA7tA3UoCnmiqzpSbu8rasIUZvbyamMQ== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.4" + debug "^4.3.4" + fast-safe-stringify "^2.1.1" + form-data "^4.0.0" + formidable "^3.5.2" + methods "^1.1.2" + mime "2.6.0" + qs "^6.11.0" + +superagent@^9.0.1: version "9.0.2" resolved "https://registry.yarnpkg.com/superagent/-/superagent-9.0.2.tgz#a18799473fc57557289d6b63960610e358bdebc1" integrity sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w== @@ -30850,7 +30928,7 @@ tar-fs@^3.0.4, tar-fs@^3.0.6: bare-fs "^2.1.1" bare-path "^2.1.0" -tar-stream@^2.1.4, tar-stream@^2.2.0: +tar-stream@^2.1.4: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -30914,6 +30992,11 @@ tcp-port-used@^1.0.2: debug "4.3.1" is2 "^2.0.6" +teamcity-service-messages@^0.1.14: + version "0.1.14" + resolved "https://registry.yarnpkg.com/teamcity-service-messages/-/teamcity-service-messages-0.1.14.tgz#193d420a5e4aef8e5e50b8c39e7865e08fbb5d8a" + integrity sha512-29aQwaHqm8RMX74u2o/h1KbMLP89FjNiMxD9wbF2BbWOnbM+q+d1sCEC+MqCc4QW3NJykn77OMpTFw/xTHIc0w== + teex@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/teex/-/teex-1.0.1.tgz#b8fa7245ef8e8effa8078281946c85ab780a0b12" @@ -31174,7 +31257,7 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmp@^0.2.3, tmp@~0.2.1: +tmp@^0.2.3, tmp@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== @@ -31329,7 +31412,7 @@ traverse@^0.6.6, traverse@~0.6.6: resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= -tree-kill@^1.2.2: +tree-kill@1.2.2, tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== @@ -31421,6 +31504,15 @@ ts-pnp@^1.1.6: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== +tsconfig-paths-webpack-plugin@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz#3c6892c5e7319c146eee1e7302ed9e6f2be4f763" + integrity sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.7.0" + tsconfig-paths "^4.1.2" + tsconfig-paths@^3.14.2: version "3.14.2" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" @@ -31431,7 +31523,7 @@ tsconfig-paths@^3.14.2: minimist "^1.2.6" strip-bom "^3.0.0" -tsconfig-paths@^4.2.0: +tsconfig-paths@^4.1.2, tsconfig-paths@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== @@ -32788,6 +32880,11 @@ watchpack@^2.2.0, watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" +watskeburt@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/watskeburt/-/watskeburt-4.1.0.tgz#3c0227669be646a97424b631164b1afe3d4d5344" + integrity sha512-KkY5H51ajqy9HYYI+u9SIURcWnqeVVhdH0I+ab6aXPGHfZYxgRCwnR6Lm3+TYB6jJVt5jFqw4GAKmwf1zHmGQw== + wbuf@^1.1.0, wbuf@^1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" @@ -33393,10 +33490,10 @@ xml@^1.0.0: resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= -xmlbuilder@13.0.2: - version "13.0.2" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-13.0.2.tgz#02ae33614b6a047d1c32b5389c1fdacb2bce47a7" - integrity sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ== +xmlbuilder@15.1.1: + version "15.1.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== xmlbuilder@~11.0.0: version "11.0.1" @@ -33663,15 +33760,6 @@ z-schema@^5.0.1: optionalDependencies: commander "^2.20.3" -zip-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-4.1.0.tgz#51dd326571544e36aa3f756430b313576dc8fc79" - integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== - dependencies: - archiver-utils "^2.1.0" - compress-commons "^4.1.0" - readable-stream "^3.6.0" - zip-stream@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb"